From 620d662ea5758451377771ef60c4c723c46f2126 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Fri, 8 Mar 2024 00:24:19 -0500 Subject: [PATCH] Add Chrome/VSCode benchmark --- README.md | 180 +++++++---- benchmark/chrome.mjs | 707 +++++++++++++++++++++++++++++++++++++++++++ benchmark/index.mjs | 20 +- benchmark/vscode.map | 1 + 4 files changed, 840 insertions(+), 68 deletions(-) create mode 100644 benchmark/chrome.mjs create mode 100644 benchmark/vscode.map diff --git a/README.md b/README.md index 969558d..a8faae0 100644 --- a/README.md +++ b/README.md @@ -131,34 +131,37 @@ assert.deepEqual(traced, { ## Benchmarks ``` -node v18.0.0 +node v20.10.0 amp.js.map - 45120 segments Memory Usage: -trace-mapping decoded 562400 bytes -trace-mapping encoded 5706544 bytes -source-map-js 10717664 bytes -source-map-0.6.1 17446384 bytes -source-map-0.8.0 9701757 bytes +trace-mapping decoded 414788 bytes +trace-mapping encoded 6280096 bytes +source-map-js 10788968 bytes +source-map-0.6.1 17665560 bytes +source-map-0.8.0 8754851 bytes +Chrome dev tools 8765264 bytes Smallest memory usage is trace-mapping decoded Init speed: -trace-mapping: decoded JSON input x 180 ops/sec ±0.34% (85 runs sampled) -trace-mapping: encoded JSON input x 364 ops/sec ±1.77% (89 runs sampled) -trace-mapping: decoded Object input x 3,116 ops/sec ±0.50% (96 runs sampled) -trace-mapping: encoded Object input x 410 ops/sec ±2.62% (85 runs sampled) -source-map-js: encoded Object input x 84.23 ops/sec ±0.91% (73 runs sampled) -source-map-0.6.1: encoded Object input x 37.21 ops/sec ±2.08% (51 runs sampled) +trace-mapping: decoded JSON input x 206 ops/sec ±0.36% (88 runs sampled) +trace-mapping: encoded JSON input x 404 ops/sec ±1.65% (84 runs sampled) +trace-mapping: decoded Object input x 4,647 ops/sec ±0.12% (97 runs sampled) +trace-mapping: encoded Object input x 453 ops/sec ±1.73% (76 runs sampled) +source-map-js: encoded Object input x 77.10 ops/sec ±1.45% (68 runs sampled) +source-map-0.6.1: encoded Object input x 39.01 ops/sec ±1.97% (53 runs sampled) +Chrome dev tools: encoded Object input x 150 ops/sec ±1.60% (79 runs sampled) Fastest is trace-mapping: decoded Object input Trace speed: -trace-mapping: decoded originalPositionFor x 3,952,212 ops/sec ±0.17% (98 runs sampled) -trace-mapping: encoded originalPositionFor x 3,487,468 ops/sec ±1.58% (90 runs sampled) -source-map-js: encoded originalPositionFor x 827,730 ops/sec ±0.78% (97 runs sampled) -source-map-0.6.1: encoded originalPositionFor x 748,991 ops/sec ±0.53% (94 runs sampled) -source-map-0.8.0: encoded originalPositionFor x 2,532,894 ops/sec ±0.57% (95 runs sampled) -Fastest is trace-mapping: decoded originalPositionFor +trace-mapping: decoded originalPositionFor x 3,998,025 ops/sec ±0.37% (100 runs sampled) +trace-mapping: encoded originalPositionFor x 3,289,465 ops/sec ±1.79% (92 runs sampled) +source-map-js: encoded originalPositionFor x 917,842 ops/sec ±1.07% (91 runs sampled) +source-map-0.6.1: encoded originalPositionFor x 785,105 ops/sec ±1.17% (97 runs sampled) +source-map-0.8.0: encoded originalPositionFor x 2,745,332 ops/sec ±0.91% (97 runs sampled) +Chrome dev tools: encoded originalPositionFor x 4,287,614 ops/sec ±1.20% (91 runs sampled) +Fastest is Chrome dev tools: encoded originalPositionFor *** @@ -167,28 +170,31 @@ Fastest is trace-mapping: decoded originalPositionFor babel.min.js.map - 347793 segments Memory Usage: -trace-mapping decoded 89832 bytes -trace-mapping encoded 35474640 bytes -source-map-js 51257176 bytes -source-map-0.6.1 63515664 bytes -source-map-0.8.0 42933752 bytes +trace-mapping decoded 26704 bytes +trace-mapping encoded 35430936 bytes +source-map-js 51644904 bytes +source-map-0.6.1 63528632 bytes +source-map-0.8.0 43147288 bytes +Chrome dev tools 50911744 bytes Smallest memory usage is trace-mapping decoded Init speed: -trace-mapping: decoded JSON input x 15.41 ops/sec ±8.65% (34 runs sampled) -trace-mapping: encoded JSON input x 28.20 ops/sec ±12.87% (42 runs sampled) -trace-mapping: decoded Object input x 964 ops/sec ±0.36% (99 runs sampled) -trace-mapping: encoded Object input x 31.77 ops/sec ±13.79% (45 runs sampled) -source-map-js: encoded Object input x 6.45 ops/sec ±5.16% (21 runs sampled) -source-map-0.6.1: encoded Object input x 4.07 ops/sec ±5.24% (15 runs sampled) +trace-mapping: decoded JSON input x 17.86 ops/sec ±6.05% (34 runs sampled) +trace-mapping: encoded JSON input x 30.95 ops/sec ±8.70% (43 runs sampled) +trace-mapping: decoded Object input x 791 ops/sec ±1.02% (93 runs sampled) +trace-mapping: encoded Object input x 33.02 ops/sec ±8.84% (45 runs sampled) +source-map-js: encoded Object input x 6.54 ops/sec ±4.17% (21 runs sampled) +source-map-0.6.1: encoded Object input x 4.26 ops/sec ±4.84% (15 runs sampled) +Chrome dev tools: encoded Object input x 22.13 ops/sec ±3.07% (41 runs sampled) Fastest is trace-mapping: decoded Object input Trace speed: -trace-mapping: decoded originalPositionFor x 7,183,038 ops/sec ±0.58% (95 runs sampled) -trace-mapping: encoded originalPositionFor x 5,192,185 ops/sec ±0.41% (100 runs sampled) -source-map-js: encoded originalPositionFor x 4,259,489 ops/sec ±0.79% (94 runs sampled) -source-map-0.6.1: encoded originalPositionFor x 3,742,629 ops/sec ±0.71% (95 runs sampled) -source-map-0.8.0: encoded originalPositionFor x 6,270,211 ops/sec ±0.64% (94 runs sampled) +trace-mapping: decoded originalPositionFor x 8,287,155 ops/sec ±1.61% (89 runs sampled) +trace-mapping: encoded originalPositionFor x 5,707,321 ops/sec ±1.64% (93 runs sampled) +source-map-js: encoded originalPositionFor x 4,617,011 ops/sec ±0.89% (96 runs sampled) +source-map-0.6.1: encoded originalPositionFor x 4,003,422 ops/sec ±1.03% (93 runs sampled) +source-map-0.8.0: encoded originalPositionFor x 6,823,856 ops/sec ±1.07% (93 runs sampled) +Chrome dev tools: encoded originalPositionFor x 7,558,852 ops/sec ±0.96% (94 runs sampled) Fastest is trace-mapping: decoded originalPositionFor @@ -198,29 +204,32 @@ Fastest is trace-mapping: decoded originalPositionFor preact.js.map - 1992 segments Memory Usage: -trace-mapping decoded 37128 bytes -trace-mapping encoded 247280 bytes -source-map-js 1143536 bytes -source-map-0.6.1 1290992 bytes -source-map-0.8.0 96544 bytes +trace-mapping decoded 41920 bytes +trace-mapping encoded 254336 bytes +source-map-js 954752 bytes +source-map-0.6.1 1160040 bytes +source-map-0.8.0 65096 bytes +Chrome dev tools 398792 bytes Smallest memory usage is trace-mapping decoded Init speed: -trace-mapping: decoded JSON input x 3,483 ops/sec ±0.30% (98 runs sampled) -trace-mapping: encoded JSON input x 6,092 ops/sec ±0.18% (97 runs sampled) -trace-mapping: decoded Object input x 249,076 ops/sec ±0.24% (98 runs sampled) -trace-mapping: encoded Object input x 14,555 ops/sec ±0.48% (100 runs sampled) -source-map-js: encoded Object input x 2,447 ops/sec ±0.36% (99 runs sampled) -source-map-0.6.1: encoded Object input x 1,201 ops/sec ±0.57% (96 runs sampled) +trace-mapping: decoded JSON input x 3,726 ops/sec ±0.13% (99 runs sampled) +trace-mapping: encoded JSON input x 6,452 ops/sec ±0.25% (100 runs sampled) +trace-mapping: decoded Object input x 83,383 ops/sec ±0.19% (99 runs sampled) +trace-mapping: encoded Object input x 14,961 ops/sec ±0.25% (97 runs sampled) +source-map-js: encoded Object input x 2,539 ops/sec ±0.24% (98 runs sampled) +source-map-0.6.1: encoded Object input x 1,237 ops/sec ±0.50% (97 runs sampled) +Chrome dev tools: encoded Object input x 4,128 ops/sec ±0.47% (90 runs sampled) Fastest is trace-mapping: decoded Object input Trace speed: -trace-mapping: decoded originalPositionFor x 7,620,192 ops/sec ±0.09% (99 runs sampled) -trace-mapping: encoded originalPositionFor x 6,872,554 ops/sec ±0.30% (97 runs sampled) -source-map-js: encoded originalPositionFor x 2,489,570 ops/sec ±0.35% (94 runs sampled) -source-map-0.6.1: encoded originalPositionFor x 1,698,633 ops/sec ±0.28% (98 runs sampled) -source-map-0.8.0: encoded originalPositionFor x 4,015,644 ops/sec ±0.22% (98 runs sampled) -Fastest is trace-mapping: decoded originalPositionFor +trace-mapping: decoded originalPositionFor x 7,860,922 ops/sec ±0.13% (99 runs sampled) +trace-mapping: encoded originalPositionFor x 7,194,603 ops/sec ±0.22% (98 runs sampled) +source-map-js: encoded originalPositionFor x 2,653,667 ops/sec ±0.27% (97 runs sampled) +source-map-0.6.1: encoded originalPositionFor x 1,794,160 ops/sec ±0.33% (100 runs sampled) +source-map-0.8.0: encoded originalPositionFor x 4,079,232 ops/sec ±0.35% (98 runs sampled) +Chrome dev tools: encoded originalPositionFor x 8,502,450 ops/sec ±0.35% (98 runs sampled) +Fastest is Chrome dev tools: encoded originalPositionFor *** @@ -229,28 +238,65 @@ Fastest is trace-mapping: decoded originalPositionFor react.js.map - 5726 segments Memory Usage: -trace-mapping decoded 16176 bytes -trace-mapping encoded 681552 bytes -source-map-js 2418352 bytes -source-map-0.6.1 2443672 bytes -source-map-0.8.0 111768 bytes +trace-mapping decoded 13464 bytes +trace-mapping encoded 682000 bytes +source-map-js 2540984 bytes +source-map-0.6.1 2230384 bytes +source-map-0.8.0 230432 bytes +Chrome dev tools 1118400 bytes +Smallest memory usage is trace-mapping decoded + +Init speed: +trace-mapping: decoded JSON input x 1,902 ops/sec ±0.13% (100 runs sampled) +trace-mapping: encoded JSON input x 4,763 ops/sec ±0.34% (100 runs sampled) +trace-mapping: decoded Object input x 75,303 ops/sec ±0.22% (100 runs sampled) +trace-mapping: encoded Object input x 5,791 ops/sec ±0.23% (100 runs sampled) +source-map-js: encoded Object input x 811 ops/sec ±0.19% (96 runs sampled) +source-map-0.6.1: encoded Object input x 420 ops/sec ±0.56% (93 runs sampled) +Chrome dev tools: encoded Object input x 1,503 ops/sec ±0.46% (94 runs sampled) +Fastest is trace-mapping: decoded Object input + +Trace speed: +trace-mapping: decoded originalPositionFor x 34,044,182 ops/sec ±0.23% (95 runs sampled) +trace-mapping: encoded originalPositionFor x 34,822,726 ops/sec ±0.47% (97 runs sampled) +source-map-js: encoded originalPositionFor x 16,094,195 ops/sec ±3.07% (87 runs sampled) +source-map-0.6.1: encoded originalPositionFor x 12,818,718 ops/sec ±1.90% (92 runs sampled) +source-map-0.8.0: encoded originalPositionFor x 24,418,865 ops/sec ±0.36% (98 runs sampled) +Chrome dev tools: encoded originalPositionFor x 39,636,843 ops/sec ±0.37% (96 runs sampled) +Fastest is Chrome dev tools: encoded originalPositionFor + + +*** + + +vscode.map - 2141001 segments + +Memory Usage: +trace-mapping decoded 4983728 bytes +trace-mapping encoded 200000064 bytes +source-map-js 278356960 bytes +source-map-0.6.1 397326704 bytes +source-map-0.8.0 243384784 bytes +Chrome dev tools 255377536 bytes Smallest memory usage is trace-mapping decoded Init speed: -trace-mapping: decoded JSON input x 1,720 ops/sec ±0.34% (98 runs sampled) -trace-mapping: encoded JSON input x 4,406 ops/sec ±0.35% (100 runs sampled) -trace-mapping: decoded Object input x 92,122 ops/sec ±0.10% (99 runs sampled) -trace-mapping: encoded Object input x 5,385 ops/sec ±0.37% (99 runs sampled) -source-map-js: encoded Object input x 794 ops/sec ±0.40% (98 runs sampled) -source-map-0.6.1: encoded Object input x 416 ops/sec ±0.54% (91 runs sampled) +trace-mapping: decoded JSON input x 1.81 ops/sec ±20.81% (9 runs sampled) +trace-mapping: encoded JSON input x 2.14 ops/sec ±36.01% (10 runs sampled) +trace-mapping: decoded Object input x 103 ops/sec ±0.54% (77 runs sampled) +trace-mapping: encoded Object input x 3.35 ops/sec ±25.98% (12 runs sampled) +source-map-js: encoded Object input x 1.08 ops/sec ±12.75% (7 runs sampled) +source-map-0.6.1: encoded Object input x 0.54 ops/sec ±13.02% (6 runs sampled) +Chrome dev tools: encoded Object input x 2.75 ops/sec ±17.79% (12 runs sampled) Fastest is trace-mapping: decoded Object input Trace speed: -trace-mapping: decoded originalPositionFor x 32,759,519 ops/sec ±0.33% (100 runs sampled) -trace-mapping: encoded originalPositionFor x 31,116,306 ops/sec ±0.33% (97 runs sampled) -source-map-js: encoded originalPositionFor x 17,458,435 ops/sec ±0.44% (97 runs sampled) -source-map-0.6.1: encoded originalPositionFor x 12,687,097 ops/sec ±0.43% (95 runs sampled) -source-map-0.8.0: encoded originalPositionFor x 23,538,275 ops/sec ±0.38% (95 runs sampled) +trace-mapping: decoded originalPositionFor x 7,276,996 ops/sec ±1.38% (90 runs sampled) +trace-mapping: encoded originalPositionFor x 4,717,088 ops/sec ±1.53% (89 runs sampled) +source-map-js: encoded originalPositionFor x 1,547,423 ops/sec ±0.91% (97 runs sampled) +source-map-0.6.1: encoded originalPositionFor x 1,453,214 ops/sec ±1.39% (93 runs sampled) +source-map-0.8.0: encoded originalPositionFor x 4,077,080 ops/sec ±0.90% (89 runs sampled) +Chrome dev tools: encoded originalPositionFor x 5,096,269 ops/sec ±0.98% (92 runs sampled) Fastest is trace-mapping: decoded originalPositionFor ``` diff --git a/benchmark/chrome.mjs b/benchmark/chrome.mjs new file mode 100644 index 0000000..b4075cd --- /dev/null +++ b/benchmark/chrome.mjs @@ -0,0 +1,707 @@ +// This is an approximation of Chrome's source map decoding. +// https://source.chromium.org/chromium/chromium/src/+/main:v8/tools/sourcemap.mjs;drc=7a90c32032759a1596fb9a0549cced1b89f42c5f + +export function SourceMap(sourceMappingURL, payload) { + if (!SourceMap.prototype._base64Map) { + const base64Digits = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + SourceMap.prototype._base64Map = {}; + for (let i = 0; i < base64Digits.length; ++i) + SourceMap.prototype._base64Map[base64Digits.charAt(i)] = i; + } + + this._sourceMappingURL = sourceMappingURL; + this._reverseMappingsBySourceURL = {}; + this._mappings = []; + this._sources = {}; + this._sourceContentByURL = {}; + this._parseMappingPayload(payload); +} + +SourceMap.prototype = { + /** + * @return {string[]} + */ + sources() { + return Object.keys(this._sources); + }, + + /** + * @param {string} sourceURL + * @return {string|undefined} + */ + sourceContent(sourceURL) { + return this._sourceContentByURL[sourceURL]; + }, + + /** + * @param {SourceMapV3} mappingPayload + */ + _parseMappingPayload(mappingPayload) { + if (mappingPayload.sections) this._parseSections(mappingPayload.sections); + else this._parseMap(mappingPayload, 0, 0); + }, + + /** + * @param {Array.} sections + */ + _parseSections(sections) { + for (let i = 0; i < sections.length; ++i) { + const section = sections[i]; + this._parseMap(section.map, section.offset.line, section.offset.column); + } + }, + + /** + * @param {number} lineNumber in compiled resource + * @param {number} columnNumber in compiled resource + * @return {?Array} + */ + findEntry(lineNumber, columnNumber) { + let first = 0; + let count = this._mappings.length; + while (count > 1) { + const step = count >> 1; + const middle = first + step; + const mapping = this._mappings[middle]; + if (lineNumber < mapping[0] || (lineNumber === mapping[0] && columnNumber < mapping[1])) + count = step; + else { + first = middle; + count -= step; + } + } + const entry = this._mappings[first]; + if ( + !first && + entry && + (lineNumber < entry[0] || (lineNumber === entry[0] && columnNumber < entry[1])) + ) + return null; + return entry; + }, + + /** + * @param {string} sourceURL of the originating resource + * @param {number} lineNumber in the originating resource + * @return {Array} + */ + findEntryReversed(sourceURL, lineNumber) { + const mappings = this._reverseMappingsBySourceURL[sourceURL]; + for (; lineNumber < mappings.length; ++lineNumber) { + const mapping = mappings[lineNumber]; + if (mapping) return mapping; + } + return this._mappings[0]; + }, + + /** + * @override + */ + _parseMap(map, lineNumber, columnNumber) { + let sourceIndex = 0; + let sourceLineNumber = 0; + let sourceColumnNumber = 0; + let nameIndex = 0; + + const sources = []; + const originalToCanonicalURLMap = {}; + for (let i = 0; i < map.sources.length; ++i) { + const originalSourceURL = map.sources[i]; + let sourceRoot = map.sourceRoot || ''; + if (sourceRoot && !sourceRoot.endsWith('/')) sourceRoot += '/'; + const href = sourceRoot + originalSourceURL; + const url = ParsedURL.completeURL(this._sourceMappingURL, href) || href; + originalToCanonicalURLMap[originalSourceURL] = url; + sources.push(url); + this._sources[url] = true; + + if (map.sourcesContent && map.sourcesContent[i]) { + this._sourceContentByURL[url] = map.sourcesContent[i]; + } + } + + const stringCharIterator = new SourceMap.StringCharIterator(map.mappings); + let sourceURL = sources[sourceIndex]; + + while (true) { + if (stringCharIterator.peek() === ',') stringCharIterator.next(); + else { + while (stringCharIterator.peek() === ';') { + lineNumber += 1; + columnNumber = 0; + stringCharIterator.next(); + } + if (!stringCharIterator.hasNext()) break; + } + + columnNumber += this._decodeVLQ(stringCharIterator); + if (this._isSeparator(stringCharIterator.peek())) { + this._mappings.push([lineNumber, columnNumber]); + continue; + } + + const sourceIndexDelta = this._decodeVLQ(stringCharIterator); + if (sourceIndexDelta) { + sourceIndex += sourceIndexDelta; + sourceURL = sources[sourceIndex]; + } + sourceLineNumber += this._decodeVLQ(stringCharIterator); + sourceColumnNumber += this._decodeVLQ(stringCharIterator); + if (!this._isSeparator(stringCharIterator.peek())) + nameIndex += this._decodeVLQ(stringCharIterator); + + this._mappings.push([ + lineNumber, + columnNumber, + sourceURL, + sourceLineNumber, + sourceColumnNumber, + ]); + } + + for (let i = 0; i < this._mappings.length; ++i) { + const mapping = this._mappings[i]; + const url = mapping[2]; + if (!url) continue; + if (!this._reverseMappingsBySourceURL[url]) { + this._reverseMappingsBySourceURL[url] = []; + } + const reverseMappings = this._reverseMappingsBySourceURL[url]; + const sourceLine = mapping[3]; + if (!reverseMappings[sourceLine]) { + reverseMappings[sourceLine] = [mapping[0], mapping[1]]; + } + } + }, + + /** + * @param {string} char + * @return {boolean} + */ + _isSeparator(char) { + return char === ',' || char === ';'; + }, + + /** + * @param {SourceMap.StringCharIterator} stringCharIterator + * @return {number} + */ + _decodeVLQ(stringCharIterator) { + // Read unsigned value. + let result = 0; + let shift = 0; + let digit; + do { + digit = this._base64Map[stringCharIterator.next()]; + result += (digit & this._VLQ_BASE_MASK) << shift; + shift += this._VLQ_BASE_SHIFT; + } while (digit & this._VLQ_CONTINUATION_MASK); + + // Fix the sign. + const negate = result & 1; + // Use unsigned right shift, so that the 32nd bit is properly shifted + // to the 31st, and the 32nd becomes unset. + result >>>= 1; + if (negate) { + // We need to OR 0x80000000 here to ensure the 32nd bit (the sign bit + // in a 32bit int) is always set for negative numbers. If `result` + // were 1, (meaning `negate` is true and all other bits were zeros), + // `result` would now be 0. But -0 doesn't flip the 32nd bit as + // intended. All other numbers will successfully set the 32nd bit + // without issue, so doing this is a noop for them. + return -result | 0x80000000; + } + return result; + }, + + _VLQ_BASE_SHIFT: 5, + _VLQ_BASE_MASK: (1 << 5) - 1, + _VLQ_CONTINUATION_MASK: 1 << 5, +}; + +SourceMap.StringCharIterator = function StringCharIterator(string) { + this._string = string; + this._position = 0; +}; + +SourceMap.StringCharIterator.prototype = { + /** + * @return {string} + */ + next() { + return this._string.charAt(this._position++); + }, + + /** + * @return {string} + */ + peek() { + return this._string.charAt(this._position); + }, + + /** + * @return {boolean} + */ + hasNext() { + return this._position < this._string.length; + }, +}; + +function normalizePath(path) { + if (path.indexOf('..') === -1 && path.indexOf('.') === -1) { + return path; + } + // Remove leading slash (will be added back below) so we + // can handle all (including empty) segments consistently. + const segments = (path[0] === '/' ? path.substring(1) : path).split('/'); + const normalizedSegments = []; + for (const segment of segments) { + if (segment === '.') { + continue; + } else if (segment === '..') { + normalizedSegments.pop(); + } else { + normalizedSegments.push(segment); + } + } + let normalizedPath = normalizedSegments.join('/'); + if (path[0] === '/' && normalizedPath) { + normalizedPath = '/' + normalizedPath; + } + if ( + normalizedPath[normalizedPath.length - 1] !== '/' && + (path[path.length - 1] === '/' || + segments[segments.length - 1] === '.' || + segments[segments.length - 1] === '..') + ) { + normalizedPath = normalizedPath + '/'; + } + return normalizedPath; +} +export function schemeIs(url, scheme) { + try { + return new URL(url).protocol === scheme; + } catch (e) { + return false; + } +} +export class ParsedURL { + #displayNameInternal; + #dataURLDisplayNameInternal; + constructor(url) { + this.isValid = false; + this.url = url; + this.scheme = ''; + this.user = ''; + this.host = ''; + this.port = ''; + this.path = ''; + this.queryParams = ''; + this.fragment = ''; + this.folderPathComponents = ''; + this.lastPathComponent = ''; + const isBlobUrl = this.url.startsWith('blob:'); + const urlToMatch = isBlobUrl ? url.substring(5) : url; + const match = urlToMatch.match(ParsedURL.urlRegex()); + if (match) { + this.isValid = true; + if (isBlobUrl) { + this.blobInnerScheme = match[2].toLowerCase(); + this.scheme = 'blob'; + } else { + this.scheme = match[2].toLowerCase(); + } + this.user = match[3] ?? ''; + this.host = match[4] ?? ''; + this.port = match[5] ?? ''; + this.path = match[6] ?? '/'; + this.queryParams = match[7] ?? ''; + this.fragment = match[8] ?? ''; + } else { + if (this.url.startsWith('data:')) { + this.scheme = 'data'; + return; + } + if (this.url.startsWith('blob:')) { + this.scheme = 'blob'; + return; + } + if (this.url === 'about:blank') { + this.scheme = 'about'; + return; + } + this.path = this.url; + } + const lastSlashExceptTrailingIndex = this.path.lastIndexOf('/', this.path.length - 2); + if (lastSlashExceptTrailingIndex !== -1) { + this.lastPathComponent = this.path.substring(lastSlashExceptTrailingIndex + 1); + } else { + this.lastPathComponent = this.path; + } + const lastSlashIndex = this.path.lastIndexOf('/'); + if (lastSlashIndex !== -1) { + this.folderPathComponents = this.path.substring(0, lastSlashIndex); + } + } + static fromString(string) { + const parsedURL = new ParsedURL(string.toString()); + if (parsedURL.isValid) { + return parsedURL; + } + return null; + } + static preEncodeSpecialCharactersInPath(path) { + // Based on net::FilePathToFileURL. Ideally we would handle + // '\\' as well on non-Windows file systems. + for (const specialChar of ['%', ';', '#', '?', ' ']) { + path = path.replaceAll(specialChar, encodeURIComponent(specialChar)); + } + return path; + } + static rawPathToEncodedPathString(path) { + const partiallyEncoded = ParsedURL.preEncodeSpecialCharactersInPath(path); + if (path.startsWith('/')) { + return new URL(partiallyEncoded, 'file:///').pathname; + } + // URL prepends a '/' + return new URL('/' + partiallyEncoded, 'file:///').pathname.substring(1); + } + /** + * @param name Must not be encoded + */ + static encodedFromParentPathAndName(parentPath, name) { + return ParsedURL.concatenate(parentPath, '/', ParsedURL.preEncodeSpecialCharactersInPath(name)); + } + /** + * @param name Must not be encoded + */ + static urlFromParentUrlAndName(parentUrl, name) { + return ParsedURL.concatenate(parentUrl, '/', ParsedURL.preEncodeSpecialCharactersInPath(name)); + } + static encodedPathToRawPathString(encPath) { + return decodeURIComponent(encPath); + } + static rawPathToUrlString(fileSystemPath) { + let preEncodedPath = ParsedURL.preEncodeSpecialCharactersInPath( + fileSystemPath.replace(/\\/g, '/'), + ); + preEncodedPath = preEncodedPath.replace(/\\/g, '/'); + if (!preEncodedPath.startsWith('file://')) { + if (preEncodedPath.startsWith('/')) { + preEncodedPath = 'file://' + preEncodedPath; + } else { + preEncodedPath = 'file:///' + preEncodedPath; + } + } + return new URL(preEncodedPath).toString(); + } + static relativePathToUrlString(relativePath, baseURL) { + const preEncodedPath = ParsedURL.preEncodeSpecialCharactersInPath( + relativePath.replace(/\\/g, '/'), + ); + return new URL(preEncodedPath, baseURL).toString(); + } + static urlToRawPathString(fileURL, isWindows) { + console.assert(fileURL.startsWith('file://'), 'This must be a file URL.'); + const decodedFileURL = decodeURIComponent(fileURL); + if (isWindows) { + return decodedFileURL.substring('file:///'.length).replace(/\//g, '\\'); + } + return decodedFileURL.substring('file://'.length); + } + static sliceUrlToEncodedPathString(url, start) { + return url.substring(start); + } + static substr(devToolsPath, from, length) { + return devToolsPath.substr(from, length); + } + static substring(devToolsPath, start, end) { + return devToolsPath.substring(start, end); + } + static prepend(prefix, devToolsPath) { + return prefix + devToolsPath; + } + static concatenate(devToolsPath, ...appendage) { + return devToolsPath.concat(...appendage); + } + static trim(devToolsPath) { + return devToolsPath.trim(); + } + static slice(devToolsPath, start, end) { + return devToolsPath.slice(start, end); + } + static join(devToolsPaths, separator) { + return devToolsPaths.join(separator); + } + static split(devToolsPath, separator, limit) { + return devToolsPath.split(separator, limit); + } + static toLowerCase(devToolsPath) { + return devToolsPath.toLowerCase(); + } + static isValidUrlString(str) { + return new ParsedURL(str).isValid; + } + static urlWithoutHash(url) { + const hashIndex = url.indexOf('#'); + if (hashIndex !== -1) { + return url.substr(0, hashIndex); + } + return url; + } + static urlRegex() { + if (ParsedURL.urlRegexInstance) { + return ParsedURL.urlRegexInstance; + } + // RegExp groups: + // 1 - scheme, hostname, ?port + // 2 - scheme (using the RFC3986 grammar) + // 3 - ?user:password + // 4 - hostname + // 5 - ?port + // 6 - ?path + // 7 - ?query + // 8 - ?fragment + const schemeRegex = /([A-Za-z][A-Za-z0-9+.-]*):\/\//; + const userRegex = /(?:([A-Za-z0-9\-._~%!$&'()*+,;=:]*)@)?/; + const hostRegex = /((?:\[::\d?\])|(?:[^\s\/:]*))/; + const portRegex = /(?::([\d]+))?/; + const pathRegex = /(\/[^#?]*)?/; + const queryRegex = /(?:\?([^#]*))?/; + const fragmentRegex = /(?:#(.*))?/; + ParsedURL.urlRegexInstance = new RegExp( + '^(' + + schemeRegex.source + + userRegex.source + + hostRegex.source + + portRegex.source + + ')' + + pathRegex.source + + queryRegex.source + + fragmentRegex.source + + '$', + ); + return ParsedURL.urlRegexInstance; + } + static extractPath(url) { + const parsedURL = this.fromString(url); + return parsedURL ? parsedURL.path : ''; + } + static extractOrigin(url) { + const parsedURL = this.fromString(url); + return parsedURL ? parsedURL.securityOrigin() : ''; + } + static extractExtension(url) { + url = ParsedURL.urlWithoutHash(url); + const indexOfQuestionMark = url.indexOf('?'); + if (indexOfQuestionMark !== -1) { + url = url.substr(0, indexOfQuestionMark); + } + const lastIndexOfSlash = url.lastIndexOf('/'); + if (lastIndexOfSlash !== -1) { + url = url.substr(lastIndexOfSlash + 1); + } + const lastIndexOfDot = url.lastIndexOf('.'); + if (lastIndexOfDot !== -1) { + url = url.substr(lastIndexOfDot + 1); + const lastIndexOfPercent = url.indexOf('%'); + if (lastIndexOfPercent !== -1) { + return url.substr(0, lastIndexOfPercent); + } + return url; + } + return ''; + } + static extractName(url) { + let index = url.lastIndexOf('/'); + const pathAndQuery = index !== -1 ? url.substr(index + 1) : url; + index = pathAndQuery.indexOf('?'); + return index < 0 ? pathAndQuery : pathAndQuery.substr(0, index); + } + static completeURL(baseURL, href) { + // Return special URLs as-is. + const trimmedHref = href.trim(); + if ( + trimmedHref.startsWith('data:') || + trimmedHref.startsWith('blob:') || + trimmedHref.startsWith('javascript:') || + trimmedHref.startsWith('mailto:') + ) { + return href; + } + // Return absolute URLs with normalized path and other components as-is. + const parsedHref = this.fromString(trimmedHref); + if (parsedHref && parsedHref.scheme) { + const securityOrigin = parsedHref.securityOrigin(); + const pathText = normalizePath(parsedHref.path); + const queryText = parsedHref.queryParams && `?${parsedHref.queryParams}`; + const fragmentText = parsedHref.fragment && `#${parsedHref.fragment}`; + return securityOrigin + pathText + queryText + fragmentText; + } + const parsedURL = this.fromString(baseURL); + if (!parsedURL) { + return null; + } + if (parsedURL.isDataURL()) { + return href; + } + if (href.length > 1 && href.charAt(0) === '/' && href.charAt(1) === '/') { + // href starts with "//" which is a full URL with the protocol dropped (use the baseURL protocol). + return parsedURL.scheme + ':' + href; + } + const securityOrigin = parsedURL.securityOrigin(); + const pathText = parsedURL.path; + const queryText = parsedURL.queryParams ? '?' + parsedURL.queryParams : ''; + // Empty href resolves to a URL without fragment. + if (!href.length) { + return securityOrigin + pathText + queryText; + } + if (href.charAt(0) === '#') { + return securityOrigin + pathText + queryText + href; + } + if (href.charAt(0) === '?') { + return securityOrigin + pathText + href; + } + const hrefMatches = href.match(/^[^#?]*/); + if (!hrefMatches || !href.length) { + throw new Error('Invalid href'); + } + let hrefPath = hrefMatches[0]; + const hrefSuffix = href.substring(hrefPath.length); + if (hrefPath.charAt(0) !== '/') { + hrefPath = parsedURL.folderPathComponents + '/' + hrefPath; + } + return securityOrigin + normalizePath(hrefPath) + hrefSuffix; + } + static splitLineAndColumn(string) { + // Only look for line and column numbers in the path to avoid matching port numbers. + const beforePathMatch = string.match(ParsedURL.urlRegex()); + let beforePath = ''; + let pathAndAfter = string; + if (beforePathMatch) { + beforePath = beforePathMatch[1]; + pathAndAfter = string.substring(beforePathMatch[1].length); + } + const lineColumnRegEx = /(?::(\d+))?(?::(\d+))?$/; + const lineColumnMatch = lineColumnRegEx.exec(pathAndAfter); + let lineNumber; + let columnNumber; + console.assert(Boolean(lineColumnMatch)); + if (!lineColumnMatch) { + return { url: string, lineNumber: 0, columnNumber: 0 }; + } + if (typeof lineColumnMatch[1] === 'string') { + lineNumber = parseInt(lineColumnMatch[1], 10); + // Immediately convert line and column to 0-based numbers. + lineNumber = isNaN(lineNumber) ? undefined : lineNumber - 1; + } + if (typeof lineColumnMatch[2] === 'string') { + columnNumber = parseInt(lineColumnMatch[2], 10); + columnNumber = isNaN(columnNumber) ? undefined : columnNumber - 1; + } + let url = + beforePath + pathAndAfter.substring(0, pathAndAfter.length - lineColumnMatch[0].length); + if (lineColumnMatch[1] === undefined && lineColumnMatch[2] === undefined) { + const wasmCodeOffsetRegex = /wasm-function\[\d+\]:0x([a-z0-9]+)$/g; + const wasmCodeOffsetMatch = wasmCodeOffsetRegex.exec(pathAndAfter); + if (wasmCodeOffsetMatch && typeof wasmCodeOffsetMatch[1] === 'string') { + url = ParsedURL.removeWasmFunctionInfoFromURL(url); + columnNumber = parseInt(wasmCodeOffsetMatch[1], 16); + columnNumber = isNaN(columnNumber) ? undefined : columnNumber; + } + } + return { url, lineNumber, columnNumber }; + } + static removeWasmFunctionInfoFromURL(url) { + const wasmFunctionRegEx = /:wasm-function\[\d+\]/; + const wasmFunctionIndex = url.search(wasmFunctionRegEx); + if (wasmFunctionIndex === -1) { + return url; + } + return ParsedURL.substring(url, 0, wasmFunctionIndex); + } + static beginsWithWindowsDriveLetter(url) { + return /^[A-Za-z]:/.test(url); + } + static beginsWithScheme(url) { + return /^[A-Za-z][A-Za-z0-9+.-]*:/.test(url); + } + static isRelativeURL(url) { + return !this.beginsWithScheme(url) || this.beginsWithWindowsDriveLetter(url); + } + get displayName() { + if (this.#displayNameInternal) { + return this.#displayNameInternal; + } + if (this.isDataURL()) { + return this.dataURLDisplayName(); + } + if (this.isBlobURL()) { + return this.url; + } + if (this.isAboutBlank()) { + return this.url; + } + this.#displayNameInternal = this.lastPathComponent; + if (!this.#displayNameInternal) { + this.#displayNameInternal = (this.host || '') + '/'; + } + if (this.#displayNameInternal === '/') { + this.#displayNameInternal = this.url; + } + return this.#displayNameInternal; + } + dataURLDisplayName() { + if (this.#dataURLDisplayNameInternal) { + return this.#dataURLDisplayNameInternal; + } + if (!this.isDataURL()) { + return ''; + } + this.#dataURLDisplayNameInternal = trimEndWithMaxLength(this.url, 20); + return this.#dataURLDisplayNameInternal; + } + isAboutBlank() { + return this.url === 'about:blank'; + } + isDataURL() { + return this.scheme === 'data'; + } + isHttpOrHttps() { + return this.scheme === 'http' || this.scheme === 'https'; + } + isBlobURL() { + return this.url.startsWith('blob:'); + } + lastPathComponentWithFragment() { + return this.lastPathComponent + (this.fragment ? '#' + this.fragment : ''); + } + domain() { + if (this.isDataURL()) { + return 'data:'; + } + return this.host + (this.port ? ':' + this.port : ''); + } + securityOrigin() { + if (this.isDataURL()) { + return 'data:'; + } + const scheme = this.isBlobURL() ? this.blobInnerScheme : this.scheme; + return scheme + '://' + this.domain(); + } + urlWithoutScheme() { + if (this.scheme && this.url.startsWith(this.scheme + '://')) { + return this.url.substring(this.scheme.length + 3); + } + return this.url; + } + static { + this.urlRegexInstance = null; + } +} +export const trimEndWithMaxLength = (str, maxLength) => { + if (str.length <= maxLength) { + return String(str); + } + return str.substr(0, maxLength - 1) + '\u2026'; +}; diff --git a/benchmark/index.mjs b/benchmark/index.mjs index d8e5763..d564632 100644 --- a/benchmark/index.mjs +++ b/benchmark/index.mjs @@ -16,6 +16,7 @@ import { import { SourceMapConsumer as SourceMapConsumerJs } from 'source-map-js'; import { SourceMapConsumer as SourceMapConsumer061 } from 'source-map'; import { SourceMapConsumer as SourceMapConsumerWasm } from 'source-map-wasm'; +import { SourceMap as ChromeMap } from './chrome.mjs'; const dir = relative(process.cwd(), dirname(fileURLToPath(import.meta.url))); const diff = !!process.env.DIFF; @@ -68,7 +69,8 @@ async function bench(file) { latestEncoded, smcjs, smc061, - smcWasm; + smcWasm, + chromeMap; currentDecoded = await track('trace-mapping decoded', results, () => { const decoded = new CurrentTraceMap(decodedMapData); currentOriginalPositionFor(decoded, { line: 1, column: 0 }); @@ -106,6 +108,11 @@ async function bench(file) { smcWasm.originalPositionFor({ line: 1, column: 0 }); return smcWasm; }); + chromeMap = await track('Chrome dev tools', results, async () => { + const map = await new ChromeMap('url', encodedMapData); + map.findEntry(0, 0); + return map; + }); } const winner = results.reduce((min, cur) => { if (cur.delta < min.delta) return cur; @@ -144,6 +151,9 @@ async function bench(file) { }) .add('source-map-0.6.1: encoded Object input', () => { new SourceMapConsumer061(encodedMapData).originalPositionFor({ line: 1, column: 0 }); + }) + .add('Chrome dev tools: encoded Object input', () => { + new ChromeMap('url', encodedMapData).findEntry(0, 0); }); // WASM isn't tested because its async and OOMs. // .add('source-map-0.8.0: encoded Object input', () => { }) @@ -222,6 +232,14 @@ async function bench(file) { const j = Math.floor(Math.random() * line.length); const column = line[j][0]; smcWasm.originalPositionFor({ line: i + 1, column }); + }) + .add('Chrome dev tools: encoded originalPositionFor', () => { + const i = Math.floor(Math.random() * lines.length); + const line = lines[i]; + if (line.length === 0) return; + const j = Math.floor(Math.random() * line.length); + const column = line[j][0]; + chromeMap.findEntry(i, column); }); } diff --git a/benchmark/vscode.map b/benchmark/vscode.map new file mode 100644 index 0000000..0b5408e --- /dev/null +++ b/benchmark/vscode.map @@ -0,0 +1 @@ +{"version":3,"sources":["out-vscode-web/vs/workbench/fake","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/deviceAccess.ts","out-vscode-web/vs/workbench/vs/base/browser/dompurify/dompurify.js","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/fastDomNode.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/iframe.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/performance.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/list/list.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/list/splice.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/scrollbar/scrollbarState.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/tree/tree.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/window.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/amd.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/arraysFind.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/collections.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/color.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/decorators.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/diff/diffChange.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/errors.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/trustedTypes.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/arrays.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/assert.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/functional.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/idGenerator.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/iterator.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/json.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/jsonFormatter.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/jsonEdit.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/keyCodes.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/keybindings.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/keybindingParser.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/lazy.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/hover/hoverDelegate.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/linkedList.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/linkedText.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/map.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/lifecycle.ts","out-vscode-web/vs/workbench/vs/base/common/marked/marked.js","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/naturalLanguage/korean.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/navigator.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/history.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/numbers.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/observableInternal/debugName.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/observableInternal/logging.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/observableInternal/autorun.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/observableInternal/base.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/observableInternal/derived.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/observableInternal/utils.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/parsers.ts","out-vscode-web/vs/workbench/vs/base/common/performance.js","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/prefixTree.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/range.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/list/rangeMap.ts","out-vscode-web/vs/workbench/vs/base/common/semver/semver.js","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/skipList.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/stopwatch.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/event.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/broadcast.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/browser.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/event.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/cancellation.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/cache.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/ime.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/observableInternal/promise.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/observable.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/paging.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/scrollable.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/stream.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/buffer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/strings.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/filters.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/hash.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/hash.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/diff/diff.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/search.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/severity.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/symbols.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/ternarySearchTree.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/tfIdf.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/types.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/codicons.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/objects.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/themables.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/iconLabels.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/uint.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/uuid.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/dataTransfer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/verifier.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/parts/request/common/request.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/parts/request/browser/request.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/codicons/codiconStyles.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/mouseCursor/mouseCursor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/config/domFontInfo.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/config/charWidthReader.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/config/migrateOptions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/config/tabFocus.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/stableEditorScroll.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/view/renderingContext.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/viewParts/lines/domReadingContext.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/viewParts/lines/rangeUtil.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/viewParts/minimap/minimapCharSheet.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/viewParts/minimap/minimapCharRenderer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/viewParts/minimap/minimapPreBaked.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/viewParts/minimap/minimapCharRendererFactory.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/widget/diffEditor/delegatingEditorImpl.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/widget/multiDiffEditorWidget/model.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/widget/multiDiffEditorWidget/objectPool.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/config/diffEditor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/config/editorZoom.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/core/characterClassifier.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/core/cursorColumns.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/core/eolCounter.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/core/indentation.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/core/offsetRange.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/core/position.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/view/viewUserInputEvents.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/core/range.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/controller/textAreaState.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/core/editOperation.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/commands/trimTrailingWhitespaceCommand.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/core/lineRange.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/core/rgba.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/core/selection.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/commands/replaceCommand.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/commands/surroundSelectionCommand.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/core/textModelDefaults.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/core/wordCharacterClassifier.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/core/wordHelper.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/cursor/cursorAtomicMoveOperations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/cursor/cursorContext.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/diff/defaultLinesDiffComputer/algorithms/diffAlgorithm.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/diff/defaultLinesDiffComputer/algorithms/myersDiffAlgorithm.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/diff/defaultLinesDiffComputer/heuristicSequenceOptimizations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/diff/defaultLinesDiffComputer/lineSequence.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/diff/defaultLinesDiffComputer/utils.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/diff/defaultLinesDiffComputer/algorithms/dynamicProgrammingDiffing.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/diff/defaultLinesDiffComputer/linesSliceCharSequence.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/diff/linesDiffComputer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/diff/rangeMapping.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/diff/defaultLinesDiffComputer/computeMovedLines.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/diff/defaultLinesDiffComputer/defaultLinesDiffComputer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/diff/legacyLinesDiffComputer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/diff/linesDiffComputers.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/editorAction.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/editorCommon.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/editorBrowser.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/editorFeatures.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/editorTheme.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/encodedTokenAttributes.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/languages/defaultDocumentColorsComputer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/languages/languageConfiguration.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/languages/linkComputer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/languages/supports.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/cursorCommon.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/cursor/cursorColumnSelection.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/cursor/cursorMoveOperations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/cursor/cursorDeleteOperations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/cursor/cursorWordOperations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/cursor/cursorMoveCommands.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/cursor/oneCursor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/cursor/cursorCollection.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/languages/supports/characterPair.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/languages/supports/indentRules.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/languages/supports/inplaceReplaceSupport.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/languages/supports/languageBracketsConfiguration.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/languages/supports/onEnter.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/languages/supports/tokenization.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/model.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/length.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/beforeEditPositionMapper.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/combineTextEditInfos.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/nodeReader.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/smallImmutableSet.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/ast.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/concat23Trees.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/parser.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/tokenizer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/brackets.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/model/bracketPairsTextModelPart/fixBrackets.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/model/fixedArray.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/model/indentationGuesser.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/model/intervalTree.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/model/pieceTreeTextBuffer/rbTreeBase.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/model/prefixSumComputer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/model/mirrorTextModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/model/textModelPart.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/model/textModelSearch.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/model/utils.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/modelLineProjectionData.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/services/treeViewsDnd.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/services/unicodeTextModelHighlighter.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/standalone/standaloneEnums.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/textModelBracketPairs.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/bracketPairsTree.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/textModelEvents.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/textModelGuides.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/model/guidesTextModelPart.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/tokenizationRegistry.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/tokens/lineTokens.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/tokens/contiguousTokensEditing.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/tokens/contiguousMultilineTokens.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/tokens/contiguousMultilineTokensBuilder.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/tokens/contiguousTokensStore.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/tokens/sparseMultilineTokens.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/tokens/sparseTokensStore.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/viewEventHandler.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/view/dynamicViewOverlay.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/view/viewPart.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/viewParts/blockDecorations/blockDecorations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/viewParts/decorations/decorations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/viewParts/glyphMargin/glyphMargin.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/viewParts/linesDecorations/linesDecorations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/viewParts/margin/margin.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/viewParts/marginDecorations/marginDecorations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/viewParts/rulers/rulers.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/viewParts/scrollDecoration/scrollDecoration.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/viewParts/viewZones/viewZones.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/viewEvents.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/viewLayout/lineDecorations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/viewLayout/linePart.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/viewLayout/linesLayout.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/viewLayout/viewLinesViewportData.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/viewModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/viewModel/glyphLanesModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/viewModel/modelLineProjection.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/viewModel/monospaceLineBreaksComputer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/viewModel/overviewZoneManager.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/viewParts/overviewRuler/overviewRuler.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/viewModel/viewContext.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/viewModelEventDispatcher.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/viewLayout/viewLayout.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/caretOperations/browser/moveCaretCommand.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/codeAction/common/types.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/colorPicker/browser/colorPickerModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/comment/browser/blockCommentCommand.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/comment/browser/lineCommentCommand.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/dnd/browser/dragAndDropCommand.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/find/browser/replaceAllCommand.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/find/browser/replacePattern.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/folding/browser/foldingRanges.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/folding/browser/foldingModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/folding/browser/hiddenRangeModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/folding/browser/indentRangeProvider.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/folding/browser/syntaxRangeProvider.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/format/browser/formattingEdit.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/hover/browser/hoverTypes.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/inPlaceReplace/browser/inPlaceReplaceCommand.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/indentation/browser/indentUtils.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/inlineCompletions/browser/commandIds.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/inlineCompletions/browser/utils.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/inlineCompletions/browser/ghostText.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/inlineCompletions/browser/singleTextEdit.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/inlineEdit/browser/commandIds.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/linesOperations/browser/copyLinesCommand.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/linesOperations/browser/sortLinesCommand.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/semanticTokens/common/semanticTokensConfig.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/smartSelect/browser/bracketSelections.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/smartSelect/browser/wordSelections.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/snippet/browser/snippetParser.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/stickyScroll/browser/stickyScrollElement.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/suggest/browser/completionModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/suggest/browser/suggestCommitCharacters.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/suggest/browser/suggestOvertypingCapturer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/suggest/browser/wordDistance.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/actions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/tree/treeDefaults.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/widget/multiDiffEditorWidget/utils.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/date.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/errorMessage.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/indexedDB.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/jsonErrorMessages.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/keybindingLabels.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/platform.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/canIUse.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/keyboardEvent.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/mouseEvent.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/process.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/hotReload.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/path.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/comparers.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/extpath.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/fuzzyScorer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/mime.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/processes.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/uri.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/console.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/marshalling.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/network.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/amdX.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/resources.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/async.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/dom.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/dnd.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/formattedTextRenderer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/globalPointerMoveMonitor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/pixelRatio.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/touch.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/aria/aria.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/contextview/contextview.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/countBadge/countBadge.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/iconLabel/iconLabels.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/highlightedlabel/highlightedLabel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/iconLabel/simpleIconLabel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/keybindingLabel/keybindingLabel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/list/rowCache.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/progressbar/progressbar.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/sash/sash.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/resizable/resizable.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/scrollbar/scrollbarVisibilityController.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/selectBox/selectBoxNative.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/tree/indexTreeModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/tree/objectTreeModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/tree/compressedObjectTreeModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/widget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/scrollbar/scrollbarArrow.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/scrollbar/abstractScrollbar.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/scrollbar/horizontalScrollbar.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/scrollbar/verticalScrollbar.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/scrollbar/scrollableElement.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/hover/hoverWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/list/listView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/list/listWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/list/listPaging.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/splitview/splitview.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/centered/centeredViewLayout.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/grid/gridview.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/grid/grid.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/splitview/paneview.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/glob.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/htmlContent.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/markdownRenderer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/iconLabel/iconLabelHover.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/button/button.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/dropdown/dropdown.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/iconLabel/iconLabel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/selectBox/selectBox.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/actionbar/actionViewItems.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/actionbar/actionbar.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/dropdown/dropdownActionViewItem.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/inputbox/inputBox.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/icons/iconSelectBox.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/menu/menu.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/menu/menubar.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/table/tableWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/toggle/toggle.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/findinput/findInputToggles.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/findinput/findInput.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/findinput/replaceInput.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/toolbar/toolbar.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/tree/abstractTree.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/tree/dataTree.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/tree/objectTree.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/tree/asyncDataTree.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/labels.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/ui/dialog/dialog.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/resourceTree.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/uriIpc.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/common/worker/simpleWorker.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/browser/defaultWorkerFactory.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/parts/ipc/common/ipc.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/parts/ipc/common/ipc.net.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/base/parts/storage/common/storage.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/config/elementSizeObserver.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/viewParts/overlayWidgets/overlayWidgets.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/widget/codeEditorContributions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/widget/diffEditor/components/diffEditorSash.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/widget/diffEditor/utils.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/core/stringBuilder.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/view/domLineBreaksComputer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/view/viewLayer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/view/viewOverlays.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/core/textChange.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/languageSelector.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/languageFeatureRegistry.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/languages/supports/richEditBrackets.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/languages/supports/electricCharacter.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsImpl.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBufferBuilder.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/services/semanticTokensDto.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/gotoSymbol/browser/link/clickLinkGesture.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/hover/browser/hoverOperation.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/inlayHints/browser/inlayHints.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/inlineCompletions/browser/provideInlineCompletions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/widget/diffEditor/components/diffEditorViewZones/inlineDiffDeletedCodeMargin.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/widget/diffEditor/features/movedBlocksLinesFeature.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/widget/diffEditor/features/revertButtonsFeature.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/config/editorOptions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/viewParts/viewCursors/viewCursor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/widget/diffEditor/diffEditorOptions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/config/fontInfo.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/config/fontMeasurements.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/viewModel/viewModelDecorations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/languages.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/languages/nullTokenize.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/languages/textToHtmlTokenizer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/model/textModelTokens.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/model/tokenizationTextModelPart.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/services/editorBaseApi.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/services/editorSimpleWorker.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/viewModel/minimapTokensColorTracker.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/model/editStack.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/standaloneStrings.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/viewLayout/viewLineRenderer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/widget/diffEditor/components/diffEditorViewZones/renderLines.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/gotoSymbol/browser/referencesModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/action/common/action.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/action/common/actionCommonCategories.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/assignment/common/assignment.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/backup/common/backup.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/contextkey/common/scanner.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/debug/common/extensionHostDebugIpc.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/download/common/downloadIpc.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/editor/common/editor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/environment/common/environmentService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/extensionManagement/common/configRemotes.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/extensionManagement/common/extensionNls.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/extensions/common/extensionValidator.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/externalServices/common/serviceMachineId.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/files/browser/webFileSystemAccess.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/history/browser/historyWidgetKeybindingHint.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/instantiation/common/descriptors.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/instantiation/common/extensions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/instantiation/common/graph.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/instantiation/common/instantiation.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/services/bulkEditService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/services/codeEditorService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/widget/diffEditor/features/hideUnchangedRegionsFeature.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/languages/language.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/services/editorWorker.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/services/languageFeatures.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/services/languageFeaturesService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/services/markerDecorations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/services/model.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/services/resolverService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/services/semanticTokensStyling.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/services/textResourceConfiguration.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/services/treeViewsDndService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/dropOrPasteInto/browser/edit.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/inlineCompletions/browser/ghostTextWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/inlineEdit/browser/ghostTextWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/clipboard/common/clipboardService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/commands/common/commands.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/codelens/browser/codelens.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/links/browser/getLinks.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/semanticTokens/common/getSemanticTokens.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/configuration/common/configuration.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/services/textResourceConfigurationService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/contextkey/common/contextkey.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/editorContextKeys.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionContextKeys.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/parameterHints/browser/provideSignatureHelp.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/parameterHints/browser/parameterHintsModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/suggest/browser/suggestAlternatives.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/suggest/browser/wordContextKey.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/accessibility/common/accessibility.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/config/editorConfiguration.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/contextkey/browser/contextKeyService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/contextkey/common/contextkeys.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/contextview/browser/contextView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/debug/common/extensionHostDebug.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/diagnostics/common/diagnostics.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/dialogs/common/dialogs.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/download/common/download.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/encryption/common/encryptionService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/environment/common/environment.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/extensionManagement/common/extensionManagement.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/extensionRecommendations/common/extensionRecommendations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/externalTerminal/common/externalTerminal.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/files/common/files.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/files/browser/htmlFileSystemProvider.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/files/browser/indexedDBFileSystemProvider.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/files/common/inMemoryFilesystemProvider.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/files/common/io.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/files/common/watcher.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/files/common/diskFileSystemProviderClient.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/hover/browser/hover.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/instantiation/common/serviceCollection.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/instantiation/common/instantiationService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/issue/common/issueReporterUtil.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/keybinding/common/baseResolvedKeybinding.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/keybinding/common/keybinding.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/dropOrPasteInto/browser/postEditWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/keybinding/common/keybindingResolver.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/keybinding/common/abstractKeybindingService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/keybinding/common/resolvedKeybindingItem.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/keybinding/common/usLayoutResolvedKeybinding.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/keyboardLayout/common/keyboardLayout.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/keyboardLayout/common/keyboardMapper.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/label/common/label.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/languagePacks/common/languagePacks.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/languagePacks/common/localizedStrings.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/layout/browser/layoutService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/accessibility/browser/accessibilityService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/contextview/browser/contextViewService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/layout/browser/zIndexRegistry.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/lifecycle/common/lifecycle.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/log/common/log.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/controller/textAreaInput.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/services/languageFeatureDebounce.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/documentSymbols/browser/outlineModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/diffEditorBreadcrumbs/browser/contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/documentSymbols/browser/documentSymbols.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/clipboard/browser/clipboardService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/files/common/fileService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/log/browser/log.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/log/common/bufferLog.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/log/common/fileLog.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/log/common/logIpc.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/log/common/logService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/markers/common/markers.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/gotoError/browser/markerNavigationService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/markers/common/markerService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/notification/common/notification.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/opener/common/opener.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/services/openerService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/opener/browser/link.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/policy/common/policy.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/product/common/product.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/product/common/productService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/progress/common/progress.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/quickinput/browser/pickerQuickAccess.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/quickinput/browser/quickInputBox.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/quickinput/browser/quickInputUtils.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/quickinput/browser/quickPickPin.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/quickinput/common/quickInput.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/registry/common/platform.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/dnd/browser/dnd.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/dnd.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/jsonschemas/common/jsonContributionRegistry.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/configuration/common/configurationRegistry.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/config/editorConfigurationSchema.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/languages/modesRegistry.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/widget/markdownRenderer/browser/markdownRenderer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/widget/hoverWidget/hoverWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/languages/languageConfigurationRegistry.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/services/editorWorkerService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/services/webWorker.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/languages/autoIndent.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/languages/enterAction.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/commands/shiftCommand.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/cursor/cursorTypeOperations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/cursor/cursor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/services/getIconClasses.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/services/languagesAssociations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/services/languagesRegistry.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/services/languageService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/colorPicker/browser/defaultDocumentColorProvider.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/colorPicker/browser/color.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/hover/browser/marginHover.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsSource.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/linesOperations/browser/moveLinesCommand.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/suggest/browser/suggestWidgetDetails.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/configuration/common/configurationModels.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/configuration/common/configurations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/keybinding/common/keybindingsRegistry.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/actions/common/actions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/toggleTabFocusMode/browser/toggleTabFocusMode.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/actions/common/menuResetAction.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/history/browser/contextScopedHistoryWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/suggest/browser/suggest.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/keyboardLayout/common/keyboardConfig.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/quickinput/common/quickAccess.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/quickinput/browser/helpQuickAccess.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/quickinput/browser/quickAccess.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/remote/common/managedSocket.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/remote/common/remoteAuthorityResolver.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/remote/browser/browserSocketFactory.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/remote/common/remoteExtensionsScanner.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/remote/common/remoteHosts.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/extensions/common/extensions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/extensionManagement/common/implicitActivationEvents.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/remote/common/remoteAgentConnection.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/remote/common/remoteSocketFactoryService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/request/common/request.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/download/common/downloadService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/request/browser/requestService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/request/common/requestIpc.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/severityIcon/browser/severityIcon.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/sign/common/abstractSignService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/sign/browser/signService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/sign/common/sign.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/storage/common/storageIpc.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/telemetry/common/commonProperties.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/telemetry/common/errorTelemetry.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/telemetry/browser/errorTelemetry.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/telemetry/common/telemetry.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/editorExtensions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/coreCommands.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/services/markerDecorations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/view/viewController.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/widget/diffEditor/diffProviderFactoryService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/widget/diffEditor/diffEditorViewModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/widget/multiDiffEditorWidget/multiDiffEditorViewModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/anchorSelect/browser/anchorSelect.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/caretOperations/browser/caretOperations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/caretOperations/browser/transpose.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/comment/browser/comment.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/cursorUndo/browser/cursorUndo.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/editorState/browser/keybindingCancellation.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/editorState/browser/editorState.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/codeAction/browser/codeAction.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/codeAction/browser/codeActionKeybindingResolver.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/codeAction/browser/codeActionModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/codeAction/browser/lightBulbWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/fontZoom/browser/fontZoom.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/gotoSymbol/browser/goToSymbol.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/gotoSymbol/browser/symbolNavigation.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/hover/browser/getHover.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/hover/browser/markdownHoverParticipant.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/indentation/browser/indentation.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/lineSelection/browser/lineSelection.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/linesOperations/browser/linesOperations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/longLinesHelper/browser/longLinesHelper.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/message/browser/messageController.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/readOnlyMessage/browser/contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/smartSelect/browser/smartSelect.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/tokenization/browser/tokenization.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/unusualLineTerminators/browser/unusualLineTerminators.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/wordOperations/browser/wordOperations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/wordPartOperations/browser/wordPartOperations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/accessibilitySignal/browser/accessibilitySignalService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/format/browser/format.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/format/browser/formatActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/actions/browser/buttonbar.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/telemetry/common/telemetryUtils.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/assignment/common/assignmentService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/extensionManagement/common/extensionManagementUtil.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/extensionManagement/common/extensionManagementCLI.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/extensionManagement/common/extensionTipsService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/extensionManagement/common/unsupportedExtensionsMigration.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/extensionResourceLoader/common/extensionResourceLoader.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/externalServices/common/marketplace.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/languagePacks/browser/languagePacks.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/telemetry/common/1dsAppender.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/telemetry/browser/1dsAppender.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/telemetry/common/telemetryLogAppender.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/telemetry/common/telemetryService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/terminal/common/capabilities/bufferMarkCapability.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/terminal/common/capabilities/commandDetection/terminalCommand.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/terminal/common/capabilities/cwdDetectionCapability.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/terminal/common/capabilities/naiveCwdDetectionCapability.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/terminal/common/capabilities/partialCommandDetectionCapability.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/terminal/common/capabilities/terminalCapabilityStore.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/terminal/common/environmentVariable.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/terminal/common/environmentVariableCollection.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/terminal/common/environmentVariableShared.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/terminal/common/terminal.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/terminal/common/terminalDataBuffering.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/terminal/common/terminalEnvironment.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/terminal/common/terminalProfiles.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/terminal/common/terminalPlatformConfiguration.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/terminal/common/terminalRecorder.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/terminal/common/terminalStrings.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/theme/common/colorRegistry.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/editorDom.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/viewParts/minimap/minimap.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/widget/multiDiffEditorWidget/colors.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/symbolIcons/browser/symbolIcons.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/theme/browser/defaultStyles.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/gotoSymbol/browser/peek/referencesTree.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/actionWidget/browser/actionList.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/actionWidget/browser/actionWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/contextview/browser/contextMenuHandler.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/list/browser/listService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/theme/common/iconRegistry.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/widget/diffEditor/components/accessibleDiffViewer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/colorPicker/browser/colorPickerWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/parameterHints/browser/parameterHintsWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/parameterHints/browser/parameterHints.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/unicodeHighlighter/browser/bannerController.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/theme/browser/iconsStyleSheet.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/theme/common/theme.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/viewParts/lines/viewLine.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/controller/mouseTarget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/controller/mouseHandler.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/controller/pointerHandler.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/viewParts/lines/viewLines.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/quickinput/browser/quickInputList.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/quickinput/browser/quickInput.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/quickinput/browser/quickInputController.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/theme/common/themeService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/services/abstractCodeEditorService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/services/hoverService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/viewParts/editorScrollbar/editorScrollbar.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/viewParts/selections/selections.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/widget/diffEditor/features/overviewRulerFeature.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/widget/diffEditor/components/diffEditorEditors.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/core/editorColorRegistry.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/viewParts/indentGuides/indentGuides.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/viewParts/lineNumbers/lineNumbers.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/controller/textAreaHandler.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/viewParts/overviewRuler/decorationsOverviewRuler.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/viewParts/viewCursors/viewCursors.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/viewParts/whitespace/whitespace.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/view.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/model/bracketPairsTextModelPart/colorizedBracketPairsDecorationProvider.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/services/markerDecorationsService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/services/semanticTokensProviderStyling.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/services/semanticTokensStylingService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/quickAccess/browser/editorNavigationQuickAccess.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/quickAccess/browser/gotoLineQuickAccess.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/quickAccess/browser/gotoSymbolQuickAccess.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/rename/browser/renameInputField.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/rename/browser/rename.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/semanticTokens/browser/documentSemanticTokens.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/semanticTokens/browser/viewportSemanticTokens.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/suggest/browser/suggestWidgetRenderer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/quickinput/browser/quickInputService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/theme/common/tokenClassificationRegistry.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/tunnel/common/tunnel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/undoRedo/common/undoRedo.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/model/textModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/widget/diffEditor/registrations.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/widget/diffEditor/components/diffEditorDecorations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/widget/diffEditor/components/diffEditorViewZones/diffEditorViewZones.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/services/modelService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/services/modelUndoRedoParticipant.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/viewModel/viewModelLines.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/common/viewModel/viewModelImpl.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/widget/codeEditorWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/widget/diffEditor/diffEditorWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/widget/diffEditor/diffEditor.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/widget/embeddedCodeEditorWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/bracketMatching/browser/bracketMatching.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/codeAction/browser/codeActionController.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/codeAction/browser/codeActionContributions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/codelens/browser/codelensWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/colorPicker/browser/colorDetector.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/colorPicker/browser/colorHoverParticipant.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/dnd/browser/dnd.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/find/browser/findDecorations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/find/browser/findModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/find/browser/findOptionsWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/find/browser/findState.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/find/browser/findWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/folding/browser/foldingDecorations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/folding/browser/folding.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/hover/browser/contentHover.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/colorPicker/browser/standaloneColorPickerWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/colorPicker/browser/standaloneColorPickerActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/inPlaceReplace/browser/inPlaceReplace.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/inlineProgress/browser/inlineProgress.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/dropOrPasteInto/browser/copyPasteController.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/clipboard/browser/clipboard.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/dropOrPasteInto/browser/dropIntoEditorController.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/linkedEditing/browser/linkedEditing.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/links/browser/links.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/stickyScroll/browser/stickyScrollModelProvider.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/stickyScroll/browser/stickyScrollProvider.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/stickyScroll/browser/stickyScrollWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/wordHighlighter/browser/highlightDecorations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/wordHighlighter/browser/wordHighlighter.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/undoRedo/common/undoRedoService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/update/common/update.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/update/common/update.config.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/uriIdentity/common/uriIdentity.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/uriIdentity/common/uriIdentityService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/url/common/url.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/url/common/urlService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/userDataSync/common/content.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/userDataSync/common/extensionsMerge.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/userDataSync/common/ignoredExtensions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/userDataSync/common/keybindingsMerge.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/userDataSync/common/snippetsMerge.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/userDataSync/common/userDataProfilesManifestMerge.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/userDataSync/common/userDataSync.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/userDataSync/common/globalStateMerge.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/userDataSync/common/settingsMerge.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/userDataSync/common/userDataSyncAccount.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/userDataSync/common/userDataSyncLog.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/webview/common/mimeTypes.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/webview/common/webviewPortMapping.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/window/common/window.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/workspace/common/canonicalUri.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/workspace/common/editSessions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/workspace/common/virtualWorkspace.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/workspace/common/workspace.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/contextmenu/browser/contextmenu.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/dropOrPasteInto/browser/defaultProviders.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/dropOrPasteInto/browser/copyPasteContribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/dropOrPasteInto/browser/dropIntoEditorContribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/snippet/browser/snippetVariables.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/snippet/browser/snippetSession.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/snippet/browser/snippetController2.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/suggest/browser/suggestModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/terminal/common/terminalLogService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/userDataProfile/common/userDataProfile.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/extensionManagement/common/abstractExtensionManagementService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/storage/common/storage.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/codelens/browser/codeLensCache.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/codelens/browser/codelensController.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/find/browser/findController.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/multicursor/browser/multicursor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/suggest/browser/suggestMemory.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/suggest/browser/suggestInlineCompletions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/actions/browser/menuEntryActionViewItem.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/peekView/browser/peekView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/gotoError/browser/gotoErrorWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/gotoError/browser/gotoError.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/gotoSymbol/browser/peek/referencesWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/gotoSymbol/browser/peek/referencesController.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/gotoSymbol/browser/goToCommands.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/gotoSymbol/browser/link/goToDefinitionAtPosition.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/hover/browser/markerHoverParticipant.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/inlayHints/browser/inlayHintsLocations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/inlayHints/browser/inlayHintsController.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/inlayHints/browser/inlayHintsHover.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/inlayHints/browser/inlayHintsContribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/stickyScroll/browser/stickyScrollController.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/stickyScroll/browser/stickyScrollActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/stickyScroll/browser/stickyScrollContribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/suggest/browser/suggestWidgetStatus.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/suggest/browser/suggestWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/suggest/browser/suggestController.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/inlineCompletions/browser/suggestWidgetInlineCompletionProvider.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/actions/browser/dropdownWithPrimaryActionViewItem.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/actions/browser/floatingMenu.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/actions/browser/toolbar.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/widget/multiDiffEditorWidget/diffEditorItemTemplate.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/widget/multiDiffEditorWidget/multiDiffEditorWidgetImpl.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/browser/widget/multiDiffEditorWidget/multiDiffEditorWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsHintsWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/hover/browser/hover.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/colorPicker/browser/colorContributions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsController.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/inlineCompletions/browser/commands.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/inlineCompletions/browser/hoverParticipant.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/inlineCompletions/browser/inlineCompletions.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/inlineEdit/browser/inlineEditHintsWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/inlineEdit/browser/inlineEditController.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/inlineEdit/browser/commands.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/inlineEdit/browser/hoverParticipant.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/inlineEdit/browser/inlineEdit.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/actions/common/menuService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/actions/common/actions.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/contextview/browser/contextMenuService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/extensionManagement/common/extensionEnablementService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/extensionManagement/common/extensionGalleryService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/extensionManagement/common/extensionStorage.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/extensionResourceLoader/browser/extensionResourceLoaderService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/quickinput/browser/commandsQuickAccess.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/quickAccess/browser/commandsQuickAccess.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/secrets/common/secrets.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/userDataProfile/browser/userDataProfile.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/userDataProfile/common/userDataProfileIpc.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/userDataProfile/common/userDataProfileStorageService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/userDataSync/common/abstractSynchronizer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/userDataSync/common/extensionsSync.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/userDataSync/common/globalStateSync.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/userDataSync/common/keybindingsSync.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/userDataSync/common/settingsSync.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/userDataSync/common/snippetsSync.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/userDataSync/common/tasksSync.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/userDataSync/common/userDataProfilesManifestSync.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/userDataSync/common/userDataSyncEnablementService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/userDataSync/common/userDataSyncLocalStoreService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/userDataSync/common/userDataSyncMachines.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/userDataSync/common/userDataSyncResourceProvider.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/userDataSync/common/userDataSyncService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/workspace/common/workspaceTrust.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/contrib/unicodeHighlighter/browser/unicodeHighlighter.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/editor/editor.all.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/platform/workspaces/common/workspaces.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/common/extHostInitDataService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/common/extHostRpcService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/common/extHostWebviewMessaging.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/common/shared/dataTransferCache.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/actions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/actions/helpActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/actions/listCommands.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/dialogs/dialogHandler.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/editor/breadcrumbs.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/editor/editor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/editor/editorGroupWatermark.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/notifications/notificationsAlerts.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/notifications/notificationsTelemetry.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/views/checkbox.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/views/viewFilter.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/quickaccess.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/actions/quickAccessActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/web.api.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/common/activity.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/common/dialogs.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/common/editor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/common/contextkeys.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/titlebar/titlebarActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/common/editor/editorInput.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/common/editor/editorModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/common/editor/binaryEditorModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/common/editor/diffEditorModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/common/editor/editorOptions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/common/editor/filteredEditorGroupModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/common/editor/textDiffEditorModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/common/memento.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/common/component.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/composite.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/part.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/editor/editorPane.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/common/notifications.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/notifications/notificationsCommands.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/notifications/notificationsActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/notifications/notificationsViewer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/common/resources.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/common/theme.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/notifications/notificationsList.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/style.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/common/views.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/accessibility/browser/unfocusedViewDimmingContribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/bulkEdit/browser/bulkTextEdits.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/callHierarchy/common/callHierarchy.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/callHierarchy/browser/callHierarchyTree.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/browser/chat.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/browser/chatAccessibilityService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/browser/chatOptions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/browser/chatSlashCommandContentWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/common/chatAgents.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/common/chatColors.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/common/chatContextKeys.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/common/chatContributionService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/common/chatParserTypes.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/browser/chatFollowups.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/browser/chatMarkdownDecorationsRenderer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/common/chatProvider.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/common/chatService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/browser/chatEditorInput.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/common/chatModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/common/chatVariables.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/common/chatWidgetHistoryService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/common/chatWordCounter.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/common/chatViewModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/codeActions/browser/codeActionsContribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/codeActions/browser/documentationContribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/codeEditor/browser/editorLineNumberMenu.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/codeEditor/browser/largeFileOptimizations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/codeEditor/browser/menuPreventer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsTree.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/codeEditor/browser/selectionClipboard.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/codeEditor/browser/toggleColumnSelection.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/codeEditor/browser/toggleMinimap.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/codeEditor/browser/toggleRenderControlCharacter.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/codeEditor/browser/toggleRenderWhitespace.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/codeEditor/browser/workbenchReferenceSearch.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/commands/common/commands.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/comments/browser/commentColors.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/comments/browser/commentFormActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/comments/browser/commentGlyphWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/comments/browser/commentMenus.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/comments/browser/commentThreadAdditionalActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/comments/browser/commentThreadHeader.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/comments/browser/commentThreadRangeDecorator.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/comments/browser/comments.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/comments/browser/commentsFilterOptions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/comments/browser/reactionsAction.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/comments/common/commentContextKeys.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/comments/common/commentModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/comments/browser/commentsModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/comments/common/commentsConfiguration.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/comments/browser/timestamp.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/customEditor/common/customEditorModelManager.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/debugIcons.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/debugColors.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/common/abstractDebugAdapter.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/common/breakpoints.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/common/debug.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/accessibilitySignals/browser/accessibilitySignalDebuggerContribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/callStackEditorContribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/debugMemory.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/common/debugCompoundRoot.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/common/debugContext.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/common/debugTelemetry.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/common/debugUtils.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/common/debugViewModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/common/disassemblyViewInput.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/editSessions/common/editSessions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/editSessions/browser/editSessionsFileSystemProvider.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/editSessions/common/editSessionsLogService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/editSessions/common/editSessionsStorageClient.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/browser/extensionRecommendations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/browser/configBasedRecommendations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/browser/exeBasedRecommendations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/browser/extensionsCompletionItemsProvider.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/browser/extensionsIcons.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/browser/keymapRecommendations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/browser/languageRecommendations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/browser/remoteRecommendations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/common/extensionQuery.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/common/extensions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/common/extensionsFileTemplate.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/common/extensionsInput.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/common/runtimeExtensionsInput.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/files/browser/explorerFileContrib.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/files/browser/fileConstants.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/files/common/explorerFileNestingTrie.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/files/common/explorerModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/inlayHints/browser/inlayHintsAccessibilty.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/inlineChat/browser/inlineChatSavingService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/inlineChat/browser/inlineChatSessionService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/inlineChat/browser/utils.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/interactive/browser/interactiveCommon.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/interactive/browser/interactiveDocumentService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/interactive/browser/interactiveHistoryService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/localHistory/browser/localHistory.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/localHistory/browser/localHistoryFileSystemProvider.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/mappedEdits/common/mappedEdits.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/markdown/browser/markdownDocumentRenderer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/markers/browser/markersFilterOptions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/markers/browser/markersModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/markers/browser/messages.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/markers/common/markers.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/markers/browser/markersViewActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/markers/browser/markersTable.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/mergeEditor/browser/model/editing.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/mergeEditor/browser/model/lineRange.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/mergeEditor/browser/mergeMarkers/mergeMarkersController.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/mergeEditor/browser/model/rangeUtils.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/mergeEditor/browser/telemetry.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/mergeEditor/browser/utils.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/mergeEditor/browser/model/mapping.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/mergeEditor/browser/model/diffComputer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/mergeEditor/browser/model/modifiedBaseRange.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/mergeEditor/browser/model/textModelDiffs.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/mergeEditor/browser/model/mergeEditorModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/mergeEditor/browser/view/colors.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/mergeEditor/browser/view/editorGutter.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/mergeEditor/browser/view/editors/codeEditorView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/mergeEditor/browser/view/editors/baseCodeEditorView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/mergeEditor/browser/view/editors/inputCodeEditorView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/mergeEditor/browser/view/fixedZoneWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/mergeEditor/browser/view/conflictActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/mergeEditor/browser/view/lineAlignment.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/mergeEditor/browser/view/scrollSynchronizer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/mergeEditor/browser/view/viewModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/mergeEditor/browser/view/viewZones.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/mergeEditor/common/mergeEditor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/mergeEditor/browser/view/editors/resultCodeEditorView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/multiDiffEditor/browser/icons.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/multiDiffEditor/browser/multiDiffSourceResolverService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/contrib/find/findFilters.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/contrib/notebookVariables/notebookVariableContextKeys.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/controller/chat/notebookChatContext.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/diff/diffCellEditorOptions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/diff/eventDispatcher.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffOverviewRuler.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/notebookEditorExtensions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/notebookIcons.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/notebookLogger.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/notebookViewEvents.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/services/notebookCellStatusBarServiceImpl.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/services/notebookEditorService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/services/notebookLoggingServiceImpl.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/view/cellPart.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellActionView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellDecorations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellDragRenderer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellFocus.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellToolbarStickyScroll.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellToolbars.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/view/cellParts/chat/cellChatPart.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/view/cellParts/collapsedCellInput.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/view/notebookCellListView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewThemeMapping.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/viewModel/cellEditorOptions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/viewModel/cellSelectionCollection.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/viewModel/viewContext.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/viewParts/notebookTopCellToolbar.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/viewParts/notebookViewZones.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/common/model/cellEdit.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/common/notebookCellStatusBarService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/common/notebookEditorModelResolverService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/common/notebookExecutionService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadNotebookDto.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/common/notebookExecutionStateService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellExecution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/common/notebookKernelService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/contrib/notebookVariables/notebookVariablesDataSource.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/common/notebookKeymapService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/common/notebookLoggingService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/services/notebookKernelHistoryServiceImpl.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/common/notebookOutputRenderer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/common/notebookPerformance.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/common/notebookRange.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/contrib/cellStatusBar/notebookVisibleCellObserver.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/contrib/cellStatusBar/contributedStatusBarItemController.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/common/notebookRendererMessagingService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/common/notebookService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/contrib/notebookVariables/notebookVariableCommands.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/services/notebookKernelServiceImpl.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/common/services/notebookWorkerService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/outline/browser/outline.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/outline/browser/outlineViewState.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/preferences/browser/preferencesIcons.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/preferences/browser/settingsLayout.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/preferences/common/preferences.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/preferences/browser/settingsSearchMenu.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/preferences/common/settingsEditorColorRegistry.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/preferences/browser/settingsWidgets.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/preferences/common/smartSnippetInserter.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/remote/browser/remoteIcons.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/remote/browser/urlFinder.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/sash/browser/sash.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/scm/browser/dirtyDiffSwitcher.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/scm/browser/util.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/scm/common/quickDiff.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/scm/common/quickDiffService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/scm/common/scm.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/scm/browser/menus.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/scm/browser/scmRepositoryRenderer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/scm/browser/scmViewService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/scm/common/scmService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/search/browser/patternInputWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/search/browser/replace.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/search/browser/searchActionsSymbol.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/search/browser/searchIcons.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/search/common/cacheState.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/search/common/cellSearchModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/search/common/constants.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/search/common/notebookSearch.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/search/common/searchHistoryService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/searchEditor/browser/constants.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/share/browser/shareService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/share/common/share.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/snippets/browser/commands/abstractSnippetsActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/snippets/browser/snippets.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/snippets/browser/snippetPicker.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/snippets/browser/commands/surroundWithSnippet.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/snippets/browser/snippetsFile.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/snippets/browser/commands/insertSnippet.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/snippets/browser/snippetCompletionProvider.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/speech/common/speechService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/common/voiceChat.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/codeEditor/browser/dictation/editorDictation.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/splash/browser/splash.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/tags/common/workspaceTags.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/tags/browser/workspaceTagsService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/tasks/common/taskService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/tasks/common/taskSystem.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/tasks/common/taskTemplates.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/baseTerminalBackend.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/terminal.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/terminalCommands.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/terminalContextMenu.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/terminalEditorSerializer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/terminalEscapeSequences.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/terminalEvents.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/terminalExtensions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/terminalIcons.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/terminalProcessExtHostProxy.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/terminalStatusList.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/terminalTooltip.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/terminalUri.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/widgets/terminalHoverWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/widgets/widgetManager.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/detachedTerminal.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/xterm/decorationStyles.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/xterm/lineDataEventAddon.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/common/basePty.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/common/environmentVariable.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/common/terminal.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/common/terminalClipboard.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/common/terminalColorRegistry.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/debugANSIHandling.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/terminalIcon.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/terminalProfileQuickpick.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/xterm/markNavigationAddon.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/common/terminalContextKey.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/common/terminalStrings.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/accessibility/browser/bufferContentTracker.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminalAccessibleBufferProvider.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/accessibility/browser/textAreaSyncAddon.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/find/browser/textInputContextMenu.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/find/browser/terminalFindWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/highlight/browser/terminal.highlight.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/links/browser/links.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/links/browser/terminalLinkHelpers.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/links/browser/terminalExternalLinkDetector.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/links/browser/terminalLink.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/links/browser/terminalLinkDetectorAdapter.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/links/browser/terminalLinkParsing.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/links/browser/terminalLinkProviderService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/links/browser/terminalLinkResolver.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/links/browser/terminalLocalLinkDetector.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/links/browser/terminalMultiLineLinkDetector.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/links/browser/terminalUriLinkDetector.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/links/browser/terminalWordLinkDetector.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/quickFix/browser/quickFix.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/quickFix/browser/terminalQuickFixBuiltinActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/stickyScroll/browser/terminalStickyScrollColorRegistry.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/stickyScroll/browser/terminalStickyScrollOverlay.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/typeAhead/browser/terminalTypeAheadAddon.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/typeAhead/browser/terminal.typeAhead.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/browser/explorerProjections/display.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/browser/theme.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/browser/icons.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/common/configuration.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/common/constants.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/common/observableValue.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/common/storedValue.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/common/testExclusions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/common/testId.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/browser/explorerProjections/testingViewState.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/common/testService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/common/testTypes.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/browser/explorerProjections/index.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/browser/explorerProjections/testingObjectTree.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/common/mainThreadTestCollection.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/common/testCoverage.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/common/testExplorerFilterState.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/common/testItemCollection.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/common/extHostTestingPrivateApi.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/common/testingContextKeys.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/common/testProfileService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/browser/explorerProjections/testItemContextOverlay.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/browser/testingConfigurationUi.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/common/testingContinuousRunService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/common/testingDecorations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/common/testingPeekOpener.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/common/testingStates.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/common/getComputedState.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/common/testResult.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/common/testResultStorage.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/common/testResultService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/browser/explorerProjections/listProjection.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/browser/explorerProjections/treeProjection.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/common/testingUri.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/browser/testingDecorations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/common/testingContentProvider.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/timeline/common/timeline.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/typeHierarchy/common/typeHierarchy.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/typeHierarchy/browser/typeHierarchyTree.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/update/common/update.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/url/common/urlGlob.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/webview/browser/resourceLoading.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/webview/browser/webview.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/webview/browser/overlayWebview.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/webview/browser/webviewFindWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/webview/browser/webviewWindowDragMonitor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/webview/common/webview.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/webviewPanel/browser/webviewEditorInput.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/webviewView/browser/webviewViewService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/webviewView/browser/webviewView.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/welcomeDialog/browser/welcomeWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStartedColors.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStartedIcons.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStartedInput.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStartedList.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/welcomeGettingStarted/common/media/notebookProfile.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/welcomeViews/common/viewsWelcomeExtensionPoint.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/welcomeWalkthrough/common/walkThroughContentProvider.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/welcomeWalkthrough/browser/walkThroughInput.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/welcomeWalkthrough/common/walkThroughUtils.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/workspace/common/workspace.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/activity/common/activity.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/activity/browser/activityService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/aiEmbeddingVector/common/aiEmbeddingVectorService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/aiRelatedInformation/common/aiRelatedInformation.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/aiRelatedInformation/common/aiRelatedInformationService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/authentication/common/authentication.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/banner/browser/bannerService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/configuration/common/configuration.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/preferences/browser/settingsEditorSettingIndicators.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/configuration/common/configurationCache.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/configuration/common/configurationModels.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/configuration/browser/configuration.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/configuration/common/jsonEditing.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/configurationResolver/common/configurationResolver.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/configurationResolver/common/configurationResolverSchema.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/configurationResolver/common/configurationResolverUtils.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/configurationResolver/common/variableResolver.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/configurationResolver/browser/baseConfigurationResolverService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/decorations/common/decorations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/decorations/browser/decorationsService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/editor/common/editorGroupsService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/titlebar/commandCenterControl.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/editor/common/editorPaneService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/editor/common/editorService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/codeeditor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/editor/editorQuickAccess.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/editor/editorWithViewState.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/common/editor/sideBySideEditorInput.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/editor/editorsObserver.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/common/editor/editorGroupModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/accessibilitySignals/browser/accessibilitySignalLineFeatureContribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/callHierarchy/browser/callHierarchyPeek.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/callHierarchy/browser/callHierarchy.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/browser/actions/chatClear.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/codeEditor/browser/inspectKeybindings.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/codeEditor/browser/quickaccess/gotoLineQuickAccess.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/common/debugSource.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/common/debugContentProvider.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/common/loadedScriptsPicker.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/multiDiffEditor/browser/scmMultiDiffSourceResolver.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/performance/browser/inputLatencyContrib.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/search/common/search.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/search/browser/symbolsQuickAccess.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/snippets/browser/commands/fileTemplateSnippets.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/snippets/browser/snippetCodeActionProvider.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/terminalMenus.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/terminalQuickAccess.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/common/remote/remoteTerminalChannel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/common/testServiceImpl.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/typeHierarchy/browser/typeHierarchyPeek.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/typeHierarchy/browser/typeHierarchy.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/webview/browser/webview.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/editor/browser/codeEditorService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/editor/common/editorGroupColumn.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/editor/common/editorGroupFinder.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/encryption/browser/encryptionService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/environment/browser/environmentService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/url/browser/externalUriResolver.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/environment/common/environmentService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/common/debugger.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/logs/common/defaultLogLevels.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/preferences/browser/keybindingWidgets.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/webview/browser/webviewElement.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/welcomeWalkthrough/browser/editor/vs_code_editor_walkthrough.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/welcomeWalkthrough/browser/editor/editorWalkThrough.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/clipboard/browser/clipboardService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/dialogs/common/dialogService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensionManagement/browser/builtinExtensionsScannerService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensionManagement/common/extensionFeatures.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensionManagement/common/extensionManagement.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/browser/unsupportedExtensionsMigrationContribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/browser/webRecommendations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/remote/browser/remoteStartEntry.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensionManagement/common/extensionManagementChannelClient.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensionRecommendations/common/extensionRecommendations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensionRecommendations/common/workspaceExtensionsConfig.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/browser/workspaceRecommendations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensionRecommendations/common/extensionIgnoredRecommendationsService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensions/browser/webWorkerFileSystemProvider.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensions/common/extHostCustomers.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensions/common/extensionDescriptionRegistry.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensions/common/extensionDevOptions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensions/common/extensionHostKind.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensions/common/extensionHostProtocol.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensions/common/extensionRunningLocation.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensions/common/extensionStorageMigration.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensions/common/extensions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/common/chatSlashCommands.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/common/chatRequestParser.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/codeEditor/browser/languageConfigurationExtensionPoint.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/browser/abstractRuntimeExtensionsEditor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/browser/extensionFeaturesTab.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/browser/extensionsActivationProgress.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/services/notebookRendererMessagingServiceImpl.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/environmentVariableInfo.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/common/environmentVariableService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/common/environmentVariable.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/quickFix/browser/quickFixAddon.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStartedDetailsRenderer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/welcomeViews/common/viewsWelcomeContribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/welcomeWalkthrough/browser/walkThroughPart.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/welcomeWalkthrough/browser/walkThroughActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/commands/common/commandService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensionManagement/common/extensionFeaturesManagemetService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensions/common/extensionsProposedApi.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensions/common/extensionsRegistry.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/common/configurationExtensionPoint.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/common/jsonValidationExtensionPoint.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/common/debugSchemas.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/tasks/common/problemMatcher.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/tasks/common/jsonSchemaCommon.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/tasks/common/jsonSchema_v1.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/tasks/common/problemCollectors.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/tasks/browser/taskTerminalStatus.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/tasks/common/taskDefinitionRegistry.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/tasks/common/jsonSchema_v2.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/tasks/common/tasks.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/tasks/browser/runAutomaticTasks.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/tasks/browser/taskQuickPick.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/tasks/browser/tasksQuickAccess.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/common/terminalExtensionPoints.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/common/terminalExtensionPoints.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/quickFix/browser/terminalQuickFixService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStartedExtensionPoint.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/actions/common/menusExtensionPoint.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/authentication/browser/authenticationService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/editSessions/browser/editSessionsStorageService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensions/common/extensionsUtil.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensions/common/lazyPromise.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensions/common/proxyIdentifier.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/common/extHost.protocol.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadAiEmbeddingVector.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadAiRelatedInformation.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadAuthentication.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadChat.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadChatProvider.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadChatVariables.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadClipboard.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadCommands.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadConfiguration.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadDecorations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadDiagnostics.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadDialogs.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadDocumentContentProviders.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadDownloadService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadEditSessionIdentityParticipant.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadEditor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadErrors.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadFileSystem.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadInteractive.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadLabelService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadLocalization.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadLogService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadManagedSockets.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadMessageService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadNotebook.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadNotebookKernels.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadNotebookRenderers.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadProgress.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadQuickDiff.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadQuickOpen.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadRemoteConnectionData.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadSCM.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadSecretState.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadShare.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadSpeech.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadStorage.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadTask.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadTelemetry.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadTesting.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadTheming.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadTimeline.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadWebviews.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadCodeInsets.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadWebviewViews.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensions/common/remoteConsoleUtil.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadConsole.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensions/common/remoteExtensionHost.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensions/common/rpcProtocol.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensions/common/extensionHostManager.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensions/common/lazyCreateExtensionHostManager.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/files/common/elevatedFileService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/files/browser/elevatedFileService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/filesConfiguration/common/filesConfigurationService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/common/editor/resourceEditorInput.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/common/notebookEditorInput.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/interactive/browser/interactiveEditorInput.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/history/common/history.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/host/browser/host.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/actions/windowActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/browser/extensionEnablementWorkspaceTrustTransitionParticipant.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/browser/extensionsDependencyChecker.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/files/browser/explorerService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/files/browser/workspaceWatcher.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/speech/browser/speechService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/speech/browser/speech.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/integrity/common/integrity.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/integrity/browser/integrityService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/issue/browser/issueService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/issue/common/issue.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadIssueReporter.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/common/reportExtensionIssueAction.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/browser/browserRuntimeExtensionsEditor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/issue/common/issue.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/keybinding/browser/unboundCommands.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/keybinding/common/fallbackKeyboardMapper.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/keybinding/common/keybindingIO.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/keybinding/common/keymapInfo.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/keybinding/common/macLinuxKeyboardMapper.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/keybinding/common/windowsKeyboardMapper.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/keybinding/browser/keyboardLayoutService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/language/common/languageService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/codeActions/common/codeActionsExtensionPoint.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/codeActions/common/documentationExtensionPoint.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/customEditor/common/extensionPoint.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/languageDetection/common/languageDetectionWorkerService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/common/editor/textEditorModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/common/editor/diffEditorInput.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/common/editor/textResourceEditorModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/common/notebookDiffEditorInput.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/languageDetection/browser/languageDetectionWorkerServiceImpl.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/languageStatus/common/languageStatusService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadLanguages.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/layout/browser/layoutService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/banner/bannerPart.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/comments/browser/commentService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/webviewPanel/browser/webviewEditor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/webviewPanel/browser/webviewCommands.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/lifecycle/common/lifecycle.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/common/contributions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/actions/textInputActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/actions/widgetNavigationCommands.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/dialogs/dialog.web.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/bracketPairColorizer2Telemetry/browser/bracketPairColorizer2Telemetry.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/browser/contrib/chatHistoryVariables.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/codeActions/browser/codeActions.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/codeEditor/browser/editorFeatures.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/codeEditor/browser/toggleMultiCursorModifier.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/contextmenu/browser/contextmenu.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/debugAdapterManager.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/common/debugLifecycle.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/deprecatedExtensionMigrator/browser/deprecatedExtensionMigrator.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/common/extensionsUtils.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/folding/browser/folding.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/issue/browser/issue.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/limitIndicator/browser/limitIndicator.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/list/browser/list.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/logs/common/logsDataCleaner.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/markers/browser/markersFileDecorations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/contrib/kernelDetection/notebookKernelDetection.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/services/notebookKeymapServiceImpl.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/remote/browser/remoteStartEntry.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/splash/browser/partsSplash.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/splash/browser/splash.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/surveys/browser/nps.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/terminalEditorInput.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/webviewPanel/browser/webviewIconManager.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/webviewPanel/browser/webviewWorkbenchService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadWebviewPanels.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/webviewPanel/browser/webviewEditorInputSerializer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/welcomeBanner/browser/welcomeBanner.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/welcomeViews/common/newFile.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/welcomeViews/common/viewsWelcome.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/driver/browser/driver.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/window.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/auxiliaryWindow/browser/auxiliaryWindowService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensionManagement/browser/extensionBisect.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadUrls.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/lifecycle/common/lifecycleService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/lifecycle/browser/lifecycleService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/localization/common/locale.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/localization/common/localizationsActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/localization/common/localization.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/localization/browser/localization.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/localization/browser/localeService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/log/common/logConstants.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/keybindings/browser/keybindings.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/notebook/common/notebookDocumentService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/common/notebookCommon.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/common/extHostTypes.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/common/extHostTunnelService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/common/extHostTypeConverters.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/browser/fileBasedRecommendations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/contrib/clipboard/cellOutputClipboard.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/contrib/debug/notebookCellPausing.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/contrib/find/notebookFindReplaceWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/contrib/profile/notebookProfile.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/controller/apiActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/controller/notebookIndentationActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadNotebookEditors.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/bulkEdit/browser/bulkCellEdits.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadBulkEdits.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/bulkEdit/browser/conflicts.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditPreview.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditTree.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/contrib/cellStatusBar/statusBarProviders.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/contrib/debug/notebookBreakpoints.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/contrib/find/findMatchDecorationModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/contrib/find/findModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/contrib/marker/markerProvider.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/contrib/troubleshoot/layout.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/contrib/undoRedo/notebookUndoRedo.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/notebookExtensionPoint.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/notebookOptions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/services/notebookExecutionStateServiceImpl.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/services/notebookWorkerServiceImpl.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellFocusIndicator.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellProgressBar.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/view/cellParts/codeCellExecutionIcon.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/view/cellParts/collapsedCellOutput.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/view/notebookCellAnchor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/viewModel/OutlineEntry.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/viewModel/baseCellViewModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/viewModel/cellOutputViewModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/contrib/viewportWarmup/viewportWarmup.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellStatusPart.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/viewModel/foldingModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/viewModel/markupCellViewModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/viewModel/notebookOutlineEntryFactory.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/viewModel/notebookOutlineProvider.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/viewModel/notebookViewModelImpl.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/viewParts/notebookOverviewRuler.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/common/model/notebookCellOutputTextModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/common/model/notebookCellTextModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/controller/cellOperations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellDnd.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/common/notebookContextKeys.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/contrib/find/notebookFindWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/contrib/find/notebookFind.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/contrib/gettingStarted/notebookGettingStarted.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/controller/coreActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/contrib/cellCommands/cellCommands.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/contrib/clipboard/notebookClipboard.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/contrib/format/formatting.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/contrib/layout/layoutActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/controller/cellOutputActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/controller/foldingController.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/controller/insertCellActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellContextKeys.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellEditorOptions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/view/cellParts/codeCellRunToolbar.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/view/cellParts/foldedCellHint.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/view/cellParts/markupCell.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorStickyScroll.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorWidgetContextKeys.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/common/notebookProvider.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/search/browser/searchFindInput.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/notification/common/notificationService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/outline/browser/outline.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/editor/breadcrumbsModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsOutline.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/outline/browser/outlineService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/output/common/delayedLogChannel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/output/common/output.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/logs/common/logsActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/logs/browser/logs.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/logs/common/logs.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/output/browser/outputLinkProvider.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/output/common/outputChannelModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/output/common/outputChannelModelService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/panecomposite/browser/panecomposite.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/actions/navigationActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/sidebar/sidebarActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/browser/extensionsQuickAccess.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/format/browser/formatActionsNone.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/viewParts/notebookKernelQuickPickStrategy.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/services/notebookExecutionServiceImpl.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/viewParts/notebookKernelView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/preferences/browser/keybindingsEditorModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/preferences/browser/keybindingsEditorInput.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/preferences/common/preferences.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/titlebar/menubarControl.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/accessibilitySignals/browser/commands.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/accessibilitySignals/browser/accessibilitySignal.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/controller/layoutActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/preferences/browser/preferencesActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/preferences/common/preferencesEditorInput.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/preferences/common/preferencesValidation.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/preferences/common/preferencesModels.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/preferences/browser/preferencesSearch.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/progress/browser/progressIndicator.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/compositePart.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/quickinput/browser/quickInputService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/remote/browser/browserRemoteResourceHandler.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/remote/common/remoteAgentEnvironmentChannel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/remote/common/remoteAgentService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadTerminalService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/common/configuration.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/accessibility/browser/accessibilityConfiguration.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/accountEntitlements/browser/accountsEntitlements.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/codeEditor/browser/editorSettingsMigration.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/codeEditor/browser/quickaccess/gotoSymbolQuickAccess.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/extensionHostDebugService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/externalUriOpener/common/configuration.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/externalUriOpener/common/contributedOpeners.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/externalUriOpener/common/externalUriOpenerService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadUriOpeners.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/externalUriOpener/common/externalUriOpener.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/inlineChat/common/inlineChat.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadInlineChat.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/inlineChat/common/inlineChatServiceImpl.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/remote/browser/remoteConnectionHealth.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/remote/common/remote.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/sash/browser/sash.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/share/browser/share.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/remotePty.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/terminal.web.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/terminalVoice.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/common/history.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminalAccessibilityHelp.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/welcomeDialog/browser/welcomeDialog.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/assignment/common/assignmentService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorToolbar.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/surveys/browser/ces.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/editor/common/editorResolverService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/editor/editorConfiguration.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/customEditor/common/customEditor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/customEditor/common/contributedCustomEditors.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/editor/browser/editorResolverService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/path/common/pathService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/linkDetector.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/exceptionWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/dialogs/browser/simpleFileDialog.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/dialogs/browser/abstractFileDialogService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/dialogs/browser/fileDialogService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/label/common/labelService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/model/common/modelService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/path/browser/pathService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/remote/common/remoteFileSystemProviderClient.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/remote/common/tunnelModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/remote/common/remoteExplorerService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadTunnelService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/remote/browser/showCandidate.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/remote/browser/tunnelFactory.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/request/browser/requestService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/search/common/ignoreFile.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/search/common/replace.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/search/common/searchExtTypes.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/search/browser/searchMessage.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/search/common/search.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadSearch.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/search/common/searchNotebookHelpers.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/search/browser/notebookSearch/searchNotebookHelpers.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/history/browser/historyService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/search/common/queryBuilder.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/search/browser/notebookSearch/notebookSearchService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/search/browser/notebookSearch/notebookSearchContributions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/links/browser/terminalLinkOpeners.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/links/browser/terminalLinkManager.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensions/common/workspaceContains.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/search/common/searchHelpers.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/search/common/searchService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/search/browser/searchService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/secrets/browser/secretStorageService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/statusbar/browser/statusbar.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/statusBarExtensionPoint.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadStatusBar.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/notifications/notificationsStatus.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/statusbar/statusbarActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/statusbar/statusbarItem.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/statusbar/statusbarModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/accessibility/browser/accessibilityStatus.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/debugStatus.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/statusbarColorProvider.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/languageDetection/browser/languageDetection.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/languageStatus/browser/languageStatus.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/preferences/browser/keyboardLayoutPicker.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/remote/browser/remoteIndicator.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/remoteTerminalBackend.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/storage/browser/storageService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/suggest/browser/simpleCompletionItem.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/suggest/browser/simpleCompletionModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/suggest/browser/simpleSuggestWidgetRenderer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/suggest/browser/simpleSuggestWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalSuggestAddon.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/telemetry/browser/workbenchCommonProperties.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/telemetry/browser/telemetryService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/terminal/common/embedderTerminalService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/terminalMainContribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/textMate/browser/arrayOperation.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/textMate/browser/backgroundTokenization/textMateWorkerTokenizerController.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/textMate/browser/backgroundTokenization/threadedBackgroundTokenizerFactory.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/textMate/browser/textMateTokenizationFeature.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/textMate/browser/tokenizationSupport/textMateTokenizationSupport.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/textMate/browser/tokenizationSupport/tokenizationSupportWithLineLimit.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/textMate/common/TMGrammars.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/emmet/browser/emmetActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/emmet/browser/actions/expandAbbreviation.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/emmet/browser/emmet.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/textMate/common/TMHelper.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/textMate/common/TMScopeRegistry.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/textMate/common/TMGrammarFactory.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/textfile/common/encoding.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/textfile/common/textFileSaveParticipant.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/textfile/common/textfiles.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/labels.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/common/editor/textResourceEditorInput.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/customEditor/common/customTextEditorModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/common/debugModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/disassemblyView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/common/debugStorage.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/common/debugVisualizers.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadDebugService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/common/replModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/baseDebugView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/debugSession.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/replFilter.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/replViewer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/files/common/files.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/files/browser/editors/fileEditorInput.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/files/browser/editors/textFileSaveErrorHandler.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/files/browser/files.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/externalTerminal/browser/externalTerminal.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/inlineChat/browser/inlineChatLivePreviewWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/inlineChat/browser/inlineChatSession.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInputModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInput.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorSerializer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/multiDiffEditor/browser/multiDiffEditorInput.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/multiDiffEditor/browser/multiDiffEditor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/contrib/notebookVariables/notebookVariablesTree.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/format/browser/formatModified.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/codeEditor/browser/saveParticipants.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/format/browser/format.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/surveys/browser/languageSurveys.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/terminalTabbedView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/url/browser/trustedDomains.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/url/browser/trustedDomainsFileSystemProvider.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/url/browser/trustedDomainsValidator.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/url/browser/url.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/workspaces/browser/workspaces.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/configuration/common/jsonEditingService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/textresourceProperties/common/textResourcePropertiesService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/themes/common/colorExtensionPoint.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/themes/common/colorThemeSchema.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/themes/common/hostColorSchemeService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/themes/browser/browserHostColorSchemeService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/themes/common/iconExtensionPoint.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/themes/common/plistParser.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/themes/common/productIconThemeSchema.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/themes/common/fileIconThemeSchema.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/themes/common/textMateScopeMatcher.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/themes/common/themeCompatibility.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/themes/common/tokenClassificationExtensionPoint.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/themes/common/workbenchThemeService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/codeEditor/browser/inspectEditorTokens/inspectEditorTokens.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/webview/browser/themeing.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/webview/browser/webviewService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/webview/browser/webview.web.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/welcomeGettingStarted/common/media/theme_picker.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/welcomeGettingStarted/common/gettingStartedContent.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/textMate/browser/textMateTokenizationFeatureImpl.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/textMate/browser/textMateTokenizationFeature.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/themes/browser/fileIconThemeData.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/themes/browser/productIconThemeData.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/themes/browser/themes.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/themes/common/colorThemeData.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/themes/common/themeConfiguration.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/themes/common/themeExtensionPoints.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/timer/browser/timerService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadExtensionService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/performance/browser/perfviewEditor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/performance/browser/performance.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/performance/browser/startupTimings.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/performance/browser/performance.web.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/title/browser/titleService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/debugTitle.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/scm/browser/activity.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/tunnel/browser/tunnelService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/untitled/common/untitledTextEditorInput.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/inlineChat/browser/inlineChatSessionServiceImpl.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/update/browser/updateService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/url/browser/urlService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/userActivity/browser/domActivityTracker.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/userActivity/common/userActivityRegistry.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/userActivity/browser/userActivityBrowser.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/userActivity/common/userActivityService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadWindow.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/contrib/execute/executionEditorProgress.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/userData/browser/userDataInit.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/browser/extensionRecommendationsService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/themes/browser/workbenchThemeService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/userDataProfile/browser/iconSelectBox.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/userDataProfile/common/userDataProfile.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadProfilContentHandlers.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/preferences/browser/keybindingsEditorContribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/preferences/browser/preferencesRenderers.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/markdown/browser/markdownSettingRenderer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/preferences/browser/settingsTree.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/preferences/browser/tocTree.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/snippets/browser/commands/configureSnippets.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/snippets/browser/snippetsService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/snippets/browser/tabCompletion.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/codeEditor/browser/simpleEditorOptions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/accessibility/browser/accessibleViewActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/accessibility/browser/accessibilityContributions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/browser/codeBlockPart.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/comments/browser/simpleCommentEditor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/comments/browser/commentNode.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/comments/browser/commentReply.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/comments/browser/commentThreadBody.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/comments/browser/commentThreadZoneWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/comments/browser/commentsAccessibility.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/accessibility/browser/editorAccessibilityHelp.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/codeEditor/browser/diffEditorHelper.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/breakpointWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffList.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/notebookAccessibility.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellComments.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/snippets/browser/snippets.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/telemetry/browser/telemetry.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/terminalRunRecentQuickPick.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/links/browser/terminalLinkQuickpick.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/browser/testingExplorerFilter.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/update/browser/releaseNotesEditor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/userDataProfile/browser/userDataProfileActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/userDataProfile/browser/userDataProfilePreview.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/configuration/common/configurationEditing.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/configuration/browser/configurationService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/issue/browser/issueTroubleshoot.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/keybinding/browser/keybindingService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/keybinding/common/keybindingEditing.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/remote/common/abstractRemoteAgentService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/remote/browser/remoteAgentService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/userDataProfile/browser/extensionsResource.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/userDataProfile/browser/userDataProfileManagement.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/userDataProfile/browser/userDataProfileStorageService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/userDataProfile/common/remoteUserDataProfiles.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensionManagement/common/remoteExtensionManagementService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/remote/common/remoteExtensionsScanner.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/userDataProfile/common/userDataProfileIcons.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/userDataProfile/common/userDataProfileService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/userDataSync/browser/userDataSyncEnablementService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/userDataSync/browser/webUserDataSyncEnablementService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/userDataSync/common/userDataSync.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/update/browser/update.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/update/browser/update.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/userDataSync/browser/userDataSyncInit.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/userDataSync/common/userDataSyncUtil.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/views/common/treeViewsService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/views/browser/treeViewsService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/views/common/viewContainerModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/views/common/viewsService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadOutputService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadTreeViews.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/panel/panelActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/actions/layoutActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/titlebar/windowTitle.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/views/viewPane.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/workbench.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditPane.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/comments/browser/commentsController.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/comments/browser/commentsViewActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/comments/browser/commentsView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/comments/browser/comments.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/breakpointsView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/debugEditorActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/debugProgress.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/debugSessionPicker.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/debugCommands.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/debugActionViewItems.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/debugConsoleQuickAccess.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/debugQuickAccess.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/debugTaskRunner.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/debugService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/debugToolBar.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/callStackView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/loadedScriptsView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/repl.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/variablesView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/debugHover.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/watchExpressionsView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/contrib/notebookVariables/notebookVariablesView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/contrib/notebookVariables/notebookVariables.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/outline/browser/outlineActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/outline/browser/outlinePane.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/output/browser/outputServices.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/quickaccess/browser/viewQuickAccess.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/remote/browser/tunnelView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/scm/browser/scmRepositoriesViewPane.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/tasks/browser/task.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/tasks/browser/taskService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/browser/testingProgressUiService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/common/testCoverageService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/browser/codeCoverageDecorations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/browser/testCoverageBars.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/browser/testCoverageView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/timeline/common/timelineService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/userDataSync/browser/userDataSyncTrigger.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/webviewView/browser/webviewViewPane.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStartedService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/progress/browser/progressService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/userDataSync/browser/userDataSyncWorkbenchService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/workingCopy/common/resourceWorkingCopy.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/workingCopy/common/storedFileWorkingCopySaveParticipant.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/workingCopy/common/workingCopy.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/workingCopy/common/workingCopyBackup.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/welcomeGettingStarted/browser/startupPage.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/workingCopy/common/abstractFileWorkingCopyManager.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/workingCopy/common/workingCopyBackupService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/workingCopy/common/workingCopyBackupTracker.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/workingCopy/common/workingCopyEditorService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/files/browser/editors/textFileEditorTracker.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/workingCopy/common/workingCopyFileOperationParticipant.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/workingCopy/common/workingCopyHistory.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/workingCopy/common/workingCopyService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadEditors.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/actions/developerActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/contextkeys.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/editor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/editor/editorAutoSave.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/editor/editorPlaceholder.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/editor/binaryEditor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/editor/binaryDiffEditor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/editor/editorPanes.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/editor/editorStatus.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/editor/textEditor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/editor/textCodeEditor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/editor/textDiffEditor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/editor/textResourceEditor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/accessibility/browser/saveAudioCue.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/accessibility/browser/accessibility.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/codeEditor/browser/emptyTextEditorHint/emptyTextEditorHint.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/codeEditor/browser/codeEditor.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/browser/extensions.web.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/files/browser/editors/binaryFileEditor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/files/common/dirtyFilesIndicator.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/mergeEditor/browser/commands/commands.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/mergeEditor/browser/commands/devCommands.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/multiDiffEditor/browser/actions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/multiDiffEditor/browser/multiDiffEditor.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/contrib/editorHint/emptyCellEditorHint.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/output/browser/outputView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/webviewPanel/browser/webviewPanel.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/welcomeWalkthrough/browser/walkThrough.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/editor/browser/editorPaneService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/textfile/common/textFileEditorModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/untitled/common/untitledTextEditorModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/untitled/common/untitledTextEditorService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/editor/editorCommands.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/editor/editorActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadEditorTabs.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/customEditor/browser/customEditorInputFactory.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/customEditor/browser/customEditors.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/customEditor/browser/customEditor.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/localHistory/browser/localHistoryCommands.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/localHistory/browser/localHistoryTimeline.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/localHistory/browser/localHistory.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/timeline/browser/timelinePane.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/textfile/common/textEditorService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/files/browser/editors/fileEditorHandler.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/preferences/common/preferencesContribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/editor/browser/editorService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/preferences/browser/preferencesService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/untitled/common/untitledTextEditorHandler.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/editor/editor.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/userDataProfile/browser/globalStateResource.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/userDataProfile/browser/keybindingsResource.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/userDataProfile/browser/settingsResource.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/userDataProfile/browser/snippetsResource.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/userDataProfile/browser/tasksResource.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/userDataProfile/browser/userDataProfileInit.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/workingCopy/browser/workingCopyBackupTracker.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/workingCopy/browser/workingCopyBackupService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/workingCopy/common/untitledFileWorkingCopy.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/workingCopy/common/untitledFileWorkingCopyManager.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/workingCopy/common/workingCopyFileService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadCustomEditors.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadDocuments.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadDocumentsAndEditors.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadFileSystemEventService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadNotebookDocuments.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadNotebookDocumentsAndEditors.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadNotebookSaveParticipant.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadWebviewManager.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/bulkEdit/browser/bulkFileEdits.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/bulkEdit/browser/bulkEditService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/contrib/saveParticipants/saveParticipants.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/textfile/browser/textFileService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/textfile/browser/browserTextFileService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/workingCopy/common/storedFileWorkingCopy.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/workingCopy/common/storedFileWorkingCopyManager.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/workingCopy/common/fileWorkingCopyManager.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/common/notebookEditorModelResolverServiceImpl.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/workingCopy/common/workingCopyHistoryTracker.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/workingCopy/common/workingCopyHistoryService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/workingCopy/browser/workingCopyHistoryService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/workspaces/browser/abstractWorkspaceEditingService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/workspaces/browser/workspaceTrustEditorInput.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/workspaces/browser/workspaces.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/workspaces/browser/workspacesService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/workspaces/common/canonicalUriService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/workspaces/common/editSessionIdentityService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/workspaces/common/workspaceEditing.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadWorkspace.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/actions/workspaceCommands.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/actions/workspaceActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/dnd.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/compositeBarActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/compositeBar.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/editor/editorDropTarget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/editor/editorTabsControl.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/editor/multiEditorTabsControl.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/editor/multiRowEditorTabsControl.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/editor/noEditorTabsControl.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/editor/singleEditorTabsControl.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/editor/editorTitleControl.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/editor/editorGroupView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/editor/editorPart.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/editor/auxiliaryEditorPart.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/editor/editorParts.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/globalCompositeBar.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/paneCompositeBar.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/views/treeView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/views/viewPaneContainer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadComments.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/panecomposite.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/paneCompositePart.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarPart.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/panel/panelPart.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/layout.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/paneCompositePartService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/parts/views/viewsViewlet.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/workbench.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEdit.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/welcomeView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/debugViewlet.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/debug/browser/debug.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/editSessions/browser/editSessionsViews.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/files/browser/fileImportExport.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/files/browser/fileActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/files/browser/views/emptyView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/files/browser/views/explorerDecorationsProvider.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/files/browser/views/explorerView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/files/browser/explorerViewlet.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/files/browser/fileCommands.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/files/browser/files.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/browser/actions/chatAccessibilityHelp.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/browser/actions/chatActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/browser/actions/chatClearActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/browser/actions/chatCopyActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/browser/actions/chatExecuteActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/browser/actions/chatFileTreeActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/browser/actions/chatImportExport.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/browser/actions/chatMoveActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/browser/actions/chatQuickInputActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/browser/actions/chatTitleActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/browser/chatInputPart.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/browser/chatWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/browser/chatEditor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/browser/chatQuick.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/browser/chatViewPane.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/browser/chatContributionServiceImpl.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/browser/contrib/chatDynamicVariables.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadChatAgents2.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/browser/chatVariables.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/chat/browser/chat.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/inlineChat/browser/inlineChatAccessibleView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/inlineChat/browser/inlineChatActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/inlineChat/browser/inlineChatNotebook.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/inlineChat/browser/inlineChatSavingServiceImpl.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/inlineChat/browser/inlineChat.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/markers/browser/markersView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/markers/browser/markers.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/contrib/navigation/arrow.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/controller/chat/notebookChatController.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/controller/chat/cellChatActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/controller/chat/notebook.chat.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/controller/editActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/contrib/editorStatusBar/editorStatusBar.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/controller/executeActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellOutput.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/view/cellParts/codeCell.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/contrib/cellStatusBar/executionStatusBarItemController.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/interactive/browser/interactiveEditor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/contrib/debug/notebookDebugDecorations.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/services/notebookEditorServiceImpl.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/outline/browser/outline.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/output/browser/output.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/quickaccess/browser/commandsQuickAccess.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/quickaccess/browser/quickAccess.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/viewsExtensionPoint.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/remote/browser/explorerViewItems.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/remote/browser/remote.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/remote/browser/remote.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/scm/browser/scmViewPane.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/scm/browser/scmViewPaneContainer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/scm/browser/scm.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/search/browser/anythingQuickAccess.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/search/browser/searchModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/search/browser/replaceService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/search/browser/replaceContributions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/search/browser/searchActionsBase.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/search/browser/searchActionsCopy.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/search/browser/searchActionsFind.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/search/browser/searchActionsRemoveReplace.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/search/browser/searchActionsTopBar.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/search/browser/searchResultsView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/search/browser/searchWidget.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/searchEditor/browser/searchEditorSerialization.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/searchEditor/browser/searchEditor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/searchEditor/browser/searchEditorModel.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/searchEditor/browser/searchEditorInput.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/search/browser/searchActionsNav.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/searchEditor/browser/searchEditorActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/searchEditor/browser/searchEditor.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/terminalActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/terminalProfileService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/terminalView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminal.accessibility.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/developer/browser/terminal.developer.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/environmentChanges/browser/terminal.environmentChanges.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/find/browser/terminal.find.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/links/browser/terminal.links.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/quickFix/browser/terminal.quickFix.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/stickyScroll/browser/terminalStickyScrollContribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/stickyScroll/browser/terminal.stickyScroll.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminal.suggest.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminalContrib/zoom/browser/terminal.zoom.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/browser/testingViewPaneContainer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/testing/browser/testing.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/timeline/browser/timeline.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/userDataSync/browser/userDataSyncConflictsView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/userDataSync/browser/userDataSyncViews.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/userDataSync/browser/userDataSync.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/host/browser/browserHostService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/userDataProfile/browser/userDataProfileImportExportService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/views/browser/viewDescriptorService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/views/browser/viewsService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/terminalGroup.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/workspaces/browser/workspaceEditingService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/workspaces/common/workspaceIdentityService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/editSessions/common/workspaceStateSync.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/workspaces/common/workspaceTrust.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/web.main.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/browser/web.factory.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensions/common/extensionManifestPropertiesService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/mainThreadCLICommands.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/api/browser/extensionHost.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/browser/deprecatedExtensionsChecker.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/browser/extensionRecommendationNotificationService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/browser/extensionsWidgets.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/browser/extensionsList.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/browser/extensionsViewer.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/services/notebookServiceImpl.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/search/browser/searchView.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/search/browser/quickTextSearch/textSearchQuickAccess.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/search/browser/searchActionsTextQuickAccess.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/search/browser/search.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/terminalInstanceService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/terminalService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/terminal/terminal.all.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensionManagement/common/extensionManagementServerService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensions/common/extensionRunningLocationTracker.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensions/common/abstractExtensionService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/services/extensions/browser/extensionService.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/workbench.common.main.ts","out-vscode-web/vs/workbench/file:/mnt/vss/_work/1/s/src/vs/workbench/workbench.web.main.ts"],"sourcesContent":["}).call(this);","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\n// https://wicg.github.io/webusb/\n\nexport interface UsbDeviceData {\n\treadonly deviceClass: number;\n\treadonly deviceProtocol: number;\n\treadonly deviceSubclass: number;\n\treadonly deviceVersionMajor: number;\n\treadonly deviceVersionMinor: number;\n\treadonly deviceVersionSubminor: number;\n\treadonly manufacturerName?: string;\n\treadonly productId: number;\n\treadonly productName?: string;\n\treadonly serialNumber?: string;\n\treadonly usbVersionMajor: number;\n\treadonly usbVersionMinor: number;\n\treadonly usbVersionSubminor: number;\n\treadonly vendorId: number;\n}\n\nexport async function requestUsbDevice(options?: { filters?: unknown[] }): Promise {\n\tconst usb = (navigator as any).usb;\n\tif (!usb) {\n\t\treturn undefined;\n\t}\n\n\tconst device = await usb.requestDevice({ filters: options?.filters ?? [] });\n\tif (!device) {\n\t\treturn undefined;\n\t}\n\n\treturn {\n\t\tdeviceClass: device.deviceClass,\n\t\tdeviceProtocol: device.deviceProtocol,\n\t\tdeviceSubclass: device.deviceSubclass,\n\t\tdeviceVersionMajor: device.deviceVersionMajor,\n\t\tdeviceVersionMinor: device.deviceVersionMinor,\n\t\tdeviceVersionSubminor: device.deviceVersionSubminor,\n\t\tmanufacturerName: device.manufacturerName,\n\t\tproductId: device.productId,\n\t\tproductName: device.productName,\n\t\tserialNumber: device.serialNumber,\n\t\tusbVersionMajor: device.usbVersionMajor,\n\t\tusbVersionMinor: device.usbVersionMinor,\n\t\tusbVersionSubminor: device.usbVersionSubminor,\n\t\tvendorId: device.vendorId,\n\t};\n}\n\n// https://wicg.github.io/serial/\n\nexport interface SerialPortData {\n\treadonly usbVendorId?: number | undefined;\n\treadonly usbProductId?: number | undefined;\n}\n\nexport async function requestSerialPort(options?: { filters?: unknown[] }): Promise {\n\tconst serial = (navigator as any).serial;\n\tif (!serial) {\n\t\treturn undefined;\n\t}\n\n\tconst port = await serial.requestPort({ filters: options?.filters ?? [] });\n\tif (!port) {\n\t\treturn undefined;\n\t}\n\n\tconst info = port.getInfo();\n\treturn {\n\t\tusbVendorId: info.usbVendorId,\n\t\tusbProductId: info.usbProductId\n\t};\n}\n\n// https://wicg.github.io/webhid/\n\nexport interface HidDeviceData {\n\treadonly opened: boolean;\n\treadonly vendorId: number;\n\treadonly productId: number;\n\treadonly productName: string;\n\treadonly collections: [];\n}\n\nexport async function requestHidDevice(options?: { filters?: unknown[] }): Promise {\n\tconst hid = (navigator as any).hid;\n\tif (!hid) {\n\t\treturn undefined;\n\t}\n\n\tconst devices = await hid.requestDevice({ filters: options?.filters ?? [] });\n\tif (!devices.length) {\n\t\treturn undefined;\n\t}\n\n\tconst device = devices[0];\n\treturn {\n\t\topened: device.opened,\n\t\tvendorId: device.vendorId,\n\t\tproductId: device.productId,\n\t\tproductName: device.productName,\n\t\tcollections: device.collections\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 _paddingTop: string = '';\n\tprivate _paddingLeft: string = '';\n\tprivate _paddingBottom: string = '';\n\tprivate _paddingRight: 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 setPaddingTop(_paddingTop: number | string): void {\n\t\tconst paddingTop = numberAsPixels(_paddingTop);\n\t\tif (this._paddingTop === paddingTop) {\n\t\t\treturn;\n\t\t}\n\t\tthis._paddingTop = paddingTop;\n\t\tthis.domNode.style.paddingTop = this._paddingTop;\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 setPaddingBottom(_paddingBottom: number | string): void {\n\t\tconst paddingBottom = numberAsPixels(_paddingBottom);\n\t\tif (this._paddingBottom === paddingBottom) {\n\t\t\treturn;\n\t\t}\n\t\tthis._paddingBottom = paddingBottom;\n\t\tthis.domNode.style.paddingBottom = this._paddingBottom;\n\t}\n\n\tpublic setPaddingRight(_paddingRight: number | string): void {\n\t\tconst paddingRight = numberAsPixels(_paddingRight);\n\t\tif (this._paddingRight === paddingRight) {\n\t\t\treturn;\n\t\t}\n\t\tthis._paddingRight = paddingRight;\n\t\tthis.domNode.style.paddingRight = this._paddingRight;\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/**\n * Returns a sha-256 composed of `parentOrigin` and `salt` converted to base 32\n */\nexport async function parentOriginHash(parentOrigin: string, salt: string): Promise {\n\t// This same code is also inlined at `src/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.html`\n\tif (!crypto.subtle) {\n\t\tthrow new Error(`'crypto.subtle' is not available so webviews will not work. This is likely because the editor is not running in a secure context (https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts).`);\n\t}\n\n\tconst strData = JSON.stringify({ parentOrigin, salt });\n\tconst encoder = new TextEncoder();\n\tconst arrData = encoder.encode(strData);\n\tconst hash = await crypto.subtle.digest('sha-256', arrData);\n\treturn sha256AsBase32(hash);\n}\n\nfunction sha256AsBase32(bytes: ArrayBuffer): string {\n\tconst array = Array.from(new Uint8Array(bytes));\n\tconst hexArray = array.map(b => b.toString(16).padStart(2, '0')).join('');\n\t// sha256 has 256 bits, so we need at most ceil(lg(2^256-1)/lg(32)) = 52 chars to represent it in base 32\n\treturn BigInt(`0x${hexArray}`).toString(32).padStart(52, '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\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 { 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\nexport const ListDragOverReactions = {\n\treject(): IListDragOverReaction { return { accept: false }; },\n\taccept(): IListDragOverReaction { return { accept: true }; },\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\nexport abstract class CachedListVirtualDelegate implements IListVirtualDelegate {\n\n\tprivate cache = new WeakMap();\n\n\tgetHeight(element: T): number {\n\t\treturn this.cache.get(element) ?? this.estimateHeight(element);\n\t}\n\n\tprotected abstract estimateHeight(element: T): number;\n\tabstract getTemplateId(element: T): string;\n\n\tsetDynamicHeight(element: T, height: number): void {\n\t\tif (height > 0) {\n\t\t\tthis.cache.set(element, height);\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 { ISpliceable } from 'vs/base/common/sequence';\n\nexport interface ISpreadSpliceable {\n\tsplice(start: number, deleteCount: number, ...elements: T[]): void;\n}\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, ListDragOverEffectPosition, ListDragOverEffectType } 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\treadonly rootRef: TRef;\n\n\treadonly onDidSplice: Event>;\n\treadonly onDidChangeCollapseState: Event>;\n\treadonly onDidChangeRenderNodeCount: 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\tgetLastElementAncestor(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 ITreeNavigator {\n\tcurrent(): T | null;\n\tprevious(): T | null;\n\tfirst(): T | null;\n\tlast(): T | null;\n\tnext(): T | null;\n}\n\nexport interface IDataSource {\n\thasChildren?(element: TInput | T): boolean;\n\tgetChildren(element: TInput | T): Iterable;\n}\n\nexport interface IAsyncDataSource {\n\thasChildren(element: TInput | T): boolean;\n\tgetChildren(element: TInput | T): Iterable | Promise>;\n\tgetParent?(element: T): TInput | T;\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 const TreeDragOverReactions = {\n\tacceptBubbleUp(): ITreeDragOverReaction { return { accept: true, bubble: TreeDragOverBubble.Up }; },\n\tacceptBubbleDown(autoExpand = false): ITreeDragOverReaction { return { accept: true, bubble: TreeDragOverBubble.Down, autoExpand }; },\n\tacceptCopyBubbleUp(): ITreeDragOverReaction { return { accept: true, bubble: TreeDragOverBubble.Up, effect: { type: ListDragOverEffectType.Copy, position: ListDragOverEffectPosition.Over } }; },\n\tacceptCopyBubbleDown(autoExpand = false): ITreeDragOverReaction { return { accept: true, bubble: TreeDragOverBubble.Down, effect: { type: ListDragOverEffectType.Copy, position: ListDragOverEffectPosition.Over }, autoExpand }; }\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/**\n * @deprecated to support multi-window scenarios, use `DOM.mainWindow`\n * if you target the main global window or use helpers such as `DOM.getWindow()`\n * or `DOM.getActiveWindow()` to obtain the correct window for the context you are in.\n */\nexport const $window = mainWindow;\n\nexport function isAuxiliaryWindow(obj: Window): obj is CodeWindow {\n\tif (obj === mainWindow) {\n\t\treturn false;\n\t}\n\n\tconst candidate = obj as CodeWindow | undefined;\n\n\treturn typeof candidate?.vscodeWindowId === '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// ESM-comment-begin\nexport const isESM = false;\n// ESM-comment-end\n// ESM-uncomment-begin\n// export const isESM = true;\n// ESM-uncomment-end\n\nexport abstract class LoaderStats {\n\tabstract get amdLoad(): [string, number][];\n\tabstract get amdInvoke(): [string, number][];\n\tabstract get nodeRequire(): [string, number][];\n\tabstract get nodeEval(): [string, number][];\n\tabstract get nodeRequireTotal(): number;\n\n\tstatic get(): LoaderStats {\n\t\tconst amdLoadScript = new Map();\n\t\tconst amdInvokeFactory = new Map();\n\t\tconst nodeRequire = new Map();\n\t\tconst nodeEval = new Map();\n\n\t\tfunction mark(map: Map, stat: LoaderEvent) {\n\t\t\tif (map.has(stat.detail)) {\n\t\t\t\t// console.warn('BAD events, DOUBLE start', stat);\n\t\t\t\t// map.delete(stat.detail);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tmap.set(stat.detail, -stat.timestamp);\n\t\t}\n\n\t\tfunction diff(map: Map, stat: LoaderEvent) {\n\t\t\tconst duration = map.get(stat.detail);\n\t\t\tif (!duration) {\n\t\t\t\t// console.warn('BAD events, end WITHOUT start', stat);\n\t\t\t\t// map.delete(stat.detail);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (duration >= 0) {\n\t\t\t\t// console.warn('BAD events, DOUBLE end', stat);\n\t\t\t\t// map.delete(stat.detail);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tmap.set(stat.detail, duration + stat.timestamp);\n\t\t}\n\n\t\tlet stats: readonly LoaderEvent[] = [];\n\t\tif (typeof require === 'function' && typeof require.getStats === 'function') {\n\t\t\tstats = require.getStats().slice(0).sort((a, b) => a.timestamp - b.timestamp);\n\t\t}\n\n\t\tfor (const stat of stats) {\n\t\t\tswitch (stat.type) {\n\t\t\t\tcase LoaderEventType.BeginLoadingScript:\n\t\t\t\t\tmark(amdLoadScript, stat);\n\t\t\t\t\tbreak;\n\t\t\t\tcase LoaderEventType.EndLoadingScriptOK:\n\t\t\t\tcase LoaderEventType.EndLoadingScriptError:\n\t\t\t\t\tdiff(amdLoadScript, stat);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase LoaderEventType.BeginInvokeFactory:\n\t\t\t\t\tmark(amdInvokeFactory, stat);\n\t\t\t\t\tbreak;\n\t\t\t\tcase LoaderEventType.EndInvokeFactory:\n\t\t\t\t\tdiff(amdInvokeFactory, stat);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase LoaderEventType.NodeBeginNativeRequire:\n\t\t\t\t\tmark(nodeRequire, stat);\n\t\t\t\t\tbreak;\n\t\t\t\tcase LoaderEventType.NodeEndNativeRequire:\n\t\t\t\t\tdiff(nodeRequire, stat);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase LoaderEventType.NodeBeginEvaluatingScript:\n\t\t\t\t\tmark(nodeEval, stat);\n\t\t\t\t\tbreak;\n\t\t\t\tcase LoaderEventType.NodeEndEvaluatingScript:\n\t\t\t\t\tdiff(nodeEval, stat);\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tlet nodeRequireTotal = 0;\n\t\tnodeRequire.forEach(value => nodeRequireTotal += value);\n\n\t\tfunction to2dArray(map: Map): [string, number][] {\n\t\t\tconst res: [string, number][] = [];\n\t\t\tmap.forEach((value, index) => res.push([index, value]));\n\t\t\treturn res;\n\t\t}\n\n\t\treturn {\n\t\t\tamdLoad: to2dArray(amdLoadScript),\n\t\t\tamdInvoke: to2dArray(amdInvokeFactory),\n\t\t\tnodeRequire: to2dArray(nodeRequire),\n\t\t\tnodeEval: to2dArray(nodeEval),\n\t\t\tnodeRequireTotal\n\t\t};\n\t}\n\n\tstatic toMarkdownTable(header: string[], rows: Array>): string {\n\t\tlet result = '';\n\n\t\tconst lengths: number[] = [];\n\t\theader.forEach((cell, ci) => {\n\t\t\tlengths[ci] = cell.length;\n\t\t});\n\t\trows.forEach(row => {\n\t\t\trow.forEach((cell, ci) => {\n\t\t\t\tif (typeof cell === 'undefined') {\n\t\t\t\t\tcell = row[ci] = '-';\n\t\t\t\t}\n\t\t\t\tconst len = cell.toString().length;\n\t\t\t\tlengths[ci] = Math.max(len, lengths[ci]);\n\t\t\t});\n\t\t});\n\n\t\t// header\n\t\theader.forEach((cell, ci) => { result += `| ${cell + ' '.repeat(lengths[ci] - cell.toString().length)} `; });\n\t\tresult += '|\\n';\n\t\theader.forEach((_cell, ci) => { result += `| ${'-'.repeat(lengths[ci])} `; });\n\t\tresult += '|\\n';\n\n\t\t// cells\n\t\trows.forEach(row => {\n\t\t\trow.forEach((cell, ci) => {\n\t\t\t\tif (typeof cell !== 'undefined') {\n\t\t\t\t\tresult += `| ${cell + ' '.repeat(lengths[ci] - cell.toString().length)} `;\n\t\t\t\t}\n\t\t\t});\n\t\t\tresult += '|\\n';\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 { Comparator } from './arrays';\n\nexport function findLast(array: readonly T[], predicate: (item: T) => boolean, fromIdx?: number): 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\nexport function findFirstIdxMonotonous(array: readonly T[], predicate: (item: T) => boolean, startIdx = 0, endIdxEx = array.length): number {\n\tconst idx = findFirstIdxMonotonousOrArrLen(array, predicate, startIdx, endIdxEx);\n\treturn idx === array.length ? -1 : idx;\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 findFirstMaxBy(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 findLastMaxBy(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 findFirstMinBy(array: readonly T[], comparator: Comparator): T | undefined {\n\treturn findFirstMaxBy(array, (a, b) => -comparator(a, b));\n}\n\nexport function findMaxIdxBy(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 * Copyright (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\n/**\n * An interface for a JavaScript object that\n * acts a dictionary. The keys are numbers.\n */\nexport type INumberDictionary = Record;\n\n/**\n * Groups the collection into a dictionary based on the provided\n * group function.\n */\nexport function groupBy(data: V[], groupFn: (element: V) => K): Record {\n\tconst result: Record = Object.create(null);\n\tfor (const element of data) {\n\t\tconst key = groupFn(element);\n\t\tlet target = result[key];\n\t\tif (!target) {\n\t\t\ttarget = result[key] = [];\n\t\t}\n\t\ttarget.push(element);\n\t}\n\treturn result;\n}\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\nexport function diffMaps(before: Map, after: Map): { removed: V[]; added: V[] } {\n\tconst removed: V[] = [];\n\tconst added: V[] = [];\n\tfor (const [index, value] of before) {\n\t\tif (!after.has(index)) {\n\t\t\tremoved.push(value);\n\t\t}\n\t}\n\tfor (const [index, value] of after) {\n\t\tif (!before.has(index)) {\n\t\t\tadded.push(value);\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 * http://www.w3.org/TR/WCAG20/#contrast-ratiodef\n\t * Returns the contrast ration number in the set [1, 21].\n\t */\n\tgetContrastRatio(another: Color): number {\n\t\tconst lum1 = this.getRelativeLuminance();\n\t\tconst lum2 = another.getRelativeLuminance();\n\t\treturn lum1 > lum2 ? (lum1 + 0.05) / (lum2 + 0.05) : (lum2 + 0.05) / (lum1 + 0.05);\n\t}\n\n\t/**\n\t *\thttp://24ways.org/2010/calculating-color-contrast\n\t * Return 'true' if darker color otherwise 'false'\n\t */\n\tisDarker(): 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\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\tblend(c: Color): Color {\n\t\tconst rgba = c.rgba;\n\n\t\t// Convert to 0..1 opacity\n\t\tconst thisA = this.rgba.a;\n\t\tconst colorA = rgba.a;\n\n\t\tconst a = thisA + colorA * (1 - thisA);\n\t\tif (a < 1e-6) {\n\t\t\treturn Color.transparent;\n\t\t}\n\n\t\tconst r = this.rgba.r * thisA / a + rgba.r * colorA * (1 - thisA) / a;\n\t\tconst g = this.rgba.g * thisA / a + rgba.g * colorA * (1 - thisA) / a;\n\t\tconst b = this.rgba.b * thisA / a + rgba.b * colorA * (1 - thisA) / a;\n\n\t\treturn new Color(new RGBA(r, g, b, 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\tflatten(...backgrounds: Color[]): Color {\n\t\tconst background = backgrounds.reduceRight((accumulator, color) => {\n\t\t\treturn Color._flatten(color, accumulator);\n\t\t});\n\t\treturn Color._flatten(this, background);\n\t}\n\n\tprivate static _flatten(foreground: Color, background: Color) {\n\t\tconst backgroundAlpha = 1 - foreground.rgba.a;\n\t\treturn new Color(new RGBA(\n\t\t\tbackgroundAlpha * background.rgba.r + foreground.rgba.a * foreground.rgba.r,\n\t\t\tbackgroundAlpha * background.rgba.g + foreground.rgba.a * foreground.rgba.g,\n\t\t\tbackgroundAlpha * background.rgba.b + foreground.rgba.a * foreground.rgba.b\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 * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nfunction createDecorator(mapFn: (fn: Function, key: string) => Function): Function {\n\treturn (target: any, key: string, descriptor: any) => {\n\t\tlet fnKey: string | null = null;\n\t\tlet fn: Function | null = null;\n\n\t\tif (typeof descriptor.value === 'function') {\n\t\t\tfnKey = 'value';\n\t\t\tfn = descriptor.value;\n\t\t} else if (typeof descriptor.get === 'function') {\n\t\t\tfnKey = 'get';\n\t\t\tfn = descriptor.get;\n\t\t}\n\n\t\tif (!fn) {\n\t\t\tthrow new Error('not supported');\n\t\t}\n\n\t\tdescriptor[fnKey!] = mapFn(fn, key);\n\t};\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\nexport interface IDebounceReducer {\n\t(previousValue: T, ...args: any[]): T;\n}\n\nexport function debounce(delay: number, reducer?: IDebounceReducer, initialValueProvider?: () => T): Function {\n\treturn createDecorator((fn, key) => {\n\t\tconst timerKey = `$debounce$${key}`;\n\t\tconst resultKey = `$debounce$result$${key}`;\n\n\t\treturn function (this: any, ...args: any[]) {\n\t\t\tif (!this[resultKey]) {\n\t\t\t\tthis[resultKey] = initialValueProvider ? initialValueProvider() : undefined;\n\t\t\t}\n\n\t\t\tclearTimeout(this[timerKey]);\n\n\t\t\tif (reducer) {\n\t\t\t\tthis[resultKey] = reducer(this[resultKey], ...args);\n\t\t\t\targs = [this[resultKey]];\n\t\t\t}\n\n\t\t\tthis[timerKey] = setTimeout(() => {\n\t\t\t\tfn.apply(this, args);\n\t\t\t\tthis[resultKey] = initialValueProvider ? initialValueProvider() : undefined;\n\t\t\t}, delay);\n\t\t};\n\t});\n}\n\nexport function throttle(delay: number, reducer?: IDebounceReducer, initialValueProvider?: () => T): Function {\n\treturn createDecorator((fn, key) => {\n\t\tconst timerKey = `$throttle$timer$${key}`;\n\t\tconst resultKey = `$throttle$result$${key}`;\n\t\tconst lastRunKey = `$throttle$lastRun$${key}`;\n\t\tconst pendingKey = `$throttle$pending$${key}`;\n\n\t\treturn function (this: any, ...args: any[]) {\n\t\t\tif (!this[resultKey]) {\n\t\t\t\tthis[resultKey] = initialValueProvider ? initialValueProvider() : undefined;\n\t\t\t}\n\t\t\tif (this[lastRunKey] === null || this[lastRunKey] === undefined) {\n\t\t\t\tthis[lastRunKey] = -Number.MAX_VALUE;\n\t\t\t}\n\n\t\t\tif (reducer) {\n\t\t\t\tthis[resultKey] = reducer(this[resultKey], ...args);\n\t\t\t}\n\n\t\t\tif (this[pendingKey]) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst nextTime = this[lastRunKey] + delay;\n\t\t\tif (nextTime <= Date.now()) {\n\t\t\t\tthis[lastRunKey] = Date.now();\n\t\t\t\tfn.apply(this, [this[resultKey]]);\n\t\t\t\tthis[resultKey] = initialValueProvider ? initialValueProvider() : undefined;\n\t\t\t} else {\n\t\t\t\tthis[pendingKey] = true;\n\t\t\t\tthis[timerKey] = setTimeout(() => {\n\t\t\t\t\tthis[pendingKey] = false;\n\t\t\t\t\tthis[lastRunKey] = Date.now();\n\t\t\t\t\tfn.apply(this, [this[resultKey]]);\n\t\t\t\t\tthis[resultKey] = initialValueProvider ? initialValueProvider() : undefined;\n\t\t\t\t}, nextTime - Date.now());\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\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\nexport interface ErrorListenerCallback {\n\t(error: any): void;\n}\n\nexport interface ErrorListenerUnbind {\n\t(): 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\taddListener(listener: ErrorListenerCallback): ErrorListenerUnbind {\n\t\tthis.listeners.push(listener);\n\n\t\treturn () => {\n\t\t\tthis._removeListener(listener);\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\tprivate _removeListener(listener: ErrorListenerCallback): void {\n\t\tthis.listeners.splice(this.listeners.indexOf(listener), 1);\n\t}\n\n\tsetUnexpectedErrorHandler(newUnexpectedErrorHandler: (e: any) => void): void {\n\t\tthis.unexpectedErrorHandler = newUnexpectedErrorHandler;\n\t}\n\n\tgetUnexpectedErrorHandler(): (e: any) => void {\n\t\treturn this.unexpectedErrorHandler;\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\n/** @skipMangle */\nexport function setUnexpectedErrorHandler(newUnexpectedErrorHandler: (e: any) => void): void {\n\terrorHandler.setUnexpectedErrorHandler(newUnexpectedErrorHandler);\n}\n\n/**\n * Returns if the error is a SIGPIPE error. SIGPIPE errors should generally be\n * logged at most once, to avoid a loop.\n *\n * @see https://github.com/microsoft/vscode-remote-release/issues/6481\n */\nexport function isSigPipeError(e: unknown): e is Error {\n\tif (!e || typeof e !== 'object') {\n\t\treturn false;\n\t}\n\n\tconst cast = e as Record;\n\treturn cast.code === 'EPIPE' && cast.syscall?.toUpperCase() === 'WRITE';\n}\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\treadonly $isError: true;\n\treadonly name: string;\n\treadonly message: string;\n\treadonly stack: string;\n\treadonly noTelemetry: boolean;\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\n// see https://github.com/v8/v8/wiki/Stack%20Trace%20API#basic-stack-traces\nexport interface V8CallSite {\n\tgetThis(): unknown;\n\tgetTypeName(): string | null;\n\tgetFunction(): Function | undefined;\n\tgetFunctionName(): string | null;\n\tgetMethodName(): string | null;\n\tgetFileName(): string | null;\n\tgetLineNumber(): number | null;\n\tgetColumnNumber(): number | null;\n\tgetEvalOrigin(): string | undefined;\n\tisToplevel(): boolean;\n\tisEval(): boolean;\n\tisNative(): boolean;\n\tisConstructor(): boolean;\n\ttoString(): string;\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 ReadonlyError extends TypeError {\n\tconstructor(name?: string) {\n\t\tsuper(name ? `${name} is read-only and cannot be changed` : 'Cannot change read-only property');\n\t}\n}\n\nexport function getErrorMessage(err: any): string {\n\tif (!err) {\n\t\treturn 'Error';\n\t}\n\n\tif (err.message) {\n\t\treturn err.message;\n\t}\n\n\tif (err.stack) {\n\t\treturn err.stack.split('\\n')[0];\n\t}\n\n\treturn String(err);\n}\n\nexport class NotImplementedError extends Error {\n\tconstructor(message?: string) {\n\t\tsuper('NotImplemented');\n\t\tif (message) {\n\t\t\tthis.message = message;\n\t\t}\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\nexport class ExpectedError extends Error {\n\treadonly isExpected = true;\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 { CancellationToken } from 'vs/base/common/cancellation';\nimport { CancellationError } from 'vs/base/common/errors';\nimport { ISplice } from 'vs/base/common/sequence';\nimport { findFirstIdxMonotonousOrArrLen } from './arraysFind';\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 {\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\ninterface IMutableSplice extends ISplice {\n\treadonly toInsert: T[];\n\tdeleteCount: number;\n}\n\n/**\n * Diffs two *sorted* arrays and computes the splices which apply the diff.\n */\nexport function sortedDiff(before: ReadonlyArray, after: ReadonlyArray, compare: (a: T, b: T) => number): ISplice[] {\n\tconst result: IMutableSplice[] = [];\n\n\tfunction pushSplice(start: number, deleteCount: number, toInsert: T[]): void {\n\t\tif (deleteCount === 0 && toInsert.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst latest = result[result.length - 1];\n\n\t\tif (latest && latest.start + latest.deleteCount === start) {\n\t\t\tlatest.deleteCount += deleteCount;\n\t\t\tlatest.toInsert.push(...toInsert);\n\t\t} else {\n\t\t\tresult.push({ start, deleteCount, toInsert });\n\t\t}\n\t}\n\n\tlet beforeIdx = 0;\n\tlet afterIdx = 0;\n\n\twhile (true) {\n\t\tif (beforeIdx === before.length) {\n\t\t\tpushSplice(beforeIdx, 0, after.slice(afterIdx));\n\t\t\tbreak;\n\t\t}\n\t\tif (afterIdx === after.length) {\n\t\t\tpushSplice(beforeIdx, before.length - beforeIdx, []);\n\t\t\tbreak;\n\t\t}\n\n\t\tconst beforeElement = before[beforeIdx];\n\t\tconst afterElement = after[afterIdx];\n\t\tconst n = compare(beforeElement, afterElement);\n\t\tif (n === 0) {\n\t\t\t// equal\n\t\t\tbeforeIdx += 1;\n\t\t\tafterIdx += 1;\n\t\t} else if (n < 0) {\n\t\t\t// beforeElement is smaller -> before element removed\n\t\t\tpushSplice(beforeIdx, 1, []);\n\t\t\tbeforeIdx += 1;\n\t\t} else if (n > 0) {\n\t\t\t// beforeElement is greater -> after element added\n\t\t\tpushSplice(beforeIdx, 0, [afterElement]);\n\t\t\tafterIdx += 1;\n\t\t}\n\t}\n\n\treturn result;\n}\n\n/**\n * Takes two *sorted* arrays and computes their delta (removed, added elements).\n * Finishes in `Math.min(before.length, after.length)` steps.\n */\nexport function delta(before: ReadonlyArray, after: ReadonlyArray, compare: (a: T, b: T) => number): { removed: T[]; added: T[] } {\n\tconst splices = sortedDiff(before, after, compare);\n\tconst removed: T[] = [];\n\tconst added: T[] = [];\n\n\tfor (const splice of splices) {\n\t\tremoved.push(...before.slice(splice.start, splice.start + splice.deleteCount));\n\t\tadded.push(...splice.toInsert);\n\t}\n\n\treturn { removed, added };\n}\n\n/**\n * Returns the top N elements from the array.\n *\n * Faster than sorting the entire array when the array is a lot larger than N.\n *\n * @param array The unsorted array.\n * @param compare A sort function for the elements.\n * @param n The number of elements to return.\n * @return The first n elements from array when sorted with compare.\n */\nexport function top(array: ReadonlyArray, compare: (a: T, b: T) => number, n: number): T[] {\n\tif (n === 0) {\n\t\treturn [];\n\t}\n\tconst result = array.slice(0, n).sort(compare);\n\ttopStep(array, compare, result, n, array.length);\n\treturn result;\n}\n\n/**\n * Asynchronous variant of `top()` allowing for splitting up work in batches between which the event loop can run.\n *\n * Returns the top N elements from the array.\n *\n * Faster than sorting the entire array when the array is a lot larger than N.\n *\n * @param array The unsorted array.\n * @param compare A sort function for the elements.\n * @param n The number of elements to return.\n * @param batch The number of elements to examine before yielding to the event loop.\n * @return The first n elements from array when sorted with compare.\n */\nexport function topAsync(array: T[], compare: (a: T, b: T) => number, n: number, batch: number, token?: CancellationToken): Promise {\n\tif (n === 0) {\n\t\treturn Promise.resolve([]);\n\t}\n\n\treturn new Promise((resolve, reject) => {\n\t\t(async () => {\n\t\t\tconst o = array.length;\n\t\t\tconst result = array.slice(0, n).sort(compare);\n\t\t\tfor (let i = n, m = Math.min(n + batch, o); i < o; i = m, m = Math.min(m + batch, o)) {\n\t\t\t\tif (i > n) {\n\t\t\t\t\tawait new Promise(resolve => setTimeout(resolve)); // any other delay function would starve I/O\n\t\t\t\t}\n\t\t\t\tif (token && token.isCancellationRequested) {\n\t\t\t\t\tthrow new CancellationError();\n\t\t\t\t}\n\t\t\t\ttopStep(array, compare, result, i, m);\n\t\t\t}\n\t\t\treturn result;\n\t\t})()\n\t\t\t.then(resolve, reject);\n\t});\n}\n\nfunction topStep(array: ReadonlyArray, compare: (a: T, b: T) => number, result: T[], i: number, m: number): void {\n\tfor (const n = result.length; i < m; i++) {\n\t\tconst element = array[i];\n\t\tif (compare(element, result[n - 1]) < 0) {\n\t\t\tresult.pop();\n\t\t\tconst j = findFirstIdxMonotonousOrArrLen(result, e => compare(element, e) < 0);\n\t\t\tresult.splice(j, 0, element);\n\t\t}\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);\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 * @deprecated Use `Array.copyWithin` instead\n */\nexport function move(array: any[], from: number, to: number): void {\n\tarray.splice(to, 0, array.splice(from, 1)[0]);\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 uniqueFilter(keyFn: (t: T) => R): (t: T) => boolean {\n\tconst seen = new Set();\n\n\treturn element => {\n\t\tconst key = keyFn(element);\n\n\t\tif (seen.has(key)) {\n\t\t\treturn false;\n\t\t}\n\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 lastOrDefault(array: ReadonlyArray, notFoundValue: NotFound): T | NotFound;\nexport function lastOrDefault(array: ReadonlyArray): T | undefined;\nexport function lastOrDefault(array: ReadonlyArray, notFoundValue?: NotFound): T | NotFound | undefined {\n\treturn array.length > 0 ? array[array.length - 1] : notFoundValue;\n}\n\nexport function commonPrefixLength(one: ReadonlyArray, other: ReadonlyArray, equals: (a: T, b: T) => boolean = (a, b) => a === b): number {\n\tlet result = 0;\n\n\tfor (let i = 0, len = Math.min(one.length, other.length); i < len && equals(one[i], other[i]); i++) {\n\t\tresult++;\n\t}\n\n\treturn result;\n}\n\n/**\n * @deprecated Use `[].flat()`\n */\nexport function flatten(arr: T[][]): T[] {\n\treturn ([]).concat(...arr);\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\nexport function index(array: ReadonlyArray, indexer: (t: T) => string): { [key: string]: T };\nexport function index(array: ReadonlyArray, indexer: (t: T) => string, mapper: (t: T) => R): { [key: string]: R };\nexport function index(array: ReadonlyArray, indexer: (t: T) => string, mapper?: (t: T) => R): { [key: string]: R } {\n\treturn array.reduce((r, t) => {\n\t\tr[indexer(t)] = mapper ? mapper(t) : t;\n\t\treturn r;\n\t}, Object.create(null));\n}\n\n/**\n * Inserts an element into an array. Returns a function which, when\n * called, will remove that element from the array.\n *\n * @deprecated In almost all cases, use a `Set` instead.\n */\nexport function insert(array: T[], element: T): () => void {\n\tarray.push(element);\n\n\treturn () => remove(array, element);\n}\n\n/**\n * Removes an element from an array if it can be found.\n *\n * @deprecated In almost all cases, use a `Set` instead.\n */\nexport function remove(array: T[], element: T): T | undefined {\n\tconst index = array.indexOf(element);\n\tif (index > -1) {\n\t\tarray.splice(index, 1);\n\n\t\treturn element;\n\t}\n\n\treturn undefined;\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 * Uses Fisher-Yates shuffle to shuffle the given array\n */\nexport function shuffle(array: T[], _seed?: number): void {\n\tlet rand: () => number;\n\n\tif (typeof _seed === 'number') {\n\t\tlet seed = _seed;\n\t\t// Seeded random number generator in JS. Modified from:\n\t\t// https://stackoverflow.com/questions/521295/seeding-the-random-number-generator-in-javascript\n\t\trand = () => {\n\t\t\tconst x = Math.sin(seed++) * 179426549; // throw away most significant digits and reduce any potential bias\n\t\t\treturn x - Math.floor(x);\n\t\t};\n\t} else {\n\t\trand = Math.random;\n\t}\n\n\tfor (let i = array.length - 1; i > 0; i -= 1) {\n\t\tconst j = Math.floor(rand() * (i + 1));\n\t\tconst temp = array[i];\n\t\tarray[i] = array[j];\n\t\tarray[j] = temp;\n\t}\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 mapArrayOrNot(items: T | T[], fn: (_: T) => U): U | U[] {\n\treturn Array.isArray(items) ?\n\t\titems.map(fn) :\n\t\tfn(items);\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\nexport function getRandomElement(arr: T[]): T | undefined {\n\treturn arr[Math.floor(Math.random() * arr.length)];\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\tpeekLast(): T | undefined {\n\t\tif (this.length === 0) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn this.items[this.lastIdx];\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\tremoveLast(): T | undefined {\n\t\tconst result = this.items[this.lastIdx];\n\t\tthis.lastIdx--;\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\tforEach(handler: (item: T) => void) {\n\t\tthis.iterate(item => { handler(item); return true; });\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\tsome(predicate: (item: T) => boolean): boolean {\n\t\tlet result = false;\n\t\tthis.iterate(item => { result = predicate(item); return !result; });\n\t\treturn result;\n\t}\n\n\tfindFirst(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\treturn false;\n\t\t\t}\n\t\t\treturn true;\n\t\t});\n\t\treturn result;\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 * Copyright (c) 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\nexport function assert(condition: boolean): void {\n\tif (!condition) {\n\t\tthrow new BugIndicatingError('Assertion Failed');\n\t}\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 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\nexport const enum ScanError {\n\tNone = 0,\n\tUnexpectedEndOfComment = 1,\n\tUnexpectedEndOfString = 2,\n\tUnexpectedEndOfNumber = 3,\n\tInvalidUnicode = 4,\n\tInvalidEscapeCharacter = 5,\n\tInvalidCharacter = 6\n}\n\nexport const enum SyntaxKind {\n\tOpenBraceToken = 1,\n\tCloseBraceToken = 2,\n\tOpenBracketToken = 3,\n\tCloseBracketToken = 4,\n\tCommaToken = 5,\n\tColonToken = 6,\n\tNullKeyword = 7,\n\tTrueKeyword = 8,\n\tFalseKeyword = 9,\n\tStringLiteral = 10,\n\tNumericLiteral = 11,\n\tLineCommentTrivia = 12,\n\tBlockCommentTrivia = 13,\n\tLineBreakTrivia = 14,\n\tTrivia = 15,\n\tUnknown = 16,\n\tEOF = 17\n}\n\n/**\n * The scanner object, representing a JSON scanner at a position in the input string.\n */\nexport interface JSONScanner {\n\t/**\n\t * Sets the scan position to a new offset. A call to 'scan' is needed to get the first token.\n\t */\n\tsetPosition(pos: number): void;\n\t/**\n\t * Read the next token. Returns the token code.\n\t */\n\tscan(): SyntaxKind;\n\t/**\n\t * Returns the current scan position, which is after the last read token.\n\t */\n\tgetPosition(): number;\n\t/**\n\t * Returns the last read token.\n\t */\n\tgetToken(): SyntaxKind;\n\t/**\n\t * Returns the last read token value. The value for strings is the decoded string content. For numbers its of type number, for boolean it's true or false.\n\t */\n\tgetTokenValue(): string;\n\t/**\n\t * The start offset of the last read token.\n\t */\n\tgetTokenOffset(): number;\n\t/**\n\t * The length of the last read token.\n\t */\n\tgetTokenLength(): number;\n\t/**\n\t * An error code of the last scan.\n\t */\n\tgetTokenError(): ScanError;\n}\n\n\n\nexport interface ParseError {\n\terror: ParseErrorCode;\n\toffset: number;\n\tlength: number;\n}\n\nexport const enum ParseErrorCode {\n\tInvalidSymbol = 1,\n\tInvalidNumberFormat = 2,\n\tPropertyNameExpected = 3,\n\tValueExpected = 4,\n\tColonExpected = 5,\n\tCommaExpected = 6,\n\tCloseBraceExpected = 7,\n\tCloseBracketExpected = 8,\n\tEndOfFileExpected = 9,\n\tInvalidCommentToken = 10,\n\tUnexpectedEndOfComment = 11,\n\tUnexpectedEndOfString = 12,\n\tUnexpectedEndOfNumber = 13,\n\tInvalidUnicode = 14,\n\tInvalidEscapeCharacter = 15,\n\tInvalidCharacter = 16\n}\n\nexport type NodeType = 'object' | 'array' | 'property' | 'string' | 'number' | 'boolean' | 'null';\n\nexport interface Node {\n\treadonly type: NodeType;\n\treadonly value?: any;\n\treadonly offset: number;\n\treadonly length: number;\n\treadonly colonOffset?: number;\n\treadonly parent?: Node;\n\treadonly children?: Node[];\n}\n\nexport type Segment = string | number;\nexport type JSONPath = Segment[];\n\nexport interface Location {\n\t/**\n\t * The previous property key or literal value (string, number, boolean or null) or undefined.\n\t */\n\tpreviousNode?: Node;\n\t/**\n\t * The path describing the location in the JSON document. The path consists of a sequence strings\n\t * representing an object property or numbers for array indices.\n\t */\n\tpath: JSONPath;\n\t/**\n\t * Matches the locations path against a pattern consisting of strings (for properties) and numbers (for array indices).\n\t * '*' will match a single segment, of any property name or index.\n\t * '**' will match a sequence of segments or no segment, of any property name or index.\n\t */\n\tmatches: (patterns: JSONPath) => boolean;\n\t/**\n\t * If set, the location's offset is at a property key.\n\t */\n\tisAtPropertyKey: boolean;\n}\n\nexport interface ParseOptions {\n\tdisallowComments?: boolean;\n\tallowTrailingComma?: boolean;\n\tallowEmptyContent?: boolean;\n}\n\nexport namespace ParseOptions {\n\texport const DEFAULT = {\n\t\tallowTrailingComma: true\n\t};\n}\n\nexport interface JSONVisitor {\n\t/**\n\t * Invoked when an open brace is encountered and an object is started. The offset and length represent the location of the open brace.\n\t */\n\tonObjectBegin?: (offset: number, length: number) => void;\n\n\t/**\n\t * Invoked when a property is encountered. The offset and length represent the location of the property name.\n\t */\n\tonObjectProperty?: (property: string, offset: number, length: number) => void;\n\n\t/**\n\t * Invoked when a closing brace is encountered and an object is completed. The offset and length represent the location of the closing brace.\n\t */\n\tonObjectEnd?: (offset: number, length: number) => void;\n\n\t/**\n\t * Invoked when an open bracket is encountered. The offset and length represent the location of the open bracket.\n\t */\n\tonArrayBegin?: (offset: number, length: number) => void;\n\n\t/**\n\t * Invoked when a closing bracket is encountered. The offset and length represent the location of the closing bracket.\n\t */\n\tonArrayEnd?: (offset: number, length: number) => void;\n\n\t/**\n\t * Invoked when a literal value is encountered. The offset and length represent the location of the literal value.\n\t */\n\tonLiteralValue?: (value: any, offset: number, length: number) => void;\n\n\t/**\n\t * Invoked when a comma or colon separator is encountered. The offset and length represent the location of the separator.\n\t */\n\tonSeparator?: (character: string, offset: number, length: number) => void;\n\n\t/**\n\t * When comments are allowed, invoked when a line or block comment is encountered. The offset and length represent the location of the comment.\n\t */\n\tonComment?: (offset: number, length: number) => void;\n\n\t/**\n\t * Invoked on an error.\n\t */\n\tonError?: (error: ParseErrorCode, offset: number, length: number) => void;\n}\n\n/**\n * Creates a JSON scanner on the given text.\n * If ignoreTrivia is set, whitespaces or comments are ignored.\n */\nexport function createScanner(text: string, ignoreTrivia: boolean = false): JSONScanner {\n\n\tlet pos = 0;\n\tconst len = text.length;\n\tlet value: string = '';\n\tlet tokenOffset = 0;\n\tlet token: SyntaxKind = SyntaxKind.Unknown;\n\tlet scanError: ScanError = ScanError.None;\n\n\tfunction scanHexDigits(count: number): number {\n\t\tlet digits = 0;\n\t\tlet hexValue = 0;\n\t\twhile (digits < count) {\n\t\t\tconst ch = text.charCodeAt(pos);\n\t\t\tif (ch >= CharacterCodes._0 && ch <= CharacterCodes._9) {\n\t\t\t\thexValue = hexValue * 16 + ch - CharacterCodes._0;\n\t\t\t}\n\t\t\telse if (ch >= CharacterCodes.A && ch <= CharacterCodes.F) {\n\t\t\t\thexValue = hexValue * 16 + ch - CharacterCodes.A + 10;\n\t\t\t}\n\t\t\telse if (ch >= CharacterCodes.a && ch <= CharacterCodes.f) {\n\t\t\t\thexValue = hexValue * 16 + ch - CharacterCodes.a + 10;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tpos++;\n\t\t\tdigits++;\n\t\t}\n\t\tif (digits < count) {\n\t\t\thexValue = -1;\n\t\t}\n\t\treturn hexValue;\n\t}\n\n\tfunction setPosition(newPosition: number) {\n\t\tpos = newPosition;\n\t\tvalue = '';\n\t\ttokenOffset = 0;\n\t\ttoken = SyntaxKind.Unknown;\n\t\tscanError = ScanError.None;\n\t}\n\n\tfunction scanNumber(): string {\n\t\tconst start = pos;\n\t\tif (text.charCodeAt(pos) === CharacterCodes._0) {\n\t\t\tpos++;\n\t\t} else {\n\t\t\tpos++;\n\t\t\twhile (pos < text.length && isDigit(text.charCodeAt(pos))) {\n\t\t\t\tpos++;\n\t\t\t}\n\t\t}\n\t\tif (pos < text.length && text.charCodeAt(pos) === CharacterCodes.dot) {\n\t\t\tpos++;\n\t\t\tif (pos < text.length && isDigit(text.charCodeAt(pos))) {\n\t\t\t\tpos++;\n\t\t\t\twhile (pos < text.length && isDigit(text.charCodeAt(pos))) {\n\t\t\t\t\tpos++;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tscanError = ScanError.UnexpectedEndOfNumber;\n\t\t\t\treturn text.substring(start, pos);\n\t\t\t}\n\t\t}\n\t\tlet end = pos;\n\t\tif (pos < text.length && (text.charCodeAt(pos) === CharacterCodes.E || text.charCodeAt(pos) === CharacterCodes.e)) {\n\t\t\tpos++;\n\t\t\tif (pos < text.length && text.charCodeAt(pos) === CharacterCodes.plus || text.charCodeAt(pos) === CharacterCodes.minus) {\n\t\t\t\tpos++;\n\t\t\t}\n\t\t\tif (pos < text.length && isDigit(text.charCodeAt(pos))) {\n\t\t\t\tpos++;\n\t\t\t\twhile (pos < text.length && isDigit(text.charCodeAt(pos))) {\n\t\t\t\t\tpos++;\n\t\t\t\t}\n\t\t\t\tend = pos;\n\t\t\t} else {\n\t\t\t\tscanError = ScanError.UnexpectedEndOfNumber;\n\t\t\t}\n\t\t}\n\t\treturn text.substring(start, end);\n\t}\n\n\tfunction scanString(): string {\n\n\t\tlet result = '',\n\t\t\tstart = pos;\n\n\t\twhile (true) {\n\t\t\tif (pos >= len) {\n\t\t\t\tresult += text.substring(start, pos);\n\t\t\t\tscanError = ScanError.UnexpectedEndOfString;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tconst ch = text.charCodeAt(pos);\n\t\t\tif (ch === CharacterCodes.doubleQuote) {\n\t\t\t\tresult += text.substring(start, pos);\n\t\t\t\tpos++;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (ch === CharacterCodes.backslash) {\n\t\t\t\tresult += text.substring(start, pos);\n\t\t\t\tpos++;\n\t\t\t\tif (pos >= len) {\n\t\t\t\t\tscanError = ScanError.UnexpectedEndOfString;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tconst ch2 = text.charCodeAt(pos++);\n\t\t\t\tswitch (ch2) {\n\t\t\t\t\tcase CharacterCodes.doubleQuote:\n\t\t\t\t\t\tresult += '\\\"';\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase CharacterCodes.backslash:\n\t\t\t\t\t\tresult += '\\\\';\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase CharacterCodes.slash:\n\t\t\t\t\t\tresult += '/';\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase CharacterCodes.b:\n\t\t\t\t\t\tresult += '\\b';\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase CharacterCodes.f:\n\t\t\t\t\t\tresult += '\\f';\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase CharacterCodes.n:\n\t\t\t\t\t\tresult += '\\n';\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase CharacterCodes.r:\n\t\t\t\t\t\tresult += '\\r';\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase CharacterCodes.t:\n\t\t\t\t\t\tresult += '\\t';\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase CharacterCodes.u: {\n\t\t\t\t\t\tconst ch3 = scanHexDigits(4);\n\t\t\t\t\t\tif (ch3 >= 0) {\n\t\t\t\t\t\t\tresult += String.fromCharCode(ch3);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tscanError = ScanError.InvalidUnicode;\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\tdefault:\n\t\t\t\t\t\tscanError = ScanError.InvalidEscapeCharacter;\n\t\t\t\t}\n\t\t\t\tstart = pos;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (ch >= 0 && ch <= 0x1F) {\n\t\t\t\tif (isLineBreak(ch)) {\n\t\t\t\t\tresult += text.substring(start, pos);\n\t\t\t\t\tscanError = ScanError.UnexpectedEndOfString;\n\t\t\t\t\tbreak;\n\t\t\t\t} else {\n\t\t\t\t\tscanError = ScanError.InvalidCharacter;\n\t\t\t\t\t// mark as error but continue with string\n\t\t\t\t}\n\t\t\t}\n\t\t\tpos++;\n\t\t}\n\t\treturn result;\n\t}\n\n\tfunction scanNext(): SyntaxKind {\n\n\t\tvalue = '';\n\t\tscanError = ScanError.None;\n\n\t\ttokenOffset = pos;\n\n\t\tif (pos >= len) {\n\t\t\t// at the end\n\t\t\ttokenOffset = len;\n\t\t\treturn token = SyntaxKind.EOF;\n\t\t}\n\n\t\tlet code = text.charCodeAt(pos);\n\t\t// trivia: whitespace\n\t\tif (isWhitespace(code)) {\n\t\t\tdo {\n\t\t\t\tpos++;\n\t\t\t\tvalue += String.fromCharCode(code);\n\t\t\t\tcode = text.charCodeAt(pos);\n\t\t\t} while (isWhitespace(code));\n\n\t\t\treturn token = SyntaxKind.Trivia;\n\t\t}\n\n\t\t// trivia: newlines\n\t\tif (isLineBreak(code)) {\n\t\t\tpos++;\n\t\t\tvalue += String.fromCharCode(code);\n\t\t\tif (code === CharacterCodes.carriageReturn && text.charCodeAt(pos) === CharacterCodes.lineFeed) {\n\t\t\t\tpos++;\n\t\t\t\tvalue += '\\n';\n\t\t\t}\n\t\t\treturn token = SyntaxKind.LineBreakTrivia;\n\t\t}\n\n\t\tswitch (code) {\n\t\t\t// tokens: []{}:,\n\t\t\tcase CharacterCodes.openBrace:\n\t\t\t\tpos++;\n\t\t\t\treturn token = SyntaxKind.OpenBraceToken;\n\t\t\tcase CharacterCodes.closeBrace:\n\t\t\t\tpos++;\n\t\t\t\treturn token = SyntaxKind.CloseBraceToken;\n\t\t\tcase CharacterCodes.openBracket:\n\t\t\t\tpos++;\n\t\t\t\treturn token = SyntaxKind.OpenBracketToken;\n\t\t\tcase CharacterCodes.closeBracket:\n\t\t\t\tpos++;\n\t\t\t\treturn token = SyntaxKind.CloseBracketToken;\n\t\t\tcase CharacterCodes.colon:\n\t\t\t\tpos++;\n\t\t\t\treturn token = SyntaxKind.ColonToken;\n\t\t\tcase CharacterCodes.comma:\n\t\t\t\tpos++;\n\t\t\t\treturn token = SyntaxKind.CommaToken;\n\n\t\t\t// strings\n\t\t\tcase CharacterCodes.doubleQuote:\n\t\t\t\tpos++;\n\t\t\t\tvalue = scanString();\n\t\t\t\treturn token = SyntaxKind.StringLiteral;\n\n\t\t\t// comments\n\t\t\tcase CharacterCodes.slash: {\n\t\t\t\tconst start = pos - 1;\n\t\t\t\t// Single-line comment\n\t\t\t\tif (text.charCodeAt(pos + 1) === CharacterCodes.slash) {\n\t\t\t\t\tpos += 2;\n\n\t\t\t\t\twhile (pos < len) {\n\t\t\t\t\t\tif (isLineBreak(text.charCodeAt(pos))) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tpos++;\n\n\t\t\t\t\t}\n\t\t\t\t\tvalue = text.substring(start, pos);\n\t\t\t\t\treturn token = SyntaxKind.LineCommentTrivia;\n\t\t\t\t}\n\n\t\t\t\t// Multi-line comment\n\t\t\t\tif (text.charCodeAt(pos + 1) === CharacterCodes.asterisk) {\n\t\t\t\t\tpos += 2;\n\n\t\t\t\t\tconst safeLength = len - 1; // For lookahead.\n\t\t\t\t\tlet commentClosed = false;\n\t\t\t\t\twhile (pos < safeLength) {\n\t\t\t\t\t\tconst ch = text.charCodeAt(pos);\n\n\t\t\t\t\t\tif (ch === CharacterCodes.asterisk && text.charCodeAt(pos + 1) === CharacterCodes.slash) {\n\t\t\t\t\t\t\tpos += 2;\n\t\t\t\t\t\t\tcommentClosed = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tpos++;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!commentClosed) {\n\t\t\t\t\t\tpos++;\n\t\t\t\t\t\tscanError = ScanError.UnexpectedEndOfComment;\n\t\t\t\t\t}\n\n\t\t\t\t\tvalue = text.substring(start, pos);\n\t\t\t\t\treturn token = SyntaxKind.BlockCommentTrivia;\n\t\t\t\t}\n\t\t\t\t// just a single slash\n\t\t\t\tvalue += String.fromCharCode(code);\n\t\t\t\tpos++;\n\t\t\t\treturn token = SyntaxKind.Unknown;\n\t\t\t}\n\t\t\t// numbers\n\t\t\tcase CharacterCodes.minus:\n\t\t\t\tvalue += String.fromCharCode(code);\n\t\t\t\tpos++;\n\t\t\t\tif (pos === len || !isDigit(text.charCodeAt(pos))) {\n\t\t\t\t\treturn token = SyntaxKind.Unknown;\n\t\t\t\t}\n\t\t\t// found a minus, followed by a number so\n\t\t\t// we fall through to proceed with scanning\n\t\t\t// numbers\n\t\t\tcase CharacterCodes._0:\n\t\t\tcase CharacterCodes._1:\n\t\t\tcase CharacterCodes._2:\n\t\t\tcase CharacterCodes._3:\n\t\t\tcase CharacterCodes._4:\n\t\t\tcase CharacterCodes._5:\n\t\t\tcase CharacterCodes._6:\n\t\t\tcase CharacterCodes._7:\n\t\t\tcase CharacterCodes._8:\n\t\t\tcase CharacterCodes._9:\n\t\t\t\tvalue += scanNumber();\n\t\t\t\treturn token = SyntaxKind.NumericLiteral;\n\t\t\t// literals and unknown symbols\n\t\t\tdefault:\n\t\t\t\t// is a literal? Read the full word.\n\t\t\t\twhile (pos < len && isUnknownContentCharacter(code)) {\n\t\t\t\t\tpos++;\n\t\t\t\t\tcode = text.charCodeAt(pos);\n\t\t\t\t}\n\t\t\t\tif (tokenOffset !== pos) {\n\t\t\t\t\tvalue = text.substring(tokenOffset, pos);\n\t\t\t\t\t// keywords: true, false, null\n\t\t\t\t\tswitch (value) {\n\t\t\t\t\t\tcase 'true': return token = SyntaxKind.TrueKeyword;\n\t\t\t\t\t\tcase 'false': return token = SyntaxKind.FalseKeyword;\n\t\t\t\t\t\tcase 'null': return token = SyntaxKind.NullKeyword;\n\t\t\t\t\t}\n\t\t\t\t\treturn token = SyntaxKind.Unknown;\n\t\t\t\t}\n\t\t\t\t// some\n\t\t\t\tvalue += String.fromCharCode(code);\n\t\t\t\tpos++;\n\t\t\t\treturn token = SyntaxKind.Unknown;\n\t\t}\n\t}\n\n\tfunction isUnknownContentCharacter(code: CharacterCodes) {\n\t\tif (isWhitespace(code) || isLineBreak(code)) {\n\t\t\treturn false;\n\t\t}\n\t\tswitch (code) {\n\t\t\tcase CharacterCodes.closeBrace:\n\t\t\tcase CharacterCodes.closeBracket:\n\t\t\tcase CharacterCodes.openBrace:\n\t\t\tcase CharacterCodes.openBracket:\n\t\t\tcase CharacterCodes.doubleQuote:\n\t\t\tcase CharacterCodes.colon:\n\t\t\tcase CharacterCodes.comma:\n\t\t\tcase CharacterCodes.slash:\n\t\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\n\tfunction scanNextNonTrivia(): SyntaxKind {\n\t\tlet result: SyntaxKind;\n\t\tdo {\n\t\t\tresult = scanNext();\n\t\t} while (result >= SyntaxKind.LineCommentTrivia && result <= SyntaxKind.Trivia);\n\t\treturn result;\n\t}\n\n\treturn {\n\t\tsetPosition: setPosition,\n\t\tgetPosition: () => pos,\n\t\tscan: ignoreTrivia ? scanNextNonTrivia : scanNext,\n\t\tgetToken: () => token,\n\t\tgetTokenValue: () => value,\n\t\tgetTokenOffset: () => tokenOffset,\n\t\tgetTokenLength: () => pos - tokenOffset,\n\t\tgetTokenError: () => scanError\n\t};\n}\n\nfunction isWhitespace(ch: number): boolean {\n\treturn ch === CharacterCodes.space || ch === CharacterCodes.tab || ch === CharacterCodes.verticalTab || ch === CharacterCodes.formFeed ||\n\t\tch === CharacterCodes.nonBreakingSpace || ch === CharacterCodes.ogham || ch >= CharacterCodes.enQuad && ch <= CharacterCodes.zeroWidthSpace ||\n\t\tch === CharacterCodes.narrowNoBreakSpace || ch === CharacterCodes.mathematicalSpace || ch === CharacterCodes.ideographicSpace || ch === CharacterCodes.byteOrderMark;\n}\n\nfunction isLineBreak(ch: number): boolean {\n\treturn ch === CharacterCodes.lineFeed || ch === CharacterCodes.carriageReturn || ch === CharacterCodes.lineSeparator || ch === CharacterCodes.paragraphSeparator;\n}\n\nfunction isDigit(ch: number): boolean {\n\treturn ch >= CharacterCodes._0 && ch <= CharacterCodes._9;\n}\n\nconst enum CharacterCodes {\n\tnullCharacter = 0,\n\tmaxAsciiCharacter = 0x7F,\n\n\tlineFeed = 0x0A, // \\n\n\tcarriageReturn = 0x0D, // \\r\n\tlineSeparator = 0x2028,\n\tparagraphSeparator = 0x2029,\n\n\t// REVIEW: do we need to support this? The scanner doesn't, but our IText does. This seems\n\t// like an odd disparity? (Or maybe it's completely fine for them to be different).\n\tnextLine = 0x0085,\n\n\t// Unicode 3.0 space characters\n\tspace = 0x0020, // \" \"\n\tnonBreakingSpace = 0x00A0, //\n\tenQuad = 0x2000,\n\temQuad = 0x2001,\n\tenSpace = 0x2002,\n\temSpace = 0x2003,\n\tthreePerEmSpace = 0x2004,\n\tfourPerEmSpace = 0x2005,\n\tsixPerEmSpace = 0x2006,\n\tfigureSpace = 0x2007,\n\tpunctuationSpace = 0x2008,\n\tthinSpace = 0x2009,\n\thairSpace = 0x200A,\n\tzeroWidthSpace = 0x200B,\n\tnarrowNoBreakSpace = 0x202F,\n\tideographicSpace = 0x3000,\n\tmathematicalSpace = 0x205F,\n\togham = 0x1680,\n\n\t_ = 0x5F,\n\t$ = 0x24,\n\n\t_0 = 0x30,\n\t_1 = 0x31,\n\t_2 = 0x32,\n\t_3 = 0x33,\n\t_4 = 0x34,\n\t_5 = 0x35,\n\t_6 = 0x36,\n\t_7 = 0x37,\n\t_8 = 0x38,\n\t_9 = 0x39,\n\n\ta = 0x61,\n\tb = 0x62,\n\tc = 0x63,\n\td = 0x64,\n\te = 0x65,\n\tf = 0x66,\n\tg = 0x67,\n\th = 0x68,\n\ti = 0x69,\n\tj = 0x6A,\n\tk = 0x6B,\n\tl = 0x6C,\n\tm = 0x6D,\n\tn = 0x6E,\n\to = 0x6F,\n\tp = 0x70,\n\tq = 0x71,\n\tr = 0x72,\n\ts = 0x73,\n\tt = 0x74,\n\tu = 0x75,\n\tv = 0x76,\n\tw = 0x77,\n\tx = 0x78,\n\ty = 0x79,\n\tz = 0x7A,\n\n\tA = 0x41,\n\tB = 0x42,\n\tC = 0x43,\n\tD = 0x44,\n\tE = 0x45,\n\tF = 0x46,\n\tG = 0x47,\n\tH = 0x48,\n\tI = 0x49,\n\tJ = 0x4A,\n\tK = 0x4B,\n\tL = 0x4C,\n\tM = 0x4D,\n\tN = 0x4E,\n\tO = 0x4F,\n\tP = 0x50,\n\tQ = 0x51,\n\tR = 0x52,\n\tS = 0x53,\n\tT = 0x54,\n\tU = 0x55,\n\tV = 0x56,\n\tW = 0x57,\n\tX = 0x58,\n\tY = 0x59,\n\tZ = 0x5A,\n\n\tampersand = 0x26, // &\n\tasterisk = 0x2A, // *\n\tat = 0x40, // @\n\tbackslash = 0x5C, // \\\n\tbar = 0x7C, // |\n\tcaret = 0x5E, // ^\n\tcloseBrace = 0x7D, // }\n\tcloseBracket = 0x5D, // ]\n\tcloseParen = 0x29, // )\n\tcolon = 0x3A, // :\n\tcomma = 0x2C, // ,\n\tdot = 0x2E, // .\n\tdoubleQuote = 0x22, // \"\n\tequals = 0x3D, // =\n\texclamation = 0x21, // !\n\tgreaterThan = 0x3E, // >\n\tlessThan = 0x3C, // <\n\tminus = 0x2D, // -\n\topenBrace = 0x7B, // {\n\topenBracket = 0x5B, // [\n\topenParen = 0x28, // (\n\tpercent = 0x25, // %\n\tplus = 0x2B, // +\n\tquestion = 0x3F, // ?\n\tsemicolon = 0x3B, // ;\n\tsingleQuote = 0x27, // '\n\tslash = 0x2F, // /\n\ttilde = 0x7E, // ~\n\n\tbackspace = 0x08, // \\b\n\tformFeed = 0x0C, // \\f\n\tbyteOrderMark = 0xFEFF,\n\ttab = 0x09, // \\t\n\tverticalTab = 0x0B, // \\v\n}\n\ninterface NodeImpl extends Node {\n\ttype: NodeType;\n\tvalue?: any;\n\toffset: number;\n\tlength: number;\n\tcolonOffset?: number;\n\tparent?: NodeImpl;\n\tchildren?: NodeImpl[];\n}\n\n/**\n * For a given offset, evaluate the location in the JSON document. Each segment in the location path is either a property name or an array index.\n */\nexport function getLocation(text: string, position: number): Location {\n\tconst segments: Segment[] = []; // strings or numbers\n\tconst earlyReturnException = new Object();\n\tlet previousNode: NodeImpl | undefined = undefined;\n\tconst previousNodeInst: NodeImpl = {\n\t\tvalue: {},\n\t\toffset: 0,\n\t\tlength: 0,\n\t\ttype: 'object',\n\t\tparent: undefined\n\t};\n\tlet isAtPropertyKey = false;\n\tfunction setPreviousNode(value: string, offset: number, length: number, type: NodeType) {\n\t\tpreviousNodeInst.value = value;\n\t\tpreviousNodeInst.offset = offset;\n\t\tpreviousNodeInst.length = length;\n\t\tpreviousNodeInst.type = type;\n\t\tpreviousNodeInst.colonOffset = undefined;\n\t\tpreviousNode = previousNodeInst;\n\t}\n\ttry {\n\n\t\tvisit(text, {\n\t\t\tonObjectBegin: (offset: number, length: number) => {\n\t\t\t\tif (position <= offset) {\n\t\t\t\t\tthrow earlyReturnException;\n\t\t\t\t}\n\t\t\t\tpreviousNode = undefined;\n\t\t\t\tisAtPropertyKey = position > offset;\n\t\t\t\tsegments.push(''); // push a placeholder (will be replaced)\n\t\t\t},\n\t\t\tonObjectProperty: (name: string, offset: number, length: number) => {\n\t\t\t\tif (position < offset) {\n\t\t\t\t\tthrow earlyReturnException;\n\t\t\t\t}\n\t\t\t\tsetPreviousNode(name, offset, length, 'property');\n\t\t\t\tsegments[segments.length - 1] = name;\n\t\t\t\tif (position <= offset + length) {\n\t\t\t\t\tthrow earlyReturnException;\n\t\t\t\t}\n\t\t\t},\n\t\t\tonObjectEnd: (offset: number, length: number) => {\n\t\t\t\tif (position <= offset) {\n\t\t\t\t\tthrow earlyReturnException;\n\t\t\t\t}\n\t\t\t\tpreviousNode = undefined;\n\t\t\t\tsegments.pop();\n\t\t\t},\n\t\t\tonArrayBegin: (offset: number, length: number) => {\n\t\t\t\tif (position <= offset) {\n\t\t\t\t\tthrow earlyReturnException;\n\t\t\t\t}\n\t\t\t\tpreviousNode = undefined;\n\t\t\t\tsegments.push(0);\n\t\t\t},\n\t\t\tonArrayEnd: (offset: number, length: number) => {\n\t\t\t\tif (position <= offset) {\n\t\t\t\t\tthrow earlyReturnException;\n\t\t\t\t}\n\t\t\t\tpreviousNode = undefined;\n\t\t\t\tsegments.pop();\n\t\t\t},\n\t\t\tonLiteralValue: (value: any, offset: number, length: number) => {\n\t\t\t\tif (position < offset) {\n\t\t\t\t\tthrow earlyReturnException;\n\t\t\t\t}\n\t\t\t\tsetPreviousNode(value, offset, length, getNodeType(value));\n\n\t\t\t\tif (position <= offset + length) {\n\t\t\t\t\tthrow earlyReturnException;\n\t\t\t\t}\n\t\t\t},\n\t\t\tonSeparator: (sep: string, offset: number, length: number) => {\n\t\t\t\tif (position <= offset) {\n\t\t\t\t\tthrow earlyReturnException;\n\t\t\t\t}\n\t\t\t\tif (sep === ':' && previousNode && previousNode.type === 'property') {\n\t\t\t\t\tpreviousNode.colonOffset = offset;\n\t\t\t\t\tisAtPropertyKey = false;\n\t\t\t\t\tpreviousNode = undefined;\n\t\t\t\t} else if (sep === ',') {\n\t\t\t\t\tconst last = segments[segments.length - 1];\n\t\t\t\t\tif (typeof last === 'number') {\n\t\t\t\t\t\tsegments[segments.length - 1] = last + 1;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tisAtPropertyKey = true;\n\t\t\t\t\t\tsegments[segments.length - 1] = '';\n\t\t\t\t\t}\n\t\t\t\t\tpreviousNode = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t} catch (e) {\n\t\tif (e !== earlyReturnException) {\n\t\t\tthrow e;\n\t\t}\n\t}\n\n\treturn {\n\t\tpath: segments,\n\t\tpreviousNode,\n\t\tisAtPropertyKey,\n\t\tmatches: (pattern: Segment[]) => {\n\t\t\tlet k = 0;\n\t\t\tfor (let i = 0; k < pattern.length && i < segments.length; i++) {\n\t\t\t\tif (pattern[k] === segments[i] || pattern[k] === '*') {\n\t\t\t\t\tk++;\n\t\t\t\t} else if (pattern[k] !== '**') {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn k === pattern.length;\n\t\t}\n\t};\n}\n\n\n/**\n * Parses the given text and returns the object the JSON content represents. On invalid input, the parser tries to be as fault tolerant as possible, but still return a result.\n * Therefore always check the errors list to find out if the input was valid.\n */\nexport function parse(text: string, errors: ParseError[] = [], options: ParseOptions = ParseOptions.DEFAULT): any {\n\tlet currentProperty: string | null = null;\n\tlet currentParent: any = [];\n\tconst previousParents: any[] = [];\n\n\tfunction onValue(value: any) {\n\t\tif (Array.isArray(currentParent)) {\n\t\t\t(currentParent).push(value);\n\t\t} else if (currentProperty !== null) {\n\t\t\tcurrentParent[currentProperty] = value;\n\t\t}\n\t}\n\n\tconst visitor: JSONVisitor = {\n\t\tonObjectBegin: () => {\n\t\t\tconst object = {};\n\t\t\tonValue(object);\n\t\t\tpreviousParents.push(currentParent);\n\t\t\tcurrentParent = object;\n\t\t\tcurrentProperty = null;\n\t\t},\n\t\tonObjectProperty: (name: string) => {\n\t\t\tcurrentProperty = name;\n\t\t},\n\t\tonObjectEnd: () => {\n\t\t\tcurrentParent = previousParents.pop();\n\t\t},\n\t\tonArrayBegin: () => {\n\t\t\tconst array: any[] = [];\n\t\t\tonValue(array);\n\t\t\tpreviousParents.push(currentParent);\n\t\t\tcurrentParent = array;\n\t\t\tcurrentProperty = null;\n\t\t},\n\t\tonArrayEnd: () => {\n\t\t\tcurrentParent = previousParents.pop();\n\t\t},\n\t\tonLiteralValue: onValue,\n\t\tonError: (error: ParseErrorCode, offset: number, length: number) => {\n\t\t\terrors.push({ error, offset, length });\n\t\t}\n\t};\n\tvisit(text, visitor, options);\n\treturn currentParent[0];\n}\n\n\n/**\n * Parses the given text and returns a tree representation the JSON content. On invalid input, the parser tries to be as fault tolerant as possible, but still return a result.\n */\nexport function parseTree(text: string, errors: ParseError[] = [], options: ParseOptions = ParseOptions.DEFAULT): Node {\n\tlet currentParent: NodeImpl = { type: 'array', offset: -1, length: -1, children: [], parent: undefined }; // artificial root\n\n\tfunction ensurePropertyComplete(endOffset: number) {\n\t\tif (currentParent.type === 'property') {\n\t\t\tcurrentParent.length = endOffset - currentParent.offset;\n\t\t\tcurrentParent = currentParent.parent!;\n\t\t}\n\t}\n\n\tfunction onValue(valueNode: Node): Node {\n\t\tcurrentParent.children!.push(valueNode);\n\t\treturn valueNode;\n\t}\n\n\tconst visitor: JSONVisitor = {\n\t\tonObjectBegin: (offset: number) => {\n\t\t\tcurrentParent = onValue({ type: 'object', offset, length: -1, parent: currentParent, children: [] });\n\t\t},\n\t\tonObjectProperty: (name: string, offset: number, length: number) => {\n\t\t\tcurrentParent = onValue({ type: 'property', offset, length: -1, parent: currentParent, children: [] });\n\t\t\tcurrentParent.children!.push({ type: 'string', value: name, offset, length, parent: currentParent });\n\t\t},\n\t\tonObjectEnd: (offset: number, length: number) => {\n\t\t\tcurrentParent.length = offset + length - currentParent.offset;\n\t\t\tcurrentParent = currentParent.parent!;\n\t\t\tensurePropertyComplete(offset + length);\n\t\t},\n\t\tonArrayBegin: (offset: number, length: number) => {\n\t\t\tcurrentParent = onValue({ type: 'array', offset, length: -1, parent: currentParent, children: [] });\n\t\t},\n\t\tonArrayEnd: (offset: number, length: number) => {\n\t\t\tcurrentParent.length = offset + length - currentParent.offset;\n\t\t\tcurrentParent = currentParent.parent!;\n\t\t\tensurePropertyComplete(offset + length);\n\t\t},\n\t\tonLiteralValue: (value: any, offset: number, length: number) => {\n\t\t\tonValue({ type: getNodeType(value), offset, length, parent: currentParent, value });\n\t\t\tensurePropertyComplete(offset + length);\n\t\t},\n\t\tonSeparator: (sep: string, offset: number, length: number) => {\n\t\t\tif (currentParent.type === 'property') {\n\t\t\t\tif (sep === ':') {\n\t\t\t\t\tcurrentParent.colonOffset = offset;\n\t\t\t\t} else if (sep === ',') {\n\t\t\t\t\tensurePropertyComplete(offset);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tonError: (error: ParseErrorCode, offset: number, length: number) => {\n\t\t\terrors.push({ error, offset, length });\n\t\t}\n\t};\n\tvisit(text, visitor, options);\n\n\tconst result = currentParent.children![0];\n\tif (result) {\n\t\tdelete result.parent;\n\t}\n\treturn result;\n}\n\n/**\n * Finds the node at the given path in a JSON DOM.\n */\nexport function findNodeAtLocation(root: Node, path: JSONPath): Node | undefined {\n\tif (!root) {\n\t\treturn undefined;\n\t}\n\tlet node = root;\n\tfor (const segment of path) {\n\t\tif (typeof segment === 'string') {\n\t\t\tif (node.type !== 'object' || !Array.isArray(node.children)) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tlet found = false;\n\t\t\tfor (const propertyNode of node.children) {\n\t\t\t\tif (Array.isArray(propertyNode.children) && propertyNode.children[0].value === segment) {\n\t\t\t\t\tnode = propertyNode.children[1];\n\t\t\t\t\tfound = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!found) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t} else {\n\t\t\tconst index = segment;\n\t\t\tif (node.type !== 'array' || index < 0 || !Array.isArray(node.children) || index >= node.children.length) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tnode = node.children[index];\n\t\t}\n\t}\n\treturn node;\n}\n\n/**\n * Gets the JSON path of the given JSON DOM node\n */\nexport function getNodePath(node: Node): JSONPath {\n\tif (!node.parent || !node.parent.children) {\n\t\treturn [];\n\t}\n\tconst path = getNodePath(node.parent);\n\tif (node.parent.type === 'property') {\n\t\tconst key = node.parent.children[0].value;\n\t\tpath.push(key);\n\t} else if (node.parent.type === 'array') {\n\t\tconst index = node.parent.children.indexOf(node);\n\t\tif (index !== -1) {\n\t\t\tpath.push(index);\n\t\t}\n\t}\n\treturn path;\n}\n\n/**\n * Evaluates the JavaScript object of the given JSON DOM node\n */\nexport function getNodeValue(node: Node): any {\n\tswitch (node.type) {\n\t\tcase 'array':\n\t\t\treturn node.children!.map(getNodeValue);\n\t\tcase 'object': {\n\t\t\tconst obj = Object.create(null);\n\t\t\tfor (const prop of node.children!) {\n\t\t\t\tconst valueNode = prop.children![1];\n\t\t\t\tif (valueNode) {\n\t\t\t\t\tobj[prop.children![0].value] = getNodeValue(valueNode);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn obj;\n\t\t}\n\t\tcase 'null':\n\t\tcase 'string':\n\t\tcase 'number':\n\t\tcase 'boolean':\n\t\t\treturn node.value;\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n\n}\n\nexport function contains(node: Node, offset: number, includeRightBound = false): boolean {\n\treturn (offset >= node.offset && offset < (node.offset + node.length)) || includeRightBound && (offset === (node.offset + node.length));\n}\n\n/**\n * Finds the most inner node at the given offset. If includeRightBound is set, also finds nodes that end at the given offset.\n */\nexport function findNodeAtOffset(node: Node, offset: number, includeRightBound = false): Node | undefined {\n\tif (contains(node, offset, includeRightBound)) {\n\t\tconst children = node.children;\n\t\tif (Array.isArray(children)) {\n\t\t\tfor (let i = 0; i < children.length && children[i].offset <= offset; i++) {\n\t\t\t\tconst item = findNodeAtOffset(children[i], offset, includeRightBound);\n\t\t\t\tif (item) {\n\t\t\t\t\treturn item;\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\t\treturn node;\n\t}\n\treturn undefined;\n}\n\n\n/**\n * Parses the given text and invokes the visitor functions for each object, array and literal reached.\n */\nexport function visit(text: string, visitor: JSONVisitor, options: ParseOptions = ParseOptions.DEFAULT): any {\n\n\tconst _scanner = createScanner(text, false);\n\n\tfunction toNoArgVisit(visitFunction?: (offset: number, length: number) => void): () => void {\n\t\treturn visitFunction ? () => visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength()) : () => true;\n\t}\n\tfunction toOneArgVisit(visitFunction?: (arg: T, offset: number, length: number) => void): (arg: T) => void {\n\t\treturn visitFunction ? (arg: T) => visitFunction(arg, _scanner.getTokenOffset(), _scanner.getTokenLength()) : () => true;\n\t}\n\n\tconst onObjectBegin = toNoArgVisit(visitor.onObjectBegin),\n\t\tonObjectProperty = toOneArgVisit(visitor.onObjectProperty),\n\t\tonObjectEnd = toNoArgVisit(visitor.onObjectEnd),\n\t\tonArrayBegin = toNoArgVisit(visitor.onArrayBegin),\n\t\tonArrayEnd = toNoArgVisit(visitor.onArrayEnd),\n\t\tonLiteralValue = toOneArgVisit(visitor.onLiteralValue),\n\t\tonSeparator = toOneArgVisit(visitor.onSeparator),\n\t\tonComment = toNoArgVisit(visitor.onComment),\n\t\tonError = toOneArgVisit(visitor.onError);\n\n\tconst disallowComments = options && options.disallowComments;\n\tconst allowTrailingComma = options && options.allowTrailingComma;\n\tfunction scanNext(): SyntaxKind {\n\t\twhile (true) {\n\t\t\tconst token = _scanner.scan();\n\t\t\tswitch (_scanner.getTokenError()) {\n\t\t\t\tcase ScanError.InvalidUnicode:\n\t\t\t\t\thandleError(ParseErrorCode.InvalidUnicode);\n\t\t\t\t\tbreak;\n\t\t\t\tcase ScanError.InvalidEscapeCharacter:\n\t\t\t\t\thandleError(ParseErrorCode.InvalidEscapeCharacter);\n\t\t\t\t\tbreak;\n\t\t\t\tcase ScanError.UnexpectedEndOfNumber:\n\t\t\t\t\thandleError(ParseErrorCode.UnexpectedEndOfNumber);\n\t\t\t\t\tbreak;\n\t\t\t\tcase ScanError.UnexpectedEndOfComment:\n\t\t\t\t\tif (!disallowComments) {\n\t\t\t\t\t\thandleError(ParseErrorCode.UnexpectedEndOfComment);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase ScanError.UnexpectedEndOfString:\n\t\t\t\t\thandleError(ParseErrorCode.UnexpectedEndOfString);\n\t\t\t\t\tbreak;\n\t\t\t\tcase ScanError.InvalidCharacter:\n\t\t\t\t\thandleError(ParseErrorCode.InvalidCharacter);\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tswitch (token) {\n\t\t\t\tcase SyntaxKind.LineCommentTrivia:\n\t\t\t\tcase SyntaxKind.BlockCommentTrivia:\n\t\t\t\t\tif (disallowComments) {\n\t\t\t\t\t\thandleError(ParseErrorCode.InvalidCommentToken);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tonComment();\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase SyntaxKind.Unknown:\n\t\t\t\t\thandleError(ParseErrorCode.InvalidSymbol);\n\t\t\t\t\tbreak;\n\t\t\t\tcase SyntaxKind.Trivia:\n\t\t\t\tcase SyntaxKind.LineBreakTrivia:\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\treturn token;\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction handleError(error: ParseErrorCode, skipUntilAfter: SyntaxKind[] = [], skipUntil: SyntaxKind[] = []): void {\n\t\tonError(error);\n\t\tif (skipUntilAfter.length + skipUntil.length > 0) {\n\t\t\tlet token = _scanner.getToken();\n\t\t\twhile (token !== SyntaxKind.EOF) {\n\t\t\t\tif (skipUntilAfter.indexOf(token) !== -1) {\n\t\t\t\t\tscanNext();\n\t\t\t\t\tbreak;\n\t\t\t\t} else if (skipUntil.indexOf(token) !== -1) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\ttoken = scanNext();\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction parseString(isValue: boolean): boolean {\n\t\tconst value = _scanner.getTokenValue();\n\t\tif (isValue) {\n\t\t\tonLiteralValue(value);\n\t\t} else {\n\t\t\tonObjectProperty(value);\n\t\t}\n\t\tscanNext();\n\t\treturn true;\n\t}\n\n\tfunction parseLiteral(): boolean {\n\t\tswitch (_scanner.getToken()) {\n\t\t\tcase SyntaxKind.NumericLiteral: {\n\t\t\t\tlet value = 0;\n\t\t\t\ttry {\n\t\t\t\t\tvalue = JSON.parse(_scanner.getTokenValue());\n\t\t\t\t\tif (typeof value !== 'number') {\n\t\t\t\t\t\thandleError(ParseErrorCode.InvalidNumberFormat);\n\t\t\t\t\t\tvalue = 0;\n\t\t\t\t\t}\n\t\t\t\t} catch (e) {\n\t\t\t\t\thandleError(ParseErrorCode.InvalidNumberFormat);\n\t\t\t\t}\n\t\t\t\tonLiteralValue(value);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase SyntaxKind.NullKeyword:\n\t\t\t\tonLiteralValue(null);\n\t\t\t\tbreak;\n\t\t\tcase SyntaxKind.TrueKeyword:\n\t\t\t\tonLiteralValue(true);\n\t\t\t\tbreak;\n\t\t\tcase SyntaxKind.FalseKeyword:\n\t\t\t\tonLiteralValue(false);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\treturn false;\n\t\t}\n\t\tscanNext();\n\t\treturn true;\n\t}\n\n\tfunction parseProperty(): boolean {\n\t\tif (_scanner.getToken() !== SyntaxKind.StringLiteral) {\n\t\t\thandleError(ParseErrorCode.PropertyNameExpected, [], [SyntaxKind.CloseBraceToken, SyntaxKind.CommaToken]);\n\t\t\treturn false;\n\t\t}\n\t\tparseString(false);\n\t\tif (_scanner.getToken() === SyntaxKind.ColonToken) {\n\t\t\tonSeparator(':');\n\t\t\tscanNext(); // consume colon\n\n\t\t\tif (!parseValue()) {\n\t\t\t\thandleError(ParseErrorCode.ValueExpected, [], [SyntaxKind.CloseBraceToken, SyntaxKind.CommaToken]);\n\t\t\t}\n\t\t} else {\n\t\t\thandleError(ParseErrorCode.ColonExpected, [], [SyntaxKind.CloseBraceToken, SyntaxKind.CommaToken]);\n\t\t}\n\t\treturn true;\n\t}\n\n\tfunction parseObject(): boolean {\n\t\tonObjectBegin();\n\t\tscanNext(); // consume open brace\n\n\t\tlet needsComma = false;\n\t\twhile (_scanner.getToken() !== SyntaxKind.CloseBraceToken && _scanner.getToken() !== SyntaxKind.EOF) {\n\t\t\tif (_scanner.getToken() === SyntaxKind.CommaToken) {\n\t\t\t\tif (!needsComma) {\n\t\t\t\t\thandleError(ParseErrorCode.ValueExpected, [], []);\n\t\t\t\t}\n\t\t\t\tonSeparator(',');\n\t\t\t\tscanNext(); // consume comma\n\t\t\t\tif (_scanner.getToken() === SyntaxKind.CloseBraceToken && allowTrailingComma) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else if (needsComma) {\n\t\t\t\thandleError(ParseErrorCode.CommaExpected, [], []);\n\t\t\t}\n\t\t\tif (!parseProperty()) {\n\t\t\t\thandleError(ParseErrorCode.ValueExpected, [], [SyntaxKind.CloseBraceToken, SyntaxKind.CommaToken]);\n\t\t\t}\n\t\t\tneedsComma = true;\n\t\t}\n\t\tonObjectEnd();\n\t\tif (_scanner.getToken() !== SyntaxKind.CloseBraceToken) {\n\t\t\thandleError(ParseErrorCode.CloseBraceExpected, [SyntaxKind.CloseBraceToken], []);\n\t\t} else {\n\t\t\tscanNext(); // consume close brace\n\t\t}\n\t\treturn true;\n\t}\n\n\tfunction parseArray(): boolean {\n\t\tonArrayBegin();\n\t\tscanNext(); // consume open bracket\n\n\t\tlet needsComma = false;\n\t\twhile (_scanner.getToken() !== SyntaxKind.CloseBracketToken && _scanner.getToken() !== SyntaxKind.EOF) {\n\t\t\tif (_scanner.getToken() === SyntaxKind.CommaToken) {\n\t\t\t\tif (!needsComma) {\n\t\t\t\t\thandleError(ParseErrorCode.ValueExpected, [], []);\n\t\t\t\t}\n\t\t\t\tonSeparator(',');\n\t\t\t\tscanNext(); // consume comma\n\t\t\t\tif (_scanner.getToken() === SyntaxKind.CloseBracketToken && allowTrailingComma) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else if (needsComma) {\n\t\t\t\thandleError(ParseErrorCode.CommaExpected, [], []);\n\t\t\t}\n\t\t\tif (!parseValue()) {\n\t\t\t\thandleError(ParseErrorCode.ValueExpected, [], [SyntaxKind.CloseBracketToken, SyntaxKind.CommaToken]);\n\t\t\t}\n\t\t\tneedsComma = true;\n\t\t}\n\t\tonArrayEnd();\n\t\tif (_scanner.getToken() !== SyntaxKind.CloseBracketToken) {\n\t\t\thandleError(ParseErrorCode.CloseBracketExpected, [SyntaxKind.CloseBracketToken], []);\n\t\t} else {\n\t\t\tscanNext(); // consume close bracket\n\t\t}\n\t\treturn true;\n\t}\n\n\tfunction parseValue(): boolean {\n\t\tswitch (_scanner.getToken()) {\n\t\t\tcase SyntaxKind.OpenBracketToken:\n\t\t\t\treturn parseArray();\n\t\t\tcase SyntaxKind.OpenBraceToken:\n\t\t\t\treturn parseObject();\n\t\t\tcase SyntaxKind.StringLiteral:\n\t\t\t\treturn parseString(true);\n\t\t\tdefault:\n\t\t\t\treturn parseLiteral();\n\t\t}\n\t}\n\n\tscanNext();\n\tif (_scanner.getToken() === SyntaxKind.EOF) {\n\t\tif (options.allowEmptyContent) {\n\t\t\treturn true;\n\t\t}\n\t\thandleError(ParseErrorCode.ValueExpected, [], []);\n\t\treturn false;\n\t}\n\tif (!parseValue()) {\n\t\thandleError(ParseErrorCode.ValueExpected, [], []);\n\t\treturn false;\n\t}\n\tif (_scanner.getToken() !== SyntaxKind.EOF) {\n\t\thandleError(ParseErrorCode.EndOfFileExpected, [], []);\n\t}\n\treturn true;\n}\n\n/**\n * Takes JSON with JavaScript-style comments and remove\n * them. Optionally replaces every none-newline character\n * of comments with a replaceCharacter\n */\nexport function stripComments(text: string, replaceCh?: string): string {\n\n\tconst _scanner = createScanner(text);\n\tconst parts: string[] = [];\n\tlet kind: SyntaxKind;\n\tlet offset = 0;\n\tlet pos: number;\n\n\tdo {\n\t\tpos = _scanner.getPosition();\n\t\tkind = _scanner.scan();\n\t\tswitch (kind) {\n\t\t\tcase SyntaxKind.LineCommentTrivia:\n\t\t\tcase SyntaxKind.BlockCommentTrivia:\n\t\t\tcase SyntaxKind.EOF:\n\t\t\t\tif (offset !== pos) {\n\t\t\t\t\tparts.push(text.substring(offset, pos));\n\t\t\t\t}\n\t\t\t\tif (replaceCh !== undefined) {\n\t\t\t\t\tparts.push(_scanner.getTokenValue().replace(/[^\\r\\n]/g, replaceCh));\n\t\t\t\t}\n\t\t\t\toffset = _scanner.getPosition();\n\t\t\t\tbreak;\n\t\t}\n\t} while (kind !== SyntaxKind.EOF);\n\n\treturn parts.join('');\n}\n\nexport function getNodeType(value: any): NodeType {\n\tswitch (typeof value) {\n\t\tcase 'boolean': return 'boolean';\n\t\tcase 'number': return 'number';\n\t\tcase 'string': return 'string';\n\t\tcase 'object': {\n\t\t\tif (!value) {\n\t\t\t\treturn 'null';\n\t\t\t} else if (Array.isArray(value)) {\n\t\t\t\treturn 'array';\n\t\t\t}\n\t\t\treturn 'object';\n\t\t}\n\t\tdefault: return '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 { createScanner, ScanError, SyntaxKind } from './json';\n\nexport interface FormattingOptions {\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\t/**\n\t * The default 'end of line' character. If not set, '\\n' is used as default.\n\t */\n\teol?: string;\n}\n\n/**\n * Represents a text modification\n */\nexport interface Edit {\n\t/**\n\t * The start offset of the modification.\n\t */\n\toffset: number;\n\t/**\n\t * The length of the modification. Must not be negative. Empty length represents an *insert*.\n\t */\n\tlength: number;\n\t/**\n\t * The new content. Empty content represents a *remove*.\n\t */\n\tcontent: string;\n}\n\n/**\n * A text range in the document\n*/\nexport interface Range {\n\t/**\n\t * The start offset of the range.\n\t */\n\toffset: number;\n\t/**\n\t * The length of the range. Must not be negative.\n\t */\n\tlength: number;\n}\n\n\nexport function format(documentText: string, range: Range | undefined, options: FormattingOptions): Edit[] {\n\tlet initialIndentLevel: number;\n\tlet formatText: string;\n\tlet formatTextStart: number;\n\tlet rangeStart: number;\n\tlet rangeEnd: number;\n\tif (range) {\n\t\trangeStart = range.offset;\n\t\trangeEnd = rangeStart + range.length;\n\n\t\tformatTextStart = rangeStart;\n\t\twhile (formatTextStart > 0 && !isEOL(documentText, formatTextStart - 1)) {\n\t\t\tformatTextStart--;\n\t\t}\n\t\tlet endOffset = rangeEnd;\n\t\twhile (endOffset < documentText.length && !isEOL(documentText, endOffset)) {\n\t\t\tendOffset++;\n\t\t}\n\t\tformatText = documentText.substring(formatTextStart, endOffset);\n\t\tinitialIndentLevel = computeIndentLevel(formatText, options);\n\t} else {\n\t\tformatText = documentText;\n\t\tinitialIndentLevel = 0;\n\t\tformatTextStart = 0;\n\t\trangeStart = 0;\n\t\trangeEnd = documentText.length;\n\t}\n\tconst eol = getEOL(options, documentText);\n\n\tlet lineBreak = false;\n\tlet indentLevel = 0;\n\tlet indentValue: string;\n\tif (options.insertSpaces) {\n\t\tindentValue = repeat(' ', options.tabSize || 4);\n\t} else {\n\t\tindentValue = '\\t';\n\t}\n\n\tconst scanner = createScanner(formatText, false);\n\tlet hasError = false;\n\n\tfunction newLineAndIndent(): string {\n\t\treturn eol + repeat(indentValue, initialIndentLevel + indentLevel);\n\t}\n\tfunction scanNext(): SyntaxKind {\n\t\tlet token = scanner.scan();\n\t\tlineBreak = false;\n\t\twhile (token === SyntaxKind.Trivia || token === SyntaxKind.LineBreakTrivia) {\n\t\t\tlineBreak = lineBreak || (token === SyntaxKind.LineBreakTrivia);\n\t\t\ttoken = scanner.scan();\n\t\t}\n\t\thasError = token === SyntaxKind.Unknown || scanner.getTokenError() !== ScanError.None;\n\t\treturn token;\n\t}\n\tconst editOperations: Edit[] = [];\n\tfunction addEdit(text: string, startOffset: number, endOffset: number) {\n\t\tif (!hasError && startOffset < rangeEnd && endOffset > rangeStart && documentText.substring(startOffset, endOffset) !== text) {\n\t\t\teditOperations.push({ offset: startOffset, length: endOffset - startOffset, content: text });\n\t\t}\n\t}\n\n\tlet firstToken = scanNext();\n\n\tif (firstToken !== SyntaxKind.EOF) {\n\t\tconst firstTokenStart = scanner.getTokenOffset() + formatTextStart;\n\t\tconst initialIndent = repeat(indentValue, initialIndentLevel);\n\t\taddEdit(initialIndent, formatTextStart, firstTokenStart);\n\t}\n\n\twhile (firstToken !== SyntaxKind.EOF) {\n\t\tlet firstTokenEnd = scanner.getTokenOffset() + scanner.getTokenLength() + formatTextStart;\n\t\tlet secondToken = scanNext();\n\n\t\tlet replaceContent = '';\n\t\twhile (!lineBreak && (secondToken === SyntaxKind.LineCommentTrivia || secondToken === SyntaxKind.BlockCommentTrivia)) {\n\t\t\t// comments on the same line: keep them on the same line, but ignore them otherwise\n\t\t\tconst commentTokenStart = scanner.getTokenOffset() + formatTextStart;\n\t\t\taddEdit(' ', firstTokenEnd, commentTokenStart);\n\t\t\tfirstTokenEnd = scanner.getTokenOffset() + scanner.getTokenLength() + formatTextStart;\n\t\t\treplaceContent = secondToken === SyntaxKind.LineCommentTrivia ? newLineAndIndent() : '';\n\t\t\tsecondToken = scanNext();\n\t\t}\n\n\t\tif (secondToken === SyntaxKind.CloseBraceToken) {\n\t\t\tif (firstToken !== SyntaxKind.OpenBraceToken) {\n\t\t\t\tindentLevel--;\n\t\t\t\treplaceContent = newLineAndIndent();\n\t\t\t}\n\t\t} else if (secondToken === SyntaxKind.CloseBracketToken) {\n\t\t\tif (firstToken !== SyntaxKind.OpenBracketToken) {\n\t\t\t\tindentLevel--;\n\t\t\t\treplaceContent = newLineAndIndent();\n\t\t\t}\n\t\t} else {\n\t\t\tswitch (firstToken) {\n\t\t\t\tcase SyntaxKind.OpenBracketToken:\n\t\t\t\tcase SyntaxKind.OpenBraceToken:\n\t\t\t\t\tindentLevel++;\n\t\t\t\t\treplaceContent = newLineAndIndent();\n\t\t\t\t\tbreak;\n\t\t\t\tcase SyntaxKind.CommaToken:\n\t\t\t\tcase SyntaxKind.LineCommentTrivia:\n\t\t\t\t\treplaceContent = newLineAndIndent();\n\t\t\t\t\tbreak;\n\t\t\t\tcase SyntaxKind.BlockCommentTrivia:\n\t\t\t\t\tif (lineBreak) {\n\t\t\t\t\t\treplaceContent = newLineAndIndent();\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// symbol following comment on the same line: keep on same line, separate with ' '\n\t\t\t\t\t\treplaceContent = ' ';\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase SyntaxKind.ColonToken:\n\t\t\t\t\treplaceContent = ' ';\n\t\t\t\t\tbreak;\n\t\t\t\tcase SyntaxKind.StringLiteral:\n\t\t\t\t\tif (secondToken === SyntaxKind.ColonToken) {\n\t\t\t\t\t\treplaceContent = '';\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t// fall through\n\t\t\t\tcase SyntaxKind.NullKeyword:\n\t\t\t\tcase SyntaxKind.TrueKeyword:\n\t\t\t\tcase SyntaxKind.FalseKeyword:\n\t\t\t\tcase SyntaxKind.NumericLiteral:\n\t\t\t\tcase SyntaxKind.CloseBraceToken:\n\t\t\t\tcase SyntaxKind.CloseBracketToken:\n\t\t\t\t\tif (secondToken === SyntaxKind.LineCommentTrivia || secondToken === SyntaxKind.BlockCommentTrivia) {\n\t\t\t\t\t\treplaceContent = ' ';\n\t\t\t\t\t} else if (secondToken !== SyntaxKind.CommaToken && secondToken !== SyntaxKind.EOF) {\n\t\t\t\t\t\thasError = true;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase SyntaxKind.Unknown:\n\t\t\t\t\thasError = true;\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (lineBreak && (secondToken === SyntaxKind.LineCommentTrivia || secondToken === SyntaxKind.BlockCommentTrivia)) {\n\t\t\t\treplaceContent = newLineAndIndent();\n\t\t\t}\n\n\t\t}\n\t\tconst secondTokenStart = scanner.getTokenOffset() + formatTextStart;\n\t\taddEdit(replaceContent, firstTokenEnd, secondTokenStart);\n\t\tfirstToken = secondToken;\n\t}\n\treturn editOperations;\n}\n\n/**\n * Creates a formatted string out of the object passed as argument, using the given formatting options\n * @param any The object to stringify and format\n * @param options The formatting options to use\n */\nexport function toFormattedString(obj: any, options: FormattingOptions) {\n\tconst content = JSON.stringify(obj, undefined, options.insertSpaces ? options.tabSize || 4 : '\\t');\n\tif (options.eol !== undefined) {\n\t\treturn content.replace(/\\r\\n|\\r|\\n/g, options.eol);\n\t}\n\treturn content;\n}\n\nfunction repeat(s: string, count: number): string {\n\tlet result = '';\n\tfor (let i = 0; i < count; i++) {\n\t\tresult += s;\n\t}\n\treturn result;\n}\n\nfunction computeIndentLevel(content: string, options: FormattingOptions): number {\n\tlet i = 0;\n\tlet nChars = 0;\n\tconst tabSize = options.tabSize || 4;\n\twhile (i < content.length) {\n\t\tconst ch = content.charAt(i);\n\t\tif (ch === ' ') {\n\t\t\tnChars++;\n\t\t} else if (ch === '\\t') {\n\t\t\tnChars += tabSize;\n\t\t} else {\n\t\t\tbreak;\n\t\t}\n\t\ti++;\n\t}\n\treturn Math.floor(nChars / tabSize);\n}\n\nexport function getEOL(options: FormattingOptions, text: string): string {\n\tfor (let i = 0; i < text.length; i++) {\n\t\tconst ch = text.charAt(i);\n\t\tif (ch === '\\r') {\n\t\t\tif (i + 1 < text.length && text.charAt(i + 1) === '\\n') {\n\t\t\t\treturn '\\r\\n';\n\t\t\t}\n\t\t\treturn '\\r';\n\t\t} else if (ch === '\\n') {\n\t\t\treturn '\\n';\n\t\t}\n\t}\n\treturn (options && options.eol) || '\\n';\n}\n\nexport function isEOL(text: string, offset: number) {\n\treturn '\\r\\n'.indexOf(text.charAt(offset)) !== -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 { findNodeAtLocation, JSONPath, Node, ParseError, parseTree, Segment } from './json';\nimport { Edit, format, FormattingOptions, isEOL } from './jsonFormatter';\n\n\nexport function removeProperty(text: string, path: JSONPath, formattingOptions: FormattingOptions): Edit[] {\n\treturn setProperty(text, path, undefined, formattingOptions);\n}\n\nexport function setProperty(text: string, originalPath: JSONPath, value: any, formattingOptions: FormattingOptions, getInsertionIndex?: (properties: string[]) => number): Edit[] {\n\tconst path = originalPath.slice();\n\tconst errors: ParseError[] = [];\n\tconst root = parseTree(text, errors);\n\tlet parent: Node | undefined = undefined;\n\n\tlet lastSegment: Segment | undefined = undefined;\n\twhile (path.length > 0) {\n\t\tlastSegment = path.pop();\n\t\tparent = findNodeAtLocation(root, path);\n\t\tif (parent === undefined && value !== undefined) {\n\t\t\tif (typeof lastSegment === 'string') {\n\t\t\t\tvalue = { [lastSegment]: value };\n\t\t\t} else {\n\t\t\t\tvalue = [value];\n\t\t\t}\n\t\t} else {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (!parent) {\n\t\t// empty document\n\t\tif (value === undefined) { // delete\n\t\t\tthrow new Error('Can not delete in empty document');\n\t\t}\n\t\treturn withFormatting(text, { offset: root ? root.offset : 0, length: root ? root.length : 0, content: JSON.stringify(value) }, formattingOptions);\n\t} else if (parent.type === 'object' && typeof lastSegment === 'string' && Array.isArray(parent.children)) {\n\t\tconst existing = findNodeAtLocation(parent, [lastSegment]);\n\t\tif (existing !== undefined) {\n\t\t\tif (value === undefined) { // delete\n\t\t\t\tif (!existing.parent) {\n\t\t\t\t\tthrow new Error('Malformed AST');\n\t\t\t\t}\n\t\t\t\tconst propertyIndex = parent.children.indexOf(existing.parent);\n\t\t\t\tlet removeBegin: number;\n\t\t\t\tlet removeEnd = existing.parent.offset + existing.parent.length;\n\t\t\t\tif (propertyIndex > 0) {\n\t\t\t\t\t// remove the comma of the previous node\n\t\t\t\t\tconst previous = parent.children[propertyIndex - 1];\n\t\t\t\t\tremoveBegin = previous.offset + previous.length;\n\t\t\t\t} else {\n\t\t\t\t\tremoveBegin = parent.offset + 1;\n\t\t\t\t\tif (parent.children.length > 1) {\n\t\t\t\t\t\t// remove the comma of the next node\n\t\t\t\t\t\tconst next = parent.children[1];\n\t\t\t\t\t\tremoveEnd = next.offset;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn withFormatting(text, { offset: removeBegin, length: removeEnd - removeBegin, content: '' }, formattingOptions);\n\t\t\t} else {\n\t\t\t\t// set value of existing property\n\t\t\t\treturn withFormatting(text, { offset: existing.offset, length: existing.length, content: JSON.stringify(value) }, formattingOptions);\n\t\t\t}\n\t\t} else {\n\t\t\tif (value === undefined) { // delete\n\t\t\t\treturn []; // property does not exist, nothing to do\n\t\t\t}\n\t\t\tconst newProperty = `${JSON.stringify(lastSegment)}: ${JSON.stringify(value)}`;\n\t\t\tconst index = getInsertionIndex ? getInsertionIndex(parent.children.map(p => p.children![0].value)) : parent.children.length;\n\t\t\tlet edit: Edit;\n\t\t\tif (index > 0) {\n\t\t\t\tconst previous = parent.children[index - 1];\n\t\t\t\tedit = { offset: previous.offset + previous.length, length: 0, content: ',' + newProperty };\n\t\t\t} else if (parent.children.length === 0) {\n\t\t\t\tedit = { offset: parent.offset + 1, length: 0, content: newProperty };\n\t\t\t} else {\n\t\t\t\tedit = { offset: parent.offset + 1, length: 0, content: newProperty + ',' };\n\t\t\t}\n\t\t\treturn withFormatting(text, edit, formattingOptions);\n\t\t}\n\t} else if (parent.type === 'array' && typeof lastSegment === 'number' && Array.isArray(parent.children)) {\n\t\tif (value !== undefined) {\n\t\t\t// Insert\n\t\t\tconst newProperty = `${JSON.stringify(value)}`;\n\t\t\tlet edit: Edit;\n\t\t\tif (parent.children.length === 0 || lastSegment === 0) {\n\t\t\t\tedit = { offset: parent.offset + 1, length: 0, content: parent.children.length === 0 ? newProperty : newProperty + ',' };\n\t\t\t} else {\n\t\t\t\tconst index = lastSegment === -1 || lastSegment > parent.children.length ? parent.children.length : lastSegment;\n\t\t\t\tconst previous = parent.children[index - 1];\n\t\t\t\tedit = { offset: previous.offset + previous.length, length: 0, content: ',' + newProperty };\n\t\t\t}\n\t\t\treturn withFormatting(text, edit, formattingOptions);\n\t\t} else {\n\t\t\t//Removal\n\t\t\tconst removalIndex = lastSegment;\n\t\t\tconst toRemove = parent.children[removalIndex];\n\t\t\tlet edit: Edit;\n\t\t\tif (parent.children.length === 1) {\n\t\t\t\t// only item\n\t\t\t\tedit = { offset: parent.offset + 1, length: parent.length - 2, content: '' };\n\t\t\t} else if (parent.children.length - 1 === removalIndex) {\n\t\t\t\t// last item\n\t\t\t\tconst previous = parent.children[removalIndex - 1];\n\t\t\t\tconst offset = previous.offset + previous.length;\n\t\t\t\tconst parentEndOffset = parent.offset + parent.length;\n\t\t\t\tedit = { offset, length: parentEndOffset - 2 - offset, content: '' };\n\t\t\t} else {\n\t\t\t\tedit = { offset: toRemove.offset, length: parent.children[removalIndex + 1].offset - toRemove.offset, content: '' };\n\t\t\t}\n\t\t\treturn withFormatting(text, edit, formattingOptions);\n\t\t}\n\t} else {\n\t\tthrow new Error(`Can not add ${typeof lastSegment !== 'number' ? 'index' : 'property'} to parent of type ${parent.type}`);\n\t}\n}\n\nexport function withFormatting(text: string, edit: Edit, formattingOptions: FormattingOptions): Edit[] {\n\t// apply the edit\n\tlet newText = applyEdit(text, edit);\n\n\t// format the new text\n\tlet begin = edit.offset;\n\tlet end = edit.offset + edit.content.length;\n\tif (edit.length === 0 || edit.content.length === 0) { // insert or remove\n\t\twhile (begin > 0 && !isEOL(newText, begin - 1)) {\n\t\t\tbegin--;\n\t\t}\n\t\twhile (end < newText.length && !isEOL(newText, end)) {\n\t\t\tend++;\n\t\t}\n\t}\n\n\tconst edits = format(newText, { offset: begin, length: end - begin }, formattingOptions);\n\n\t// apply the formatting edits and track the begin and end offsets of the changes\n\tfor (let i = edits.length - 1; i >= 0; i--) {\n\t\tconst curr = edits[i];\n\t\tnewText = applyEdit(newText, curr);\n\t\tbegin = Math.min(begin, curr.offset);\n\t\tend = Math.max(end, curr.offset + curr.length);\n\t\tend += curr.content.length - curr.length;\n\t}\n\t// create a single edit with all changes\n\tconst editLength = text.length - (newText.length - end) - begin;\n\treturn [{ offset: begin, length: editLength, content: newText.substring(begin, end) }];\n}\n\nexport function applyEdit(text: string, edit: Edit): string {\n\treturn text.substring(0, edit.offset) + edit.content + text.substring(edit.offset + edit.length);\n}\n\nexport function applyEdits(text: string, edits: Edit[]): string {\n\tconst sortedEdits = edits.slice(0).sort((a, b) => {\n\t\tconst diff = a.offset - b.offset;\n\t\tif (diff === 0) {\n\t\t\treturn a.length - b.length;\n\t\t}\n\t\treturn diff;\n\t});\n\tlet lastModifiedOffset = text.length;\n\tfor (let i = sortedEdits.length - 1; i >= 0; i--) {\n\t\tconst e = sortedEdits[i];\n\t\tif (e.offset + e.length <= lastModifiedOffset) {\n\t\t\ttext = applyEdit(text, e);\n\t\t} else {\n\t\t\tthrow new Error('Overlapping edit');\n\t\t}\n\t\tlastModifiedOffset = e.offset;\n\t}\n\treturn text;\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (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\nexport const ScanCodeUtils = {\n\tlowerCaseToEnum: (scanCode: string) => scanCodeLowerCaseStrToInt[scanCode] || ScanCode.None,\n\ttoEnum: (scanCode: string) => scanCodeStrToInt[scanCode] || ScanCode.None,\n\ttoString: (scanCode: ScanCode) => scanCodeIntToStr[scanCode] || 'None'\n};\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 getHashCode(): string {\n\t\tconst ctrl = this.ctrlKey ? '1' : '0';\n\t\tconst shift = this.shiftKey ? '1' : '0';\n\t\tconst alt = this.altKey ? '1' : '0';\n\t\tconst meta = this.metaKey ? '1' : '0';\n\t\treturn `K${ctrl}${shift}${alt}${meta}${this.keyCode}`;\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\tpublic toKeybinding(): Keybinding {\n\t\treturn new Keybinding([this]);\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\tpublic equals(other: Chord): boolean {\n\t\treturn (\n\t\t\tother instanceof ScanCodeChord\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.scanCode === other.scanCode\n\t\t);\n\t}\n\n\tpublic getHashCode(): string {\n\t\tconst ctrl = this.ctrlKey ? '1' : '0';\n\t\tconst shift = this.shiftKey ? '1' : '0';\n\t\tconst alt = this.altKey ? '1' : '0';\n\t\tconst meta = this.metaKey ? '1' : '0';\n\t\treturn `S${ctrl}${shift}${alt}${meta}${this.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\tpublic getHashCode(): string {\n\t\tlet result = '';\n\t\tfor (let i = 0, len = this.chords.length; i < len; i++) {\n\t\t\tif (i !== 0) {\n\t\t\t\tresult += ';';\n\t\t\t}\n\t\t\tresult += this.chords[i].getHashCode();\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic equals(other: Keybinding | null): boolean {\n\t\tif (other === null) {\n\t\t\treturn false;\n\t\t}\n\t\tif (this.chords.length !== other.chords.length) {\n\t\t\treturn false;\n\t\t}\n\t\tfor (let i = 0; i < this.chords.length; i++) {\n\t\t\tif (!this.chords[i].equals(other.chords[i])) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\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 * Is the user settings label reflecting the label?\n\t */\n\tpublic abstract isWYSIWYG(): boolean;\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\nimport { KeyCodeUtils, ScanCodeUtils } from 'vs/base/common/keyCodes';\nimport { KeyCodeChord, ScanCodeChord, Keybinding, Chord } from 'vs/base/common/keybindings';\n\nexport class KeybindingParser {\n\n\tprivate static _readModifiers(input: string) {\n\t\tinput = input.toLowerCase().trim();\n\n\t\tlet ctrl = false;\n\t\tlet shift = false;\n\t\tlet alt = false;\n\t\tlet meta = false;\n\n\t\tlet matchedModifier: boolean;\n\n\t\tdo {\n\t\t\tmatchedModifier = false;\n\t\t\tif (/^ctrl(\\+|\\-)/.test(input)) {\n\t\t\t\tctrl = true;\n\t\t\t\tinput = input.substr('ctrl-'.length);\n\t\t\t\tmatchedModifier = true;\n\t\t\t}\n\t\t\tif (/^shift(\\+|\\-)/.test(input)) {\n\t\t\t\tshift = true;\n\t\t\t\tinput = input.substr('shift-'.length);\n\t\t\t\tmatchedModifier = true;\n\t\t\t}\n\t\t\tif (/^alt(\\+|\\-)/.test(input)) {\n\t\t\t\talt = true;\n\t\t\t\tinput = input.substr('alt-'.length);\n\t\t\t\tmatchedModifier = true;\n\t\t\t}\n\t\t\tif (/^meta(\\+|\\-)/.test(input)) {\n\t\t\t\tmeta = true;\n\t\t\t\tinput = input.substr('meta-'.length);\n\t\t\t\tmatchedModifier = true;\n\t\t\t}\n\t\t\tif (/^win(\\+|\\-)/.test(input)) {\n\t\t\t\tmeta = true;\n\t\t\t\tinput = input.substr('win-'.length);\n\t\t\t\tmatchedModifier = true;\n\t\t\t}\n\t\t\tif (/^cmd(\\+|\\-)/.test(input)) {\n\t\t\t\tmeta = true;\n\t\t\t\tinput = input.substr('cmd-'.length);\n\t\t\t\tmatchedModifier = true;\n\t\t\t}\n\t\t} while (matchedModifier);\n\n\t\tlet key: string;\n\n\t\tconst firstSpaceIdx = input.indexOf(' ');\n\t\tif (firstSpaceIdx > 0) {\n\t\t\tkey = input.substring(0, firstSpaceIdx);\n\t\t\tinput = input.substring(firstSpaceIdx);\n\t\t} else {\n\t\t\tkey = input;\n\t\t\tinput = '';\n\t\t}\n\n\t\treturn {\n\t\t\tremains: input,\n\t\t\tctrl,\n\t\t\tshift,\n\t\t\talt,\n\t\t\tmeta,\n\t\t\tkey\n\t\t};\n\t}\n\n\tprivate static parseChord(input: string): [Chord, string] {\n\t\tconst mods = this._readModifiers(input);\n\t\tconst scanCodeMatch = mods.key.match(/^\\[([^\\]]+)\\]$/);\n\t\tif (scanCodeMatch) {\n\t\t\tconst strScanCode = scanCodeMatch[1];\n\t\t\tconst scanCode = ScanCodeUtils.lowerCaseToEnum(strScanCode);\n\t\t\treturn [new ScanCodeChord(mods.ctrl, mods.shift, mods.alt, mods.meta, scanCode), mods.remains];\n\t\t}\n\t\tconst keyCode = KeyCodeUtils.fromUserSettings(mods.key);\n\t\treturn [new KeyCodeChord(mods.ctrl, mods.shift, mods.alt, mods.meta, keyCode), mods.remains];\n\t}\n\n\tstatic parseKeybinding(input: string): Keybinding | null {\n\t\tif (!input) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst chords: Chord[] = [];\n\t\tlet chord: Chord;\n\n\t\twhile (input.length > 0) {\n\t\t\t[chord, input] = this.parseChord(input);\n\t\t\tchords.push(chord);\n\t\t}\n\t\treturn (chords.length > 0 ? new Keybinding(chords) : 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\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 * True if the lazy value has been resolved.\n\t */\n\tget hasValue() { return this._didRun; }\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/iconLabel/iconHoverDelegate';\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\nexport function setHoverDelegateFactory(hoverDelegateProvider: ((placement: 'mouse' | 'element', enableInstantHover: boolean) => IScopedHoverDelegate)): void {\n\thoverDelegateFactory = hoverDelegateProvider;\n}\n\nexport function getDefaultHoverDelegate(placement: 'mouse' | 'element'): IHoverDelegate;\nexport function getDefaultHoverDelegate(placement: 'mouse' | 'element', enableInstantHover: true): IScopedHoverDelegate;\nexport function getDefaultHoverDelegate(placement: 'mouse' | 'element', enableInstantHover?: boolean): IHoverDelegate | IScopedHoverDelegate {\n\tif (enableInstantHover) {\n\t\t// If instant hover is enabled, the consumer is responsible for disposing the hover delegate\n\t\treturn hoverDelegateFactory(placement, true);\n\t}\n\n\tif (placement === 'element') {\n\t\treturn defaultHoverDelegateElement.value;\n\t}\n\treturn defaultHoverDelegateMouse.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\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\nexport function getOrSet(map: Map, key: K, value: V): V {\n\tlet result = map.get(key);\n\tif (result === undefined) {\n\t\tresult = value;\n\t\tmap.set(key, result);\n\t}\n\n\treturn result;\n}\n\nexport function mapToString(map: Map): string {\n\tconst entries: string[] = [];\n\tmap.forEach((value, key) => {\n\t\tentries.push(`${key} => ${value}`);\n\t});\n\n\treturn `Map(${map.size}) {${entries.join(', ')}}`;\n}\n\nexport function setToString(set: Set): string {\n\tconst entries: K[] = [];\n\tset.forEach(value => {\n\t\tentries.push(value);\n\t});\n\n\treturn `Set(${set.size}) {${entries.join(', ')}}`;\n}\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\nexport class ResourceSet implements Set {\n\n\treadonly [Symbol.toStringTag]: string = 'ResourceSet';\n\n\tprivate readonly _map: ResourceMap;\n\n\tconstructor(toKey?: ResourceMapKeyFn);\n\tconstructor(entries: readonly URI[], toKey?: ResourceMapKeyFn);\n\tconstructor(entriesOrKey?: readonly URI[] | ResourceMapKeyFn, toKey?: ResourceMapKeyFn) {\n\t\tif (!entriesOrKey || typeof entriesOrKey === 'function') {\n\t\t\tthis._map = new ResourceMap(entriesOrKey);\n\t\t} else {\n\t\t\tthis._map = new ResourceMap(toKey);\n\t\t\tentriesOrKey.forEach(this.add, this);\n\t\t}\n\t}\n\n\n\tget size(): number {\n\t\treturn this._map.size;\n\t}\n\n\tadd(value: URI): this {\n\t\tthis._map.set(value, value);\n\t\treturn this;\n\t}\n\n\tclear(): void {\n\t\tthis._map.clear();\n\t}\n\n\tdelete(value: URI): boolean {\n\t\treturn this._map.delete(value);\n\t}\n\n\tforEach(callbackfn: (value: URI, value2: URI, set: Set) => void, thisArg?: any): void {\n\t\tthis._map.forEach((_value, key) => callbackfn.call(thisArg, key, key, this));\n\t}\n\n\thas(value: URI): boolean {\n\t\treturn this._map.has(value);\n\t}\n\n\tentries(): IterableIterator<[URI, URI]> {\n\t\treturn this._map.entries();\n\t}\n\n\tkeys(): IterableIterator {\n\t\treturn this._map.keys();\n\t}\n\n\tvalues(): IterableIterator {\n\t\treturn this._map.keys();\n\t}\n\n\t[Symbol.iterator](): IterableIterator {\n\t\treturn this.keys();\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\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\nexport class LRUCache extends LinkedMap {\n\n\tprivate _limit: number;\n\tprivate _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\tget ratio(): number {\n\t\treturn this._ratio;\n\t}\n\n\tset ratio(ratio: number) {\n\t\tthis._ratio = Math.min(Math.max(0, ratio), 1);\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\tthis.checkTrim();\n\t\treturn this;\n\t}\n\n\tprivate checkTrim() {\n\t\tif (this.size > this._limit) {\n\t\t\tthis.trimOld(Math.round(this._limit * this._ratio));\n\t\t}\n\t}\n}\n\nexport class CounterSet {\n\n\tprivate map = new Map();\n\n\tadd(value: T): CounterSet {\n\t\tthis.map.set(value, (this.map.get(value) || 0) + 1);\n\t\treturn this;\n\t}\n\n\tdelete(value: T): boolean {\n\t\tlet counter = this.map.get(value) || 0;\n\n\t\tif (counter === 0) {\n\t\t\treturn false;\n\t\t}\n\n\t\tcounter--;\n\n\t\tif (counter === 0) {\n\t\t\tthis.map.delete(value);\n\t\t} else {\n\t\t\tthis.map.set(value, counter);\n\t\t}\n\n\t\treturn true;\n\t}\n\n\thas(value: T): boolean {\n\t\treturn this.map.has(value);\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\tforEach(callbackfn: (value: V, key: K, map: BidirectionalMap) => void, thisArg?: any): void {\n\t\tthis._m1.forEach((value, key) => {\n\t\t\tcallbackfn.call(thisArg, value, key, this);\n\t\t});\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\nexport function mapsStrictEqualIgnoreOrder(a: Map, b: Map): boolean {\n\tif (a === b) {\n\t\treturn true;\n\t}\n\n\tif (a.size !== b.size) {\n\t\treturn false;\n\t}\n\n\tfor (const [key, value] of a) {\n\t\tif (!b.has(key) || b.get(key) !== value) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tfor (const [key] of b) {\n\t\tif (!a.has(key)) {\n\t\t\treturn false;\n\t\t}\n\t}\n\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\nimport { compareBy, numberComparator } from 'vs/base/common/arrays';\nimport { groupBy } from 'vs/base/common/collections';\nimport { SetMap } from './map';\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 interface DisposableInfo {\n\tvalue: IDisposable;\n\tsource: string | null;\n\tparent: IDisposable | null;\n\tisSingleton: boolean;\n\tidx: number;\n}\n\nexport class DisposableTracker implements IDisposableTracker {\n\tprivate static idx = 0;\n\n\tprivate readonly livingDisposables = new Map();\n\n\tprivate getDisposableData(d: IDisposable): DisposableInfo {\n\t\tlet val = this.livingDisposables.get(d);\n\t\tif (!val) {\n\t\t\tval = { parent: null, source: null, isSingleton: false, value: d, idx: DisposableTracker.idx++ };\n\t\t\tthis.livingDisposables.set(d, val);\n\t\t}\n\t\treturn val;\n\t}\n\n\ttrackDisposable(d: IDisposable): void {\n\t\tconst data = this.getDisposableData(d);\n\t\tif (!data.source) {\n\t\t\tdata.source =\n\t\t\t\tnew Error().stack!;\n\t\t}\n\t}\n\n\tsetParent(child: IDisposable, parent: IDisposable | null): void {\n\t\tconst data = this.getDisposableData(child);\n\t\tdata.parent = parent;\n\t}\n\n\tmarkAsDisposed(x: IDisposable): void {\n\t\tthis.livingDisposables.delete(x);\n\t}\n\n\tmarkAsSingleton(disposable: IDisposable): void {\n\t\tthis.getDisposableData(disposable).isSingleton = true;\n\t}\n\n\tprivate getRootParent(data: DisposableInfo, cache: Map): DisposableInfo {\n\t\tconst cacheValue = cache.get(data);\n\t\tif (cacheValue) {\n\t\t\treturn cacheValue;\n\t\t}\n\n\t\tconst result = data.parent ? this.getRootParent(this.getDisposableData(data.parent), cache) : data;\n\t\tcache.set(data, result);\n\t\treturn result;\n\t}\n\n\tgetTrackedDisposables(): IDisposable[] {\n\t\tconst rootParentCache = new Map();\n\n\t\tconst leaking = [...this.livingDisposables.entries()]\n\t\t\t.filter(([, v]) => v.source !== null && !this.getRootParent(v, rootParentCache).isSingleton)\n\t\t\t.flatMap(([k]) => k);\n\n\t\treturn leaking;\n\t}\n\n\tcomputeLeakingDisposables(maxReported = 10, preComputedLeaks?: DisposableInfo[]): { leaks: DisposableInfo[]; details: string } | undefined {\n\t\tlet uncoveredLeakingObjs: DisposableInfo[] | undefined;\n\t\tif (preComputedLeaks) {\n\t\t\tuncoveredLeakingObjs = preComputedLeaks;\n\t\t} else {\n\t\t\tconst rootParentCache = new Map();\n\n\t\t\tconst leakingObjects = [...this.livingDisposables.values()]\n\t\t\t\t.filter((info) => info.source !== null && !this.getRootParent(info, rootParentCache).isSingleton);\n\n\t\t\tif (leakingObjects.length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst leakingObjsSet = new Set(leakingObjects.map(o => o.value));\n\n\t\t\t// Remove all objects that are a child of other leaking objects. Assumes there are no cycles.\n\t\t\tuncoveredLeakingObjs = leakingObjects.filter(l => {\n\t\t\t\treturn !(l.parent && leakingObjsSet.has(l.parent));\n\t\t\t});\n\n\t\t\tif (uncoveredLeakingObjs.length === 0) {\n\t\t\t\tthrow new Error('There are cyclic diposable chains!');\n\t\t\t}\n\t\t}\n\n\t\tif (!uncoveredLeakingObjs) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tfunction getStackTracePath(leaking: DisposableInfo): string[] {\n\t\t\tfunction removePrefix(array: string[], linesToRemove: (string | RegExp)[]) {\n\t\t\t\twhile (array.length > 0 && linesToRemove.some(regexp => typeof regexp === 'string' ? regexp === array[0] : array[0].match(regexp))) {\n\t\t\t\t\tarray.shift();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst lines = leaking.source!.split('\\n').map(p => p.trim().replace('at ', '')).filter(l => l !== '');\n\t\t\tremovePrefix(lines, ['Error', /^trackDisposable \\(.*\\)$/, /^DisposableTracker.trackDisposable \\(.*\\)$/]);\n\t\t\treturn lines.reverse();\n\t\t}\n\n\t\tconst stackTraceStarts = new SetMap();\n\t\tfor (const leaking of uncoveredLeakingObjs) {\n\t\t\tconst stackTracePath = getStackTracePath(leaking);\n\t\t\tfor (let i = 0; i <= stackTracePath.length; i++) {\n\t\t\t\tstackTraceStarts.add(stackTracePath.slice(0, i).join('\\n'), leaking);\n\t\t\t}\n\t\t}\n\n\t\t// Put earlier leaks first\n\t\tuncoveredLeakingObjs.sort(compareBy(l => l.idx, numberComparator));\n\n\t\tlet message = '';\n\n\t\tlet i = 0;\n\t\tfor (const leaking of uncoveredLeakingObjs.slice(0, maxReported)) {\n\t\t\ti++;\n\t\t\tconst stackTracePath = getStackTracePath(leaking);\n\t\t\tconst stackTraceFormattedLines = [];\n\n\t\t\tfor (let i = 0; i < stackTracePath.length; i++) {\n\t\t\t\tlet line = stackTracePath[i];\n\t\t\t\tconst starts = stackTraceStarts.get(stackTracePath.slice(0, i + 1).join('\\n'));\n\t\t\t\tline = `(shared with ${starts.size}/${uncoveredLeakingObjs.length} leaks) at ${line}`;\n\n\t\t\t\tconst prevStarts = stackTraceStarts.get(stackTracePath.slice(0, i).join('\\n'));\n\t\t\t\tconst continuations = groupBy([...prevStarts].map(d => getStackTracePath(d)[i]), v => v);\n\t\t\t\tdelete continuations[stackTracePath[i]];\n\t\t\t\tfor (const [cont, set] of Object.entries(continuations)) {\n\t\t\t\t\tstackTraceFormattedLines.unshift(` - stacktraces of ${set.length} other leaks continue with ${cont}`);\n\t\t\t\t}\n\n\t\t\t\tstackTraceFormattedLines.unshift(line);\n\t\t\t}\n\n\t\t\tmessage += `\\n\\n\\n==================== Leaking disposable ${i}/${uncoveredLeakingObjs.length}: ${leaking.value.constructor.name} ====================\\n${stackTraceFormattedLines.join('\\n')}\\n============================================================\\n\\n`;\n\t\t}\n\n\t\tif (uncoveredLeakingObjs.length > maxReported) {\n\t\t\tmessage += `\\n\\n\\n... and ${uncoveredLeakingObjs.length - maxReported} more leaking disposables\\n\\n`;\n\t\t}\n\n\t\treturn { leaks: uncoveredLeakingObjs, details: message };\n\t}\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).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\nexport function disposeIfDisposable(disposables: Array): Array {\n\tfor (const d of disposables) {\n\t\tif (isDisposable(d)) {\n\t\t\td.dispose();\n\t\t}\n\t}\n\treturn [];\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 a disposable from store and disposes of it. This will not throw or warn and proceed to dispose the\n\t * disposable even when the disposable is not part in the store.\n\t */\n\tpublic delete(o: T): void {\n\t\tif (!o) {\n\t\t\treturn;\n\t\t}\n\t\tif ((o as unknown as DisposableStore) === this) {\n\t\t\tthrow new Error('Cannot dispose a disposable on itself!');\n\t\t}\n\t\tthis._toDispose.delete(o);\n\t\to.dispose();\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\t/**\n\t * Clears the value, but does not dispose it.\n\t * The old value is returned.\n\t*/\n\tclearAndLeak(): T | undefined {\n\t\tconst oldValue = this._value;\n\t\tthis._value = undefined;\n\t\tif (oldValue) {\n\t\t\tsetParentOfDisposable(oldValue, null);\n\t\t}\n\t\treturn oldValue;\n\t}\n}\n\n/**\n * Manages the lifecycle of a disposable value that may be changed like {@link MutableDisposable}, but the value must\n * exist and cannot be undefined.\n */\nexport class MandatoryMutableDisposable implements IDisposable {\n\tprivate _disposable = new MutableDisposable();\n\tprivate _isDisposed = false;\n\n\tconstructor(initialValue: T) {\n\t\tthis._disposable.value = initialValue;\n\t}\n\n\tget value(): T {\n\t\treturn this._disposable.value!;\n\t}\n\n\tset value(value: T) {\n\t\tif (this._isDisposed || value === this._disposable.value) {\n\t\t\treturn;\n\t\t}\n\t\tthis._disposable.value = value;\n\t}\n\n\tdispose() {\n\t\tthis._isDisposed = true;\n\t\tthis._disposable.dispose();\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\n/**\n * A safe disposable can be `unset` so that a leaked reference (listener)\n * can be cut-off.\n */\nexport class SafeDisposable implements IDisposable {\n\n\tdispose: () => void = () => { };\n\tunset: () => void = () => { };\n\tisset: () => boolean = () => false;\n\n\tconstructor() {\n\t\ttrackDisposable(this);\n\t}\n\n\tset(fn: Function) {\n\t\tlet callback: Function | undefined = fn;\n\t\tthis.unset = () => callback = undefined;\n\t\tthis.isset = () => callback !== undefined;\n\t\tthis.dispose = () => {\n\t\t\tif (callback) {\n\t\t\t\tcallback();\n\t\t\t\tcallback = undefined;\n\t\t\t\tmarkAsDisposed(this);\n\t\t\t}\n\t\t};\n\t\treturn this;\n\t}\n}\n\nexport interface IReference extends IDisposable {\n\treadonly object: T;\n}\n\nexport abstract class ReferenceCollection {\n\n\tprivate readonly references: Map = new Map();\n\n\tacquire(key: string, ...args: any[]): IReference {\n\t\tlet reference = this.references.get(key);\n\n\t\tif (!reference) {\n\t\t\treference = { counter: 0, object: this.createReferencedObject(key, ...args) };\n\t\t\tthis.references.set(key, reference);\n\t\t}\n\n\t\tconst { object } = reference;\n\t\tconst dispose = createSingleCallFunction(() => {\n\t\t\tif (--reference.counter === 0) {\n\t\t\t\tthis.destroyReferencedObject(key, reference.object);\n\t\t\t\tthis.references.delete(key);\n\t\t\t}\n\t\t});\n\n\t\treference.counter++;\n\n\t\treturn { object, dispose };\n\t}\n\n\tprotected abstract createReferencedObject(key: string, ...args: any[]): T;\n\tprotected abstract destroyReferencedObject(key: string, object: T): void;\n}\n\n/**\n * Unwraps a reference collection of promised values. Makes sure\n * references are disposed whenever promises get rejected.\n */\nexport class AsyncReferenceCollection {\n\n\tconstructor(private referenceCollection: ReferenceCollection>) { }\n\n\tasync acquire(key: string, ...args: any[]): Promise> {\n\t\tconst ref = this.referenceCollection.acquire(key, ...args);\n\n\t\ttry {\n\t\t\tconst object = await ref.object;\n\n\t\t\treturn {\n\t\t\t\tobject,\n\t\t\t\tdispose: () => ref.dispose()\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tref.dispose();\n\t\t\tthrow error;\n\t\t}\n\t}\n}\n\nexport class ImmortalReference implements IReference {\n\tconstructor(public object: T) { }\n\tdispose(): void { /* noop */ }\n}\n\nexport function disposeOnReturn(fn: (store: DisposableStore) => void): void {\n\tconst store = new DisposableStore();\n\ttry {\n\t\tfn(store);\n\t} finally {\n\t\tstore.dispose();\n\t}\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\thas(key: K): boolean {\n\t\treturn this._store.has(key);\n\t}\n\n\tget size(): number {\n\t\treturn this._store.size;\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\tkeys(): IterableIterator {\n\t\treturn this._store.keys();\n\t}\n\n\tvalues(): IterableIterator {\n\t\treturn this._store.values();\n\t}\n\n\t[Symbol.iterator](): IterableIterator<[K, V]> {\n\t\treturn this._store[Symbol.iterator]();\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[313/*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 * Copyright (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\tcurrent(): T | null;\n\tprevious(): T | null;\n\tfirst(): T | null;\n\tlast(): T | null;\n\tnext(): T | null;\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 isFirst(): boolean {\n\t\treturn this._currentPosition() === 0;\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\tpublic clear(): void {\n\t\tthis._initialize([]);\n\t\tthis._onChange();\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\ninterface HistoryNode {\n\tvalue: T;\n\tprevious: HistoryNode | undefined;\n\tnext: HistoryNode | undefined;\n}\n\nexport class HistoryNavigator2 {\n\n\tprivate valueSet: Set;\n\tprivate head: HistoryNode;\n\tprivate tail: HistoryNode;\n\tprivate cursor: HistoryNode;\n\tprivate _size: number;\n\tget size(): number { return this._size; }\n\n\tconstructor(history: readonly T[], private capacity: number = 10) {\n\t\tif (history.length < 1) {\n\t\t\tthrow new Error('not supported');\n\t\t}\n\n\t\tthis._size = 1;\n\t\tthis.head = this.tail = this.cursor = {\n\t\t\tvalue: history[0],\n\t\t\tprevious: undefined,\n\t\t\tnext: undefined\n\t\t};\n\n\t\tthis.valueSet = new Set([history[0]]);\n\t\tfor (let i = 1; i < history.length; i++) {\n\t\t\tthis.add(history[i]);\n\t\t}\n\t}\n\n\tadd(value: T): void {\n\t\tconst node: HistoryNode = {\n\t\t\tvalue,\n\t\t\tprevious: this.tail,\n\t\t\tnext: undefined\n\t\t};\n\n\t\tthis.tail.next = node;\n\t\tthis.tail = node;\n\t\tthis.cursor = this.tail;\n\t\tthis._size++;\n\n\t\tif (this.valueSet.has(value)) {\n\t\t\tthis._deleteFromList(value);\n\t\t} else {\n\t\t\tthis.valueSet.add(value);\n\t\t}\n\n\t\twhile (this._size > this.capacity) {\n\t\t\tthis.valueSet.delete(this.head.value);\n\n\t\t\tthis.head = this.head.next!;\n\t\t\tthis.head.previous = undefined;\n\t\t\tthis._size--;\n\t\t}\n\t}\n\n\t/**\n\t * @returns old last value\n\t */\n\treplaceLast(value: T): T {\n\t\tif (this.tail.value === value) {\n\t\t\treturn value;\n\t\t}\n\n\t\tconst oldValue = this.tail.value;\n\t\tthis.valueSet.delete(oldValue);\n\t\tthis.tail.value = value;\n\n\t\tif (this.valueSet.has(value)) {\n\t\t\tthis._deleteFromList(value);\n\t\t} else {\n\t\t\tthis.valueSet.add(value);\n\t\t}\n\n\t\treturn oldValue;\n\t}\n\n\tprepend(value: T): void {\n\t\tif (this._size === this.capacity || this.valueSet.has(value)) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst node: HistoryNode = {\n\t\t\tvalue,\n\t\t\tprevious: undefined,\n\t\t\tnext: this.head\n\t\t};\n\n\t\tthis.head.previous = node;\n\t\tthis.head = node;\n\t\tthis._size++;\n\n\t\tthis.valueSet.add(value);\n\t}\n\n\tisAtEnd(): boolean {\n\t\treturn this.cursor === this.tail;\n\t}\n\n\tcurrent(): T {\n\t\treturn this.cursor.value;\n\t}\n\n\tprevious(): T {\n\t\tif (this.cursor.previous) {\n\t\t\tthis.cursor = this.cursor.previous;\n\t\t}\n\n\t\treturn this.cursor.value;\n\t}\n\n\tnext(): T {\n\t\tif (this.cursor.next) {\n\t\t\tthis.cursor = this.cursor.next;\n\t\t}\n\n\t\treturn this.cursor.value;\n\t}\n\n\thas(t: T): boolean {\n\t\treturn this.valueSet.has(t);\n\t}\n\n\tresetCursor(): T {\n\t\tthis.cursor = this.tail;\n\t\treturn this.cursor.value;\n\t}\n\n\t*[Symbol.iterator](): Iterator {\n\t\tlet node: HistoryNode | undefined = this.head;\n\n\t\twhile (node) {\n\t\t\tyield node.value;\n\t\t\tnode = node.next;\n\t\t}\n\t}\n\n\tprivate _deleteFromList(value: T): void {\n\t\tlet temp = this.head;\n\n\t\twhile (temp !== this.tail) {\n\t\t\tif (temp.value === value) {\n\t\t\t\tif (temp === this.head) {\n\t\t\t\t\tthis.head = this.head.next!;\n\t\t\t\t\tthis.head.previous = undefined;\n\t\t\t\t} else {\n\t\t\t\t\ttemp.previous!.next = temp.next;\n\t\t\t\t\ttemp.next!.previous = temp.previous;\n\t\t\t\t}\n\n\t\t\t\tthis._size--;\n\t\t\t}\n\n\t\t\ttemp = temp.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\nexport function clamp(value: number, min: number, max: number): number {\n\treturn Math.min(Math.max(value, min), max);\n}\n\nexport function rot(index: number, modulo: number): number {\n\treturn (modulo + (index % modulo)) % modulo;\n}\n\nexport class Counter {\n\tprivate _next = 0;\n\n\tgetNext(): number {\n\t\treturn this._next++;\n\t}\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 autorunHandleChanges (but with a disposable store that is cleared before the next run or on dispose)\n */\nexport function autorunWithStoreHandleChanges(\n\toptions: IDebugNameData & {\n\t\tcreateEmptyChangeSummary?: () => TChangeSummary;\n\t\thandleChange: (context: IChangeContext, changeSummary: TChangeSummary) => boolean;\n\t},\n\tfn: (reader: IReader, changeSummary: TChangeSummary, store: DisposableStore) => void\n): IDisposable {\n\tconst store = new DisposableStore();\n\tconst disposable = autorunHandleChanges(\n\t\t{\n\t\t\towner: options.owner,\n\t\t\tdebugName: options.debugName,\n\t\t\tdebugReferenceFn: options.debugReferenceFn,\n\t\t\tcreateEmptyChangeSummary: options.createEmptyChangeSummary,\n\t\t\thandleChange: options.handleChange,\n\t\t},\n\t\t(reader, changeSummary) => {\n\t\t\tstore.clear();\n\t\t\tfn(reader, changeSummary, store);\n\t\t}\n\t);\n\treturn toDisposable(() => {\n\t\tdisposable.dispose();\n\t\tstore.dispose();\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\nexport function autorunDelta(\n\tobservable: IObservable,\n\thandler: (args: { lastValue: T | undefined; newValue: T }) => void\n): IDisposable {\n\tlet _lastValue: T | undefined;\n\treturn autorunOpts({ debugReferenceFn: handler }, (reader) => {\n\t\tconst newValue = observable.read(reader);\n\t\tconst lastValue = _lastValue;\n\t\t_lastValue = newValue;\n\t\thandler({ lastValue, newValue });\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 => 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 { DisposableStore, IDisposable } from 'vs/base/common/lifecycle';\nimport { keepObserved, recomputeInitiallyAndOnChange } from 'vs/base/common/observable';\nimport { DebugNameData, Owner, getFunctionName } from 'vs/base/common/observableInternal/debugName';\nimport type { 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 * Makes sure this value is cached.\n\t */\n\tkeepObserved(store: DisposableStore): 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},\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\t/**\n\t * Ensures that this observable is observed. This keeps the cache alive.\n\t * However, in case of deriveds, it does not force eager evaluation (only when the value is read/get).\n\t * Use `recomputeInitiallyAndOnChange` for eager evaluation.\n\t */\n\tpublic keepObserved(store: DisposableStore): IObservable {\n\t\tstore.add(_keepObserved!(this));\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\tif (typeof nameOrOwner === 'string') {\n\t\treturn new ObservableValue(undefined, nameOrOwner, initialValue);\n\t} else {\n\t\treturn new ObservableValue(nameOrOwner, undefined, initialValue);\n\t}\n}\n\nexport class ObservableValue\n\textends BaseObservable\n\timplements ISettableObservable {\n\tprotected _value: T;\n\n\tget debugName() {\n\t\treturn new DebugNameData(this._owner, this._debugName, undefined).getDebugName(this) ?? 'ObservableValue';\n\t}\n\n\tconstructor(\n\t\tprivate readonly _owner: Owner,\n\t\tprivate readonly _debugName: string | undefined,\n\t\tinitialValue: T\n\t) {\n\t\tsuper();\n\t\tthis._value = initialValue;\n\t}\n\tpublic get(): T {\n\t\treturn this._value;\n\t}\n\n\tpublic set(value: T, tx: ITransaction | undefined, change: TChange): void {\n\t\tif (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\tif (typeof nameOrOwner === 'string') {\n\t\treturn new DisposableObservableValue(undefined, nameOrOwner, initialValue);\n\t} else {\n\t\treturn new DisposableObservableValue(nameOrOwner, undefined, initialValue);\n\t}\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 IChangeTracker {\n\t/**\n\t * Returns if this change should cause an invalidation.\n\t * Implementations can record changes.\n\t*/\n\thandleChange(context: IChangeContext): boolean;\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 { DisposableStore, IDisposable } from 'vs/base/common/lifecycle';\nimport { BaseObservable, IChangeContext, IObservable, IObserver, IReader, _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\nexport type EqualityComparer = (a: T, b: T) => boolean;\nexport const defaultEqualityComparer: EqualityComparer = (a, b) => a === b;\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: object, computeFn: (reader: IReader) => T): IObservable;\nexport function derived(computeFnOrOwner: ((reader: IReader) => T) | object, 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\tdefaultEqualityComparer\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\tdefaultEqualityComparer\n\t);\n}\n\nexport function derivedOpts(\n\toptions: IDebugNameData & {\n\t\tequalityComparer?: 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.equalityComparer ?? defaultEqualityComparer\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 ?? defaultEqualityComparer\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\tdefaultEqualityComparer\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\tdefaultEqualityComparer\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 => 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 * Copyright (c) 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 { autorun } from 'vs/base/common/observableInternal/autorun';\nimport { BaseObservable, ConvenientObservable, IObservable, IObserver, IReader, ITransaction, _setKeepObserved, _setRecomputeInitiallyAndOnChange, observableValue, 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';\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\n\nexport function observableFromPromise(promise: Promise): IObservable<{ value?: T }> {\n\tconst observable = observableValue<{ value?: T }>('promiseValue', {});\n\tpromise.then((value) => {\n\t\tobservable.set({ value }, undefined);\n\t});\n\treturn observable;\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\treturn this._getValue(undefined);\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\nexport function debouncedObservable(observable: IObservable, debounceMs: number, disposableStore: DisposableStore): IObservable {\n\tconst debouncedObservable = observableValue('debounced', undefined);\n\n\tlet timeout: any = undefined;\n\n\tdisposableStore.add(autorun(reader => {\n\t\t/** @description debounce */\n\t\tconst value = observable.read(reader);\n\n\t\tif (timeout) {\n\t\t\tclearTimeout(timeout);\n\t\t}\n\t\ttimeout = setTimeout(() => {\n\t\t\ttransaction(tx => {\n\t\t\t\tdebouncedObservable.set(value, tx);\n\t\t\t});\n\t\t}, debounceMs);\n\n\t}));\n\n\treturn debouncedObservable;\n}\n\nexport function wasEventTriggeredRecently(event: Event, timeoutMs: number, disposableStore: DisposableStore): IObservable {\n\tconst observable = observableValue('triggeredRecently', false);\n\n\tlet timeout: any = undefined;\n\n\tdisposableStore.add(event(() => {\n\t\tobservable.set(true, undefined);\n\n\t\tif (timeout) {\n\t\t\tclearTimeout(timeout);\n\t\t}\n\t\ttimeout = setTimeout(() => {\n\t\t\tobservable.set(false, undefined);\n\t\t}, timeoutMs);\n\t}));\n\n\treturn observable;\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(computeFn: (reader: IReader, lastValue: T | undefined) => T): IObservable {\n\tlet lastValue: T | undefined = undefined;\n\tconst observable = derived(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 & { clearCache(transaction: ITransaction): void } {\n\tlet lastValue: T | undefined = undefined;\n\tconst counter = observableValue('derivedObservableWithWritableCache.counter', 0);\n\tconst observable = derived(owner, reader => {\n\t\tcounter.read(reader);\n\t\tlastValue = computeFn(reader, lastValue);\n\t\treturn lastValue;\n\t});\n\treturn Object.assign(observable, {\n\t\tclearCache: (transaction: ITransaction) => {\n\t\t\tlastValue = undefined;\n\t\t\tcounter.set(counter.get() + 1, transaction);\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","/*---------------------------------------------------------------------------------------------\n * Copyright (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 ValidationState {\n\tOK = 0,\n\tInfo = 1,\n\tWarning = 2,\n\tError = 3,\n\tFatal = 4\n}\n\nexport class ValidationStatus {\n\tprivate _state: ValidationState;\n\n\tconstructor() {\n\t\tthis._state = ValidationState.OK;\n\t}\n\n\tpublic get state(): ValidationState {\n\t\treturn this._state;\n\t}\n\n\tpublic set state(value: ValidationState) {\n\t\tif (value > this._state) {\n\t\t\tthis._state = value;\n\t\t}\n\t}\n\n\tpublic isOK(): boolean {\n\t\treturn this._state === ValidationState.OK;\n\t}\n\n\tpublic isFatal(): boolean {\n\t\treturn this._state === ValidationState.Fatal;\n\t}\n}\n\nexport interface IProblemReporter {\n\tinfo(message: string): void;\n\twarn(message: string): void;\n\terror(message: string): void;\n\tfatal(message: string): void;\n\tstatus: ValidationStatus;\n}\n\nexport abstract class Parser {\n\n\tprivate _problemReporter: IProblemReporter;\n\n\tconstructor(problemReporter: IProblemReporter) {\n\t\tthis._problemReporter = problemReporter;\n\t}\n\n\tpublic reset(): void {\n\t\tthis._problemReporter.status.state = ValidationState.OK;\n\t}\n\n\tpublic get problemReporter(): IProblemReporter {\n\t\treturn this._problemReporter;\n\t}\n\n\tpublic info(message: string): void {\n\t\tthis._problemReporter.info(message);\n\t}\n\n\tpublic warn(message: string): void {\n\t\tthis._problemReporter.warn(message);\n\t}\n\n\tpublic error(message: string): void {\n\t\tthis._problemReporter.error(message);\n\t}\n\n\tpublic fatal(message: string): void {\n\t\tthis._problemReporter.fatal(message);\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'use strict';\n\n//@ts-check\n\n(function () {\n\n\t/**\n\t * @returns {{mark(name:string):void, getMarks():{name:string, startTime:number}[]}}\n\t */\n\tfunction _definePolyfillMarks(timeOrigin) {\n\n\t\tconst _data = [];\n\t\tif (typeof timeOrigin === 'number') {\n\t\t\t_data.push('code/timeOrigin', timeOrigin);\n\t\t}\n\n\t\tfunction mark(name) {\n\t\t\t_data.push(name, Date.now());\n\t\t}\n\t\tfunction getMarks() {\n\t\t\tconst result = [];\n\t\t\tfor (let i = 0; i < _data.length; i += 2) {\n\t\t\t\tresult.push({\n\t\t\t\t\tname: _data[i],\n\t\t\t\t\tstartTime: _data[i + 1],\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\t\treturn { mark, getMarks };\n\t}\n\n\t/**\n\t * @returns {{mark(name:string):void, getMarks():{name:string, startTime:number}[]}}\n\t */\n\tfunction _define() {\n\n\t\t// Identify browser environment when following property is not present\n\t\t// https://nodejs.org/dist/latest-v16.x/docs/api/perf_hooks.html#performancenodetiming\n\t\tif (typeof performance === 'object' && typeof performance.mark === 'function' && !performance.nodeTiming) {\n\t\t\t// in a browser context, reuse performance-util\n\n\t\t\tif (typeof performance.timeOrigin !== 'number' && !performance.timing) {\n\t\t\t\t// safari & webworker: because there is no timeOrigin and no workaround\n\t\t\t\t// we use the `Date.now`-based polyfill.\n\t\t\t\treturn _definePolyfillMarks();\n\n\t\t\t} else {\n\t\t\t\t// use \"native\" performance for mark and getMarks\n\t\t\t\treturn {\n\t\t\t\t\tmark(name) {\n\t\t\t\t\t\tperformance.mark(name);\n\t\t\t\t\t},\n\t\t\t\t\tgetMarks() {\n\t\t\t\t\t\tlet timeOrigin = performance.timeOrigin;\n\t\t\t\t\t\tif (typeof timeOrigin !== 'number') {\n\t\t\t\t\t\t\t// safari: there is no timerOrigin but in renderers there is the timing-property\n\t\t\t\t\t\t\t// see https://bugs.webkit.org/show_bug.cgi?id=174862\n\t\t\t\t\t\t\ttimeOrigin = performance.timing.navigationStart || performance.timing.redirectStart || performance.timing.fetchStart;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst result = [{ name: 'code/timeOrigin', startTime: Math.round(timeOrigin) }];\n\t\t\t\t\t\tfor (const entry of performance.getEntriesByType('mark')) {\n\t\t\t\t\t\t\tresult.push({\n\t\t\t\t\t\t\t\tname: entry.name,\n\t\t\t\t\t\t\t\tstartTime: Math.round(timeOrigin + entry.startTime)\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn result;\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}\n\n\t\t} else if (typeof process === 'object') {\n\t\t\t// node.js: use the normal polyfill but add the timeOrigin\n\t\t\t// from the node perf_hooks API as very first mark\n\t\t\tconst timeOrigin = performance?.timeOrigin ?? Math.round((require.__$__nodeRequire || require)('perf_hooks').performance.timeOrigin);\n\t\t\treturn _definePolyfillMarks(timeOrigin);\n\n\t\t} else {\n\t\t\t// unknown environment\n\t\t\tconsole.trace('perf-util loaded in UNKNOWN environment');\n\t\t\treturn _definePolyfillMarks();\n\t\t}\n\t}\n\n\tfunction _factory(sharedObj) {\n\t\tif (!sharedObj.MonacoPerformanceMarks) {\n\t\t\tsharedObj.MonacoPerformanceMarks = _define();\n\t\t}\n\t\treturn sharedObj.MonacoPerformanceMarks;\n\t}\n\n\t// This module can be loaded in an amd and commonjs-context.\n\t// Because we want both instances to use the same perf-data\n\t// we store them globally\n\n\t// eslint-disable-next-line no-var\n\tvar sharedObj;\n\tif (typeof global === 'object') {\n\t\t// nodejs\n\t\tsharedObj = global;\n\t} else if (typeof self === 'object') {\n\t\t// browser\n\t\tsharedObj = self;\n\t} else {\n\t\tsharedObj = {};\n\t}\n\n\tif (typeof define === 'function') {\n\t\t// amd\n\t\tdefine(\"vs/base/common/performance\", [], function () { return _factory(sharedObj); });\n\t} else if (typeof module === 'object' && typeof module.exports === 'object') {\n\t\t// commonjs\n\t\tmodule.exports = _factory(sharedObj);\n\t} else {\n\t\tconsole.trace('perf-util defined in UNKNOWN context (neither requirejs or commonjs)');\n\t\tsharedObj.perf = _factory(sharedObj);\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 { Iterable } from 'vs/base/common/iterator';\n\nconst unset = Symbol('unset');\n\nexport interface IPrefixTreeNode {\n\t/** Possible children of the node. */\n\tchildren?: ReadonlyMap>;\n\n\t/** The value if data exists for this node in the tree. Mutable. */\n\tvalue: T | undefined;\n}\n\n/**\n * A simple prefix tree implementation where a value is stored based on\n * well-defined prefix segments.\n */\nexport class WellDefinedPrefixTree {\n\tprivate readonly root = new Node();\n\tprivate _size = 0;\n\n\tpublic get size() {\n\t\treturn this._size;\n\t}\n\n\t/** Gets the top-level nodes of the tree */\n\tpublic get nodes(): Iterable> {\n\t\treturn this.root.children?.values() || Iterable.empty();\n\t}\n\n\t/**\n\t * Inserts a new value in the prefix tree.\n\t * @param onNode - called for each node as we descend to the insertion point,\n\t * including the insertion point itself.\n\t */\n\tinsert(key: Iterable, value: V, onNode?: (n: IPrefixTreeNode) => void): void {\n\t\tthis.opNode(key, n => n._value = value, onNode);\n\t}\n\n\t/** Mutates a value in the prefix tree. */\n\tmutate(key: Iterable, mutate: (value?: V) => V): void {\n\t\tthis.opNode(key, n => n._value = mutate(n._value === unset ? undefined : n._value));\n\t}\n\n\t/** Deletes a node from the prefix tree, returning the value it contained. */\n\tdelete(key: Iterable): V | undefined {\n\t\tconst path = this.getPathToKey(key);\n\t\tif (!path) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet i = path.length - 1;\n\t\tconst value = path[i].node._value;\n\t\tif (value === unset) {\n\t\t\treturn; // not actually a real node\n\t\t}\n\n\t\tthis._size--;\n\t\tpath[i].node._value = unset;\n\n\t\tfor (; i > 0; i--) {\n\t\t\tconst { node, part } = path[i];\n\t\t\tif (node.children?.size || node._value !== unset) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tpath[i - 1].node.children!.delete(part);\n\t\t}\n\n\t\treturn value;\n\t}\n\n\t/** Deletes a subtree from the prefix tree, returning the values they contained. */\n\t*deleteRecursive(key: Iterable): Iterable {\n\t\tconst path = this.getPathToKey(key);\n\t\tif (!path) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst subtree = path[path.length - 1].node;\n\n\t\t// important: run the deletion before we start to yield results, so that\n\t\t// it still runs even if the caller doesn't consumer the iterator\n\t\tfor (let i = path.length - 1; i > 0; i--) {\n\t\t\tconst parent = path[i - 1];\n\t\t\tparent.node.children!.delete(path[i].part);\n\t\t\tif (parent.node.children!.size > 0 || parent.node._value !== unset) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tfor (const node of bfsIterate(subtree)) {\n\t\t\tif (node._value !== unset) {\n\t\t\t\tthis._size--;\n\t\t\t\tyield node._value;\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Gets a value from the tree. */\n\tfind(key: Iterable): V | undefined {\n\t\tlet node = this.root;\n\t\tfor (const segment of key) {\n\t\t\tconst next = node.children?.get(segment);\n\t\t\tif (!next) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\tnode = next;\n\t\t}\n\n\t\treturn node._value === unset ? undefined : node._value;\n\t}\n\n\t/** Gets whether the tree has the key, or a parent of the key, already inserted. */\n\thasKeyOrParent(key: Iterable): boolean {\n\t\tlet node = this.root;\n\t\tfor (const segment of key) {\n\t\t\tconst next = node.children?.get(segment);\n\t\t\tif (!next) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (next._value !== unset) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tnode = next;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/** Gets whether the tree has the given key or any children. */\n\thasKeyOrChildren(key: Iterable): boolean {\n\t\tlet node = this.root;\n\t\tfor (const segment of key) {\n\t\t\tconst next = node.children?.get(segment);\n\t\t\tif (!next) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tnode = next;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/** Gets whether the tree has the given key. */\n\thasKey(key: Iterable): boolean {\n\t\tlet node = this.root;\n\t\tfor (const segment of key) {\n\t\t\tconst next = node.children?.get(segment);\n\t\t\tif (!next) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tnode = next;\n\t\t}\n\n\t\treturn node._value !== unset;\n\t}\n\n\tprivate getPathToKey(key: Iterable) {\n\t\tconst path = [{ part: '', node: this.root }];\n\t\tlet i = 0;\n\t\tfor (const part of key) {\n\t\t\tconst node = path[i].node.children?.get(part);\n\t\t\tif (!node) {\n\t\t\t\treturn; // node not in tree\n\t\t\t}\n\n\t\t\tpath.push({ part, node });\n\t\t\ti++;\n\t\t}\n\n\t\treturn path;\n\t}\n\n\tprivate opNode(key: Iterable, fn: (node: Node) => void, onDescend?: (node: Node) => void): void {\n\t\tlet node = this.root;\n\t\tfor (const part of key) {\n\t\t\tif (!node.children) {\n\t\t\t\tconst next = new Node();\n\t\t\t\tnode.children = new Map([[part, next]]);\n\t\t\t\tnode = next;\n\t\t\t} else if (!node.children.has(part)) {\n\t\t\t\tconst next = new Node();\n\t\t\t\tnode.children.set(part, next);\n\t\t\t\tnode = next;\n\t\t\t} else {\n\t\t\t\tnode = node.children.get(part)!;\n\t\t\t}\n\t\t\tonDescend?.(node);\n\t\t}\n\n\t\tconst sizeBefore = node._value === unset ? 0 : 1;\n\t\tfn(node);\n\t\tconst sizeAfter = node._value === unset ? 0 : 1;\n\t\tthis._size += sizeAfter - sizeBefore;\n\t}\n\n\t/** Returns an iterable of the tree values in no defined order. */\n\t*values() {\n\t\tfor (const { _value } of bfsIterate(this.root)) {\n\t\t\tif (_value !== unset) {\n\t\t\t\tyield _value;\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction* bfsIterate(root: Node): Iterable> {\n\tconst stack = [root];\n\twhile (stack.length > 0) {\n\t\tconst node = stack.pop()!;\n\t\tyield node;\n\n\t\tif (node.children) {\n\t\t\tfor (const child of node.children.values()) {\n\t\t\t\tstack.push(child);\n\t\t\t}\n\t\t}\n\t}\n}\n\nclass Node implements IPrefixTreeNode {\n\tpublic children?: Map>;\n\n\tpublic get value() {\n\t\treturn this._value === unset ? undefined : this._value;\n\t}\n\n\tpublic set value(value: T | undefined) {\n\t\tthis._value = value === undefined ? unset : value;\n\t}\n\n\tpublic _value: T | typeof unset = unset;\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (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 interface IRangedGroup {\n\trange: IRange;\n\tsize: 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\treadonly count: 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 * Semver UMD module\n * Copyright (c) Isaac Z. Schlueter and Contributors\n * https://github.com/npm/node-semver\n */\n\n/**\n * DO NOT EDIT THIS FILE\n */\n\n!function(e,r){if(\"object\"==typeof exports&&\"object\"==typeof module)module.exports=r();else if(\"function\"==typeof define&&define.amd)define(\"vs/base/common/semver/semver\", [],r);else{var t=r();for(var n in t)(\"object\"==typeof exports?exports:e)[n]=t[n]}}(\"undefined\"!=typeof self?self:this,(function(){return function(e){var r={};function t(n){if(r[n])return r[n].exports;var o=r[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,t),o.l=!0,o.exports}return t.m=e,t.c=r,t.d=function(e,r,n){t.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:n})},t.r=function(e){\"undefined\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\"Module\"}),Object.defineProperty(e,\"__esModule\",{value:!0})},t.t=function(e,r){if(1&r&&(e=t(e)),8&r)return e;if(4&r&&\"object\"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(t.r(n),Object.defineProperty(n,\"default\",{enumerable:!0,value:e}),2&r&&\"string\"!=typeof e)for(var o in e)t.d(n,o,function(r){return e[r]}.bind(null,o));return n},t.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(r,\"a\",r),r},t.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},t.p=\"\",t(t.s=0)}([function(e,r,t){(function(t){var n;r=e.exports=H,n=\"object\"==typeof t&&t.env&&t.env.NODE_DEBUG&&/\\bsemver\\b/i.test(t.env.NODE_DEBUG)?function(){var e=Array.prototype.slice.call(arguments,0);e.unshift(\"SEMVER\"),console.log.apply(console,e)}:function(){},r.SEMVER_SPEC_VERSION=\"2.0.0\";var o=256,i=Number.MAX_SAFE_INTEGER||9007199254740991,s=r.re=[],a=r.src=[],u=0,c=u++;a[c]=\"0|[1-9]\\\\d*\";var p=u++;a[p]=\"[0-9]+\";var f=u++;a[f]=\"\\\\d*[a-zA-Z-][a-zA-Z0-9-]*\";var l=u++;a[l]=\"(\"+a[c]+\")\\\\.(\"+a[c]+\")\\\\.(\"+a[c]+\")\";var h=u++;a[h]=\"(\"+a[p]+\")\\\\.(\"+a[p]+\")\\\\.(\"+a[p]+\")\";var v=u++;a[v]=\"(?:\"+a[c]+\"|\"+a[f]+\")\";var m=u++;a[m]=\"(?:\"+a[p]+\"|\"+a[f]+\")\";var w=u++;a[w]=\"(?:-(\"+a[v]+\"(?:\\\\.\"+a[v]+\")*))\";var g=u++;a[g]=\"(?:-?(\"+a[m]+\"(?:\\\\.\"+a[m]+\")*))\";var y=u++;a[y]=\"[0-9A-Za-z-]+\";var d=u++;a[d]=\"(?:\\\\+(\"+a[y]+\"(?:\\\\.\"+a[y]+\")*))\";var b=u++,j=\"v?\"+a[l]+a[w]+\"?\"+a[d]+\"?\";a[b]=\"^\"+j+\"$\";var E=\"[v=\\\\s]*\"+a[h]+a[g]+\"?\"+a[d]+\"?\",T=u++;a[T]=\"^\"+E+\"$\";var x=u++;a[x]=\"((?:<|>)?=?)\";var $=u++;a[$]=a[p]+\"|x|X|\\\\*\";var k=u++;a[k]=a[c]+\"|x|X|\\\\*\";var S=u++;a[S]=\"[v=\\\\s]*(\"+a[k]+\")(?:\\\\.(\"+a[k]+\")(?:\\\\.(\"+a[k]+\")(?:\"+a[w]+\")?\"+a[d]+\"?)?)?\";var R=u++;a[R]=\"[v=\\\\s]*(\"+a[$]+\")(?:\\\\.(\"+a[$]+\")(?:\\\\.(\"+a[$]+\")(?:\"+a[g]+\")?\"+a[d]+\"?)?)?\";var I=u++;a[I]=\"^\"+a[x]+\"\\\\s*\"+a[S]+\"$\";var _=u++;a[_]=\"^\"+a[x]+\"\\\\s*\"+a[R]+\"$\";var O=u++;a[O]=\"(?:^|[^\\\\d])(\\\\d{1,16})(?:\\\\.(\\\\d{1,16}))?(?:\\\\.(\\\\d{1,16}))?(?:$|[^\\\\d])\";var A=u++;a[A]=\"(?:~>?)\";var M=u++;a[M]=\"(\\\\s*)\"+a[A]+\"\\\\s+\",s[M]=new RegExp(a[M],\"g\");var V=u++;a[V]=\"^\"+a[A]+a[S]+\"$\";var P=u++;a[P]=\"^\"+a[A]+a[R]+\"$\";var C=u++;a[C]=\"(?:\\\\^)\";var L=u++;a[L]=\"(\\\\s*)\"+a[C]+\"\\\\s+\",s[L]=new RegExp(a[L],\"g\");var N=u++;a[N]=\"^\"+a[C]+a[S]+\"$\";var q=u++;a[q]=\"^\"+a[C]+a[R]+\"$\";var D=u++;a[D]=\"^\"+a[x]+\"\\\\s*(\"+E+\")$|^$\";var X=u++;a[X]=\"^\"+a[x]+\"\\\\s*(\"+j+\")$|^$\";var z=u++;a[z]=\"(\\\\s*)\"+a[x]+\"\\\\s*(\"+E+\"|\"+a[S]+\")\",s[z]=new RegExp(a[z],\"g\");var G=u++;a[G]=\"^\\\\s*(\"+a[S]+\")\\\\s+-\\\\s+(\"+a[S]+\")\\\\s*$\";var Z=u++;a[Z]=\"^\\\\s*(\"+a[R]+\")\\\\s+-\\\\s+(\"+a[R]+\")\\\\s*$\";var B=u++;a[B]=\"(<|>)?=?\\\\s*\\\\*\";for(var U=0;U<35;U++)n(U,a[U]),s[U]||(s[U]=new RegExp(a[U]));function F(e,r){if(e instanceof H)return e;if(\"string\"!=typeof e)return null;if(e.length>o)return null;if(!(r?s[T]:s[b]).test(e))return null;try{return new H(e,r)}catch(e){return null}}function H(e,r){if(e instanceof H){if(e.loose===r)return e;e=e.version}else if(\"string\"!=typeof e)throw new TypeError(\"Invalid Version: \"+e);if(e.length>o)throw new TypeError(\"version is longer than \"+o+\" characters\");if(!(this instanceof H))return new H(e,r);n(\"SemVer\",e,r),this.loose=r;var t=e.trim().match(r?s[T]:s[b]);if(!t)throw new TypeError(\"Invalid Version: \"+e);if(this.raw=e,this.major=+t[1],this.minor=+t[2],this.patch=+t[3],this.major>i||this.major<0)throw new TypeError(\"Invalid major version\");if(this.minor>i||this.minor<0)throw new TypeError(\"Invalid minor version\");if(this.patch>i||this.patch<0)throw new TypeError(\"Invalid patch version\");t[4]?this.prerelease=t[4].split(\".\").map((function(e){if(/^[0-9]+$/.test(e)){var r=+e;if(r>=0&&r=0;)\"number\"==typeof this.prerelease[t]&&(this.prerelease[t]++,t=-2);-1===t&&this.prerelease.push(0)}r&&(this.prerelease[0]===r?isNaN(this.prerelease[1])&&(this.prerelease=[r,0]):this.prerelease=[r,0]);break;default:throw new Error(\"invalid increment argument: \"+e)}return this.format(),this.raw=this.version,this},r.inc=function(e,r,t,n){\"string\"==typeof t&&(n=t,t=void 0);try{return new H(e,t).inc(r,n).version}catch(e){return null}},r.diff=function(e,r){if(ee(e,r))return null;var t=F(e),n=F(r);if(t.prerelease.length||n.prerelease.length){for(var o in t)if((\"major\"===o||\"minor\"===o||\"patch\"===o)&&t[o]!==n[o])return\"pre\"+o;return\"prerelease\"}for(var o in t)if((\"major\"===o||\"minor\"===o||\"patch\"===o)&&t[o]!==n[o])return o},r.compareIdentifiers=K;var J=/^[0-9]+$/;function K(e,r){var t=J.test(e),n=J.test(r);return t&&n&&(e=+e,r=+r),t&&!n?-1:n&&!t?1:er?1:0}function Q(e,r,t){return new H(e,t).compare(new H(r,t))}function W(e,r,t){return Q(e,r,t)>0}function Y(e,r,t){return Q(e,r,t)<0}function ee(e,r,t){return 0===Q(e,r,t)}function re(e,r,t){return 0!==Q(e,r,t)}function te(e,r,t){return Q(e,r,t)>=0}function ne(e,r,t){return Q(e,r,t)<=0}function oe(e,r,t,n){var o;switch(r){case\"===\":\"object\"==typeof e&&(e=e.version),\"object\"==typeof t&&(t=t.version),o=e===t;break;case\"!==\":\"object\"==typeof e&&(e=e.version),\"object\"==typeof t&&(t=t.version),o=e!==t;break;case\"\":case\"=\":case\"==\":o=ee(e,t,n);break;case\"!=\":o=re(e,t,n);break;case\">\":o=W(e,t,n);break;case\">=\":o=te(e,t,n);break;case\"<\":o=Y(e,t,n);break;case\"<=\":o=ne(e,t,n);break;default:throw new TypeError(\"Invalid operator: \"+r)}return o}function ie(e,r){if(e instanceof ie){if(e.loose===r)return e;e=e.value}if(!(this instanceof ie))return new ie(e,r);n(\"comparator\",e,r),this.loose=r,this.parse(e),this.semver===se?this.value=\"\":this.value=this.operator+this.semver.version,n(\"comp\",this)}r.rcompareIdentifiers=function(e,r){return K(r,e)},r.major=function(e,r){return new H(e,r).major},r.minor=function(e,r){return new H(e,r).minor},r.patch=function(e,r){return new H(e,r).patch},r.compare=Q,r.compareLoose=function(e,r){return Q(e,r,!0)},r.rcompare=function(e,r,t){return Q(r,e,t)},r.sort=function(e,t){return e.sort((function(e,n){return r.compare(e,n,t)}))},r.rsort=function(e,t){return e.sort((function(e,n){return r.rcompare(e,n,t)}))},r.gt=W,r.lt=Y,r.eq=ee,r.neq=re,r.gte=te,r.lte=ne,r.cmp=oe,r.Comparator=ie;var se={};function ae(e,r){if(e instanceof ae)return e.loose===r?e:new ae(e.raw,r);if(e instanceof ie)return new ae(e.value,r);if(!(this instanceof ae))return new ae(e,r);if(this.loose=r,this.raw=e,this.set=e.split(/\\s*\\|\\|\\s*/).map((function(e){return this.parseRange(e.trim())}),this).filter((function(e){return e.length})),!this.set.length)throw new TypeError(\"Invalid SemVer Range: \"+e);this.format()}function ue(e){return!e||\"x\"===e.toLowerCase()||\"*\"===e}function ce(e,r,t,n,o,i,s,a,u,c,p,f,l){return((r=ue(t)?\"\":ue(n)?\">=\"+t+\".0.0\":ue(o)?\">=\"+t+\".\"+n+\".0\":\">=\"+r)+\" \"+(a=ue(u)?\"\":ue(c)?\"<\"+(+u+1)+\".0.0\":ue(p)?\"<\"+u+\".\"+(+c+1)+\".0\":f?\"<=\"+u+\".\"+c+\".\"+p+\"-\"+f:\"<=\"+a)).trim()}function pe(e,r){for(var t=0;t0){var o=e[t].semver;if(o.major===r.major&&o.minor===r.minor&&o.patch===r.patch)return!0}return!1}return!0}function fe(e,r,t){try{r=new ae(r,t)}catch(e){return!1}return r.test(e)}function le(e,r,t,n){var o,i,s,a,u;switch(e=new H(e,n),r=new ae(r,n),t){case\">\":o=W,i=ne,s=Y,a=\">\",u=\">=\";break;case\"<\":o=Y,i=te,s=W,a=\"<\",u=\"<=\";break;default:throw new TypeError('Must provide a hilo val of \"<\" or \">\"')}if(fe(e,r,n))return!1;for(var c=0;c=0.0.0\")),f=f||e,l=l||e,o(e.semver,f.semver,n)?f=e:s(e.semver,l.semver,n)&&(l=e)})),f.operator===a||f.operator===u)return!1;if((!l.operator||l.operator===a)&&i(e,l.semver))return!1;if(l.operator===u&&s(e,l.semver))return!1}return!0}ie.prototype.parse=function(e){var r=this.loose?s[D]:s[X],t=e.match(r);if(!t)throw new TypeError(\"Invalid comparator: \"+e);this.operator=t[1],\"=\"===this.operator&&(this.operator=\"\"),t[2]?this.semver=new H(t[2],this.loose):this.semver=se},ie.prototype.toString=function(){return this.value},ie.prototype.test=function(e){return n(\"Comparator.test\",e,this.loose),this.semver===se||(\"string\"==typeof e&&(e=new H(e,this.loose)),oe(e,this.operator,this.semver,this.loose))},ie.prototype.intersects=function(e,r){if(!(e instanceof ie))throw new TypeError(\"a Comparator is required\");var t;if(\"\"===this.operator)return t=new ae(e.value,r),fe(this.value,t,r);if(\"\"===e.operator)return t=new ae(this.value,r),fe(e.semver,t,r);var n=!(\">=\"!==this.operator&&\">\"!==this.operator||\">=\"!==e.operator&&\">\"!==e.operator),o=!(\"<=\"!==this.operator&&\"<\"!==this.operator||\"<=\"!==e.operator&&\"<\"!==e.operator),i=this.semver.version===e.semver.version,s=!(\">=\"!==this.operator&&\"<=\"!==this.operator||\">=\"!==e.operator&&\"<=\"!==e.operator),a=oe(this.semver,\"<\",e.semver,r)&&(\">=\"===this.operator||\">\"===this.operator)&&(\"<=\"===e.operator||\"<\"===e.operator),u=oe(this.semver,\">\",e.semver,r)&&(\"<=\"===this.operator||\"<\"===this.operator)&&(\">=\"===e.operator||\">\"===e.operator);return n||o||i&&s||a||u},r.Range=ae,ae.prototype.format=function(){return this.range=this.set.map((function(e){return e.join(\" \").trim()})).join(\"||\").trim(),this.range},ae.prototype.toString=function(){return this.range},ae.prototype.parseRange=function(e){var r=this.loose;e=e.trim(),n(\"range\",e,r);var t=r?s[Z]:s[G];e=e.replace(t,ce),n(\"hyphen replace\",e),e=e.replace(s[z],\"$1$2$3\"),n(\"comparator trim\",e,s[z]),e=(e=(e=e.replace(s[M],\"$1~\")).replace(s[L],\"$1^\")).split(/\\s+/).join(\" \");var o=r?s[D]:s[X],i=e.split(\" \").map((function(e){return function(e,r){return n(\"comp\",e),e=function(e,r){return e.trim().split(/\\s+/).map((function(e){return function(e,r){n(\"caret\",e,r);var t=r?s[q]:s[N];return e.replace(t,(function(r,t,o,i,s){var a;return n(\"caret\",e,r,t,o,i,s),ue(t)?a=\"\":ue(o)?a=\">=\"+t+\".0.0 <\"+(+t+1)+\".0.0\":ue(i)?a=\"0\"===t?\">=\"+t+\".\"+o+\".0 <\"+t+\".\"+(+o+1)+\".0\":\">=\"+t+\".\"+o+\".0 <\"+(+t+1)+\".0.0\":s?(n(\"replaceCaret pr\",s),\"-\"!==s.charAt(0)&&(s=\"-\"+s),a=\"0\"===t?\"0\"===o?\">=\"+t+\".\"+o+\".\"+i+s+\" <\"+t+\".\"+o+\".\"+(+i+1):\">=\"+t+\".\"+o+\".\"+i+s+\" <\"+t+\".\"+(+o+1)+\".0\":\">=\"+t+\".\"+o+\".\"+i+s+\" <\"+(+t+1)+\".0.0\"):(n(\"no pr\"),a=\"0\"===t?\"0\"===o?\">=\"+t+\".\"+o+\".\"+i+\" <\"+t+\".\"+o+\".\"+(+i+1):\">=\"+t+\".\"+o+\".\"+i+\" <\"+t+\".\"+(+o+1)+\".0\":\">=\"+t+\".\"+o+\".\"+i+\" <\"+(+t+1)+\".0.0\"),n(\"caret return\",a),a}))}(e,r)})).join(\" \")}(e,r),n(\"caret\",e),e=function(e,r){return e.trim().split(/\\s+/).map((function(e){return function(e,r){var t=r?s[P]:s[V];return e.replace(t,(function(r,t,o,i,s){var a;return n(\"tilde\",e,r,t,o,i,s),ue(t)?a=\"\":ue(o)?a=\">=\"+t+\".0.0 <\"+(+t+1)+\".0.0\":ue(i)?a=\">=\"+t+\".\"+o+\".0 <\"+t+\".\"+(+o+1)+\".0\":s?(n(\"replaceTilde pr\",s),\"-\"!==s.charAt(0)&&(s=\"-\"+s),a=\">=\"+t+\".\"+o+\".\"+i+s+\" <\"+t+\".\"+(+o+1)+\".0\"):a=\">=\"+t+\".\"+o+\".\"+i+\" <\"+t+\".\"+(+o+1)+\".0\",n(\"tilde return\",a),a}))}(e,r)})).join(\" \")}(e,r),n(\"tildes\",e),e=function(e,r){return n(\"replaceXRanges\",e,r),e.split(/\\s+/).map((function(e){return function(e,r){e=e.trim();var t=r?s[_]:s[I];return e.replace(t,(function(r,t,o,i,s,a){n(\"xRange\",e,r,t,o,i,s,a);var u=ue(o),c=u||ue(i),p=c||ue(s);return\"=\"===t&&p&&(t=\"\"),u?r=\">\"===t||\"<\"===t?\"<0.0.0\":\"*\":t&&p?(c&&(i=0),p&&(s=0),\">\"===t?(t=\">=\",c?(o=+o+1,i=0,s=0):p&&(i=+i+1,s=0)):\"<=\"===t&&(t=\"<\",c?o=+o+1:i=+i+1),r=t+o+\".\"+i+\".\"+s):c?r=\">=\"+o+\".0.0 <\"+(+o+1)+\".0.0\":p&&(r=\">=\"+o+\".\"+i+\".0 <\"+o+\".\"+(+i+1)+\".0\"),n(\"xRange return\",r),r}))}(e,r)})).join(\" \")}(e,r),n(\"xrange\",e),e=function(e,r){return n(\"replaceStars\",e,r),e.trim().replace(s[B],\"\")}(e,r),n(\"stars\",e),e}(e,r)})).join(\" \").split(/\\s+/);return this.loose&&(i=i.filter((function(e){return!!e.match(o)}))),i=i.map((function(e){return new ie(e,r)}))},ae.prototype.intersects=function(e,r){if(!(e instanceof ae))throw new TypeError(\"a Range is required\");return this.set.some((function(t){return t.every((function(t){return e.set.some((function(e){return e.every((function(e){return t.intersects(e,r)}))}))}))}))},r.toComparators=function(e,r){return new ae(e,r).set.map((function(e){return e.map((function(e){return e.value})).join(\" \").trim().split(\" \")}))},ae.prototype.test=function(e){if(!e)return!1;\"string\"==typeof e&&(e=new H(e,this.loose));for(var r=0;r\",t)},r.outside=le,r.prerelease=function(e,r){var t=F(e,r);return t&&t.prerelease.length?t.prerelease:null},r.intersects=function(e,r,t){return e=new ae(e,t),r=new ae(r,t),e.intersects(r)},r.coerce=function(e){if(e instanceof H)return e;if(\"string\"!=typeof e)return null;var r=e.match(s[O]);return null==r?null:F((r[1]||\"0\")+\".\"+(r[2]||\"0\")+\".\"+(r[3]||\"0\"))}}).call(this,t(1))},function(e,r){var t,n,o=e.exports={};function i(){throw new Error(\"setTimeout has not been defined\")}function s(){throw new Error(\"clearTimeout has not been defined\")}function a(e){if(t===setTimeout)return setTimeout(e,0);if((t===i||!t)&&setTimeout)return t=setTimeout,setTimeout(e,0);try{return t(e,0)}catch(r){try{return t.call(null,e,0)}catch(r){return t.call(this,e,0)}}}!function(){try{t=\"function\"==typeof setTimeout?setTimeout:i}catch(e){t=i}try{n=\"function\"==typeof clearTimeout?clearTimeout:s}catch(e){n=s}}();var u,c=[],p=!1,f=-1;function l(){p&&u&&(p=!1,u.length?c=u.concat(c):f=-1,c.length&&h())}function h(){if(!p){var e=a(l);p=!0;for(var r=c.length;r;){for(u=c,c=[];++f1)for(var t=1;t {\n\treadonly forward: Node[];\n\tconstructor(readonly level: number, readonly key: K, public value: V) {\n\t\tthis.forward = [];\n\t}\n}\n\nconst NIL: undefined = undefined;\n\ninterface Comparator {\n\t(a: K, b: K): number;\n}\n\nexport class SkipList implements Map {\n\n\treadonly [Symbol.toStringTag] = 'SkipList';\n\n\tprivate _maxLevel: number;\n\tprivate _level: number = 0;\n\tprivate _header: Node;\n\tprivate _size: number = 0;\n\n\t/**\n\t *\n\t * @param capacity Capacity at which the list performs best\n\t */\n\tconstructor(\n\t\treadonly comparator: (a: K, b: K) => number,\n\t\tcapacity: number = 2 ** 16\n\t) {\n\t\tthis._maxLevel = Math.max(1, Math.log2(capacity) | 0);\n\t\tthis._header = new Node(this._maxLevel, NIL, NIL);\n\t}\n\n\tget size(): number {\n\t\treturn this._size;\n\t}\n\n\tclear(): void {\n\t\tthis._header = new Node(this._maxLevel, NIL, NIL);\n\t\tthis._size = 0;\n\t}\n\n\thas(key: K): boolean {\n\t\treturn Boolean(SkipList._search(this, key, this.comparator));\n\t}\n\n\tget(key: K): V | undefined {\n\t\treturn SkipList._search(this, key, this.comparator)?.value;\n\t}\n\n\tset(key: K, value: V): this {\n\t\tif (SkipList._insert(this, key, value, this.comparator)) {\n\t\t\tthis._size += 1;\n\t\t}\n\t\treturn this;\n\t}\n\n\tdelete(key: K): boolean {\n\t\tconst didDelete = SkipList._delete(this, key, this.comparator);\n\t\tif (didDelete) {\n\t\t\tthis._size -= 1;\n\t\t}\n\t\treturn didDelete;\n\t}\n\n\t// --- iteration\n\n\tforEach(callbackfn: (value: V, key: K, map: Map) => void, thisArg?: any): void {\n\t\tlet node = this._header.forward[0];\n\t\twhile (node) {\n\t\t\tcallbackfn.call(thisArg, node.value, node.key, this);\n\t\t\tnode = node.forward[0];\n\t\t}\n\t}\n\n\t[Symbol.iterator](): IterableIterator<[K, V]> {\n\t\treturn this.entries();\n\t}\n\n\t*entries(): IterableIterator<[K, V]> {\n\t\tlet node = this._header.forward[0];\n\t\twhile (node) {\n\t\t\tyield [node.key, node.value];\n\t\t\tnode = node.forward[0];\n\t\t}\n\t}\n\n\t*keys(): IterableIterator {\n\t\tlet node = this._header.forward[0];\n\t\twhile (node) {\n\t\t\tyield node.key;\n\t\t\tnode = node.forward[0];\n\t\t}\n\t}\n\n\t*values(): IterableIterator {\n\t\tlet node = this._header.forward[0];\n\t\twhile (node) {\n\t\t\tyield node.value;\n\t\t\tnode = node.forward[0];\n\t\t}\n\t}\n\n\ttoString(): string {\n\t\t// debug string...\n\t\tlet result = '[SkipList]:';\n\t\tlet node = this._header.forward[0];\n\t\twhile (node) {\n\t\t\tresult += `node(${node.key}, ${node.value}, lvl:${node.level})`;\n\t\t\tnode = node.forward[0];\n\t\t}\n\t\treturn result;\n\t}\n\n\t// from https://www.epaperpress.com/sortsearch/download/skiplist.pdf\n\n\tprivate static _search(list: SkipList, searchKey: K, comparator: Comparator) {\n\t\tlet x = list._header;\n\t\tfor (let i = list._level - 1; i >= 0; i--) {\n\t\t\twhile (x.forward[i] && comparator(x.forward[i].key, searchKey) < 0) {\n\t\t\t\tx = x.forward[i];\n\t\t\t}\n\t\t}\n\t\tx = x.forward[0];\n\t\tif (x && comparator(x.key, searchKey) === 0) {\n\t\t\treturn x;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tprivate static _insert(list: SkipList, searchKey: K, value: V, comparator: Comparator) {\n\t\tconst update: Node[] = [];\n\t\tlet x = list._header;\n\t\tfor (let i = list._level - 1; i >= 0; i--) {\n\t\t\twhile (x.forward[i] && comparator(x.forward[i].key, searchKey) < 0) {\n\t\t\t\tx = x.forward[i];\n\t\t\t}\n\t\t\tupdate[i] = x;\n\t\t}\n\t\tx = x.forward[0];\n\t\tif (x && comparator(x.key, searchKey) === 0) {\n\t\t\t// update\n\t\t\tx.value = value;\n\t\t\treturn false;\n\t\t} else {\n\t\t\t// insert\n\t\t\tconst lvl = SkipList._randomLevel(list);\n\t\t\tif (lvl > list._level) {\n\t\t\t\tfor (let i = list._level; i < lvl; i++) {\n\t\t\t\t\tupdate[i] = list._header;\n\t\t\t\t}\n\t\t\t\tlist._level = lvl;\n\t\t\t}\n\t\t\tx = new Node(lvl, searchKey, value);\n\t\t\tfor (let i = 0; i < lvl; i++) {\n\t\t\t\tx.forward[i] = update[i].forward[i];\n\t\t\t\tupdate[i].forward[i] = x;\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\t}\n\n\tprivate static _randomLevel(list: SkipList, p: number = 0.5): number {\n\t\tlet lvl = 1;\n\t\twhile (Math.random() < p && lvl < list._maxLevel) {\n\t\t\tlvl += 1;\n\t\t}\n\t\treturn lvl;\n\t}\n\n\tprivate static _delete(list: SkipList, searchKey: K, comparator: Comparator) {\n\t\tconst update: Node[] = [];\n\t\tlet x = list._header;\n\t\tfor (let i = list._level - 1; i >= 0; i--) {\n\t\t\twhile (x.forward[i] && comparator(x.forward[i].key, searchKey) < 0) {\n\t\t\t\tx = x.forward[i];\n\t\t\t}\n\t\t\tupdate[i] = x;\n\t\t}\n\t\tx = x.forward[0];\n\t\tif (!x || comparator(x.key, searchKey) !== 0) {\n\t\t\t// not found\n\t\t\treturn false;\n\t\t}\n\t\tfor (let i = 0; i < list._level; i++) {\n\t\t\tif (update[i].forward[i] !== x) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tupdate[i].forward[i] = x.forward[i];\n\t\t}\n\t\twhile (list._level > 0 && list._header.forward[list._level - 1] === NIL) {\n\t\t\tlist._level -= 1;\n\t\t}\n\t\treturn true;\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\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","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { onUnexpectedError } from 'vs/base/common/errors';\nimport { createSingleCallFunction } from 'vs/base/common/functional';\nimport { combinedDisposable, Disposable, DisposableMap, 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 an emitter with listeners is disposed. That is a sign of code smell.\n// -----------------------------------------------------------------------------------------------------------------------\nconst _enableDisposeWithListenerWarning = false;\n// _enableDisposeWithListenerWarning = Boolean(\"TRUE\"); // causes a linter warning so that it cannot be pushed\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// _enableSnapshotPotentialLeakWarning = Boolean(\"TRUE\"); // causes a linter warning so that it cannot be pushed\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;\nexport function setGlobalLeakWarningThreshold(n: number): IDisposable {\n\tconst oldValue = _globalLeakWarningThreshold;\n\t_globalLeakWarningThreshold = n;\n\treturn {\n\t\tdispose() {\n\t\t\t_globalLeakWarningThreshold = oldValue;\n\t\t}\n\t};\n}\n\nclass LeakageMonitor {\n\n\tprivate _stacks: Map | undefined;\n\tprivate _warnCountdown: number = 0;\n\n\tconstructor(\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\t// find most frequent listener and print warning\n\t\t\tlet topStack: string | undefined;\n\t\t\tlet topCount: number = 0;\n\t\t\tfor (const [stack, count] of this._stacks) {\n\t\t\t\tif (!topStack || topCount < count) {\n\t\t\t\t\ttopStack = stack;\n\t\t\t\t\ttopCount = count;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconsole.warn(`[${this.name}] potential listener LEAK detected, having ${listenerCount} listeners already. MOST frequent listener (${topCount}):`);\n\t\t\tconsole.warn(topStack!);\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\nclass Stacktrace {\n\n\tstatic create() {\n\t\treturn new Stacktrace(new Error().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\nlet id = 0;\nclass UniqueContainer {\n\tstack?: Stacktrace;\n\tpublic id = id++;\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/**\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 ? new LeakageMonitor(this._options?.leakWarningThreshold ?? _globalLeakWarningThreshold) : undefined;\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 * 3) {\n\t\t\t\tconsole.warn(`[${this._leakageMon.name}] REFUSES to accept new listeners because it exceeded its threshold by far`);\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\t\t\tconst result = toDisposable(() => { removeMonitor?.(); this._removeListener(contained); });\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\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\t_isEventDeliveryQueue: true;\n}\n\nexport const createEventDeliveryQueue = (): EventDeliveryQueue => new EventDeliveryQueuePrivate();\n\nclass EventDeliveryQueuePrivate implements EventDeliveryQueue {\n\tdeclare _isEventDeliveryQueue: true;\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\nexport interface IWaitUntil {\n\ttoken: CancellationToken;\n\twaitUntil(thenable: Promise): void;\n}\n\nexport type IWaitUntilData = Omit, 'token'>;\n\nexport class AsyncEmitter extends Emitter {\n\n\tprivate _asyncDeliveryQueue?: LinkedList<[(ev: T) => void, IWaitUntilData]>;\n\n\tasync fireAsync(data: IWaitUntilData, token: CancellationToken, promiseJoin?: (p: Promise, listener: Function) => Promise): Promise {\n\t\tif (!this._listeners) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this._asyncDeliveryQueue) {\n\t\t\tthis._asyncDeliveryQueue = new LinkedList();\n\t\t}\n\n\t\tforEachListener(this._listeners, listener => this._asyncDeliveryQueue!.push([listener.value, data]));\n\n\t\twhile (this._asyncDeliveryQueue.size > 0 && !token.isCancellationRequested) {\n\n\t\t\tconst [listener, data] = this._asyncDeliveryQueue.shift()!;\n\t\t\tconst thenables: Promise[] = [];\n\n\t\t\tconst event = {\n\t\t\t\t...data,\n\t\t\t\ttoken,\n\t\t\t\twaitUntil: (p: Promise): void => {\n\t\t\t\t\tif (Object.isFrozen(thenables)) {\n\t\t\t\t\t\tthrow new Error('waitUntil can NOT be called asynchronous');\n\t\t\t\t\t}\n\t\t\t\t\tif (promiseJoin) {\n\t\t\t\t\t\tp = promiseJoin(p, listener);\n\t\t\t\t\t}\n\t\t\t\t\tthenables.push(p);\n\t\t\t\t}\n\t\t\t};\n\n\t\t\ttry {\n\t\t\t\tlistener(event);\n\t\t\t} catch (e) {\n\t\t\t\tonUnexpectedError(e);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// freeze thenables-collection to enforce sync-calls to\n\t\t\t// wait until and then wait for all thenables to resolve\n\t\t\tObject.freeze(thenables);\n\n\t\t\tawait Promise.allSettled(thenables).then(values => {\n\t\t\t\tfor (const value of values) {\n\t\t\t\t\tif (value.status === 'rejected') {\n\t\t\t\t\t\tonUnexpectedError(value.reason);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t}\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\tpublic get isPaused(): boolean {\n\t\treturn this._isPaused !== 0;\n\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\nexport interface IDynamicListEventMultiplexer extends IDisposable {\n\treadonly event: Event;\n}\nexport class DynamicListEventMultiplexer implements IDynamicListEventMultiplexer {\n\tprivate readonly _store = new DisposableStore();\n\n\treadonly event: Event;\n\n\tconstructor(\n\t\titems: TItem[],\n\t\tonAddItem: Event,\n\t\tonRemoveItem: Event,\n\t\tgetEvent: (item: TItem) => Event\n\t) {\n\t\tconst multiplexer = this._store.add(new EventMultiplexer());\n\t\tconst itemListeners = this._store.add(new DisposableMap());\n\n\t\tfunction addItem(instance: TItem) {\n\t\t\titemListeners.set(instance, multiplexer.add(getEvent(instance)));\n\t\t}\n\n\t\t// Existing items\n\t\tfor (const instance of items) {\n\t\t\taddItem(instance);\n\t\t}\n\n\t\t// Added items\n\t\tthis._store.add(onAddItem(instance => {\n\t\t\taddItem(instance);\n\t\t}));\n\n\t\t// Removed items\n\t\tthis._store.add(onRemoveItem(instance => {\n\t\t\titemListeners.deleteAndDispose(instance);\n\t\t}));\n\n\t\tthis.event = multiplexer.event;\n\t}\n\n\tdispose() {\n\t\tthis._store.dispose();\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 buffers: Function[][] = [];\n\n\twrapEvent(event: Event): Event {\n\t\treturn (listener, thisArgs?, disposables?) => {\n\t\t\treturn event(i => {\n\t\t\t\tconst buffer = this.buffers[this.buffers.length - 1];\n\n\t\t\t\tif (buffer) {\n\t\t\t\t\tbuffer.push(() => listener.call(thisArgs, i));\n\t\t\t\t} else {\n\t\t\t\t\tlistener.call(thisArgs, i);\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 buffer: Array<() => R> = [];\n\t\tthis.buffers.push(buffer);\n\t\tconst r = fn();\n\t\tthis.buffers.pop();\n\t\tbuffer.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","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { getErrorMessage } from 'vs/base/common/errors';\nimport { Emitter } from 'vs/base/common/event';\nimport { Disposable, toDisposable } from 'vs/base/common/lifecycle';\n\nexport class BroadcastDataChannel extends Disposable {\n\n\tprivate broadcastChannel: BroadcastChannel | undefined;\n\n\tprivate readonly _onDidReceiveData = this._register(new Emitter());\n\treadonly onDidReceiveData = this._onDidReceiveData.event;\n\n\tconstructor(private readonly channelName: string) {\n\t\tsuper();\n\n\t\t// Use BroadcastChannel\n\t\tif ('BroadcastChannel' in mainWindow) {\n\t\t\ttry {\n\t\t\t\tthis.broadcastChannel = new BroadcastChannel(channelName);\n\t\t\t\tconst listener = (event: MessageEvent) => {\n\t\t\t\t\tthis._onDidReceiveData.fire(event.data);\n\t\t\t\t};\n\t\t\t\tthis.broadcastChannel.addEventListener('message', listener);\n\t\t\t\tthis._register(toDisposable(() => {\n\t\t\t\t\tif (this.broadcastChannel) {\n\t\t\t\t\t\tthis.broadcastChannel.removeEventListener('message', listener);\n\t\t\t\t\t\tthis.broadcastChannel.close();\n\t\t\t\t\t}\n\t\t\t\t}));\n\t\t\t} catch (error) {\n\t\t\t\tconsole.warn('Error while creating broadcast channel. Falling back to localStorage.', getErrorMessage(error));\n\t\t\t}\n\t\t}\n\n\t\t// BroadcastChannel is not supported. Use storage.\n\t\tif (!this.broadcastChannel) {\n\t\t\tthis.channelName = `BroadcastDataChannel.${channelName}`;\n\t\t\tthis.createBroadcastChannel();\n\t\t}\n\t}\n\n\tprivate createBroadcastChannel(): void {\n\t\tconst listener = (event: StorageEvent) => {\n\t\t\tif (event.key === this.channelName && event.newValue) {\n\t\t\t\tthis._onDidReceiveData.fire(JSON.parse(event.newValue));\n\t\t\t}\n\t\t};\n\t\tmainWindow.addEventListener('storage', listener);\n\t\tthis._register(toDisposable(() => mainWindow.removeEventListener('storage', listener)));\n\t}\n\n\t/**\n\t * Sends the data to other BroadcastChannel objects set up for this channel. Data can be structured objects, e.g. nested objects and arrays.\n\t * @param data data to broadcast\n\t */\n\tpostData(data: T): void {\n\t\tif (this.broadcastChannel) {\n\t\t\tthis.broadcastChannel.postMessage(data);\n\t\t} else {\n\t\t\t// remove previous changes so that event is triggered even if new changes are same as old changes\n\t\t\tlocalStorage.removeItem(this.channelName);\n\t\t\tlocalStorage.setItem(this.channelName, JSON.stringify(data));\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 { CodeWindow, mainWindow } from 'vs/base/browser/window';\nimport { Emitter } from 'vs/base/common/event';\n\nclass WindowManager {\n\n\tstatic readonly INSTANCE = new WindowManager();\n\n\t// --- Zoom Level\n\n\tprivate readonly mapWindowIdToZoomLevel = new Map();\n\n\tprivate readonly _onDidChangeZoomLevel = new Emitter();\n\treadonly onDidChangeZoomLevel = this._onDidChangeZoomLevel.event;\n\n\tgetZoomLevel(targetWindow: Window): number {\n\t\treturn this.mapWindowIdToZoomLevel.get(this.getWindowId(targetWindow)) ?? 0;\n\t}\n\tsetZoomLevel(zoomLevel: number, targetWindow: Window): void {\n\t\tif (this.getZoomLevel(targetWindow) === zoomLevel) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst targetWindowId = this.getWindowId(targetWindow);\n\t\tthis.mapWindowIdToZoomLevel.set(targetWindowId, zoomLevel);\n\t\tthis._onDidChangeZoomLevel.fire(targetWindowId);\n\t}\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\tsetZoomFactor(zoomFactor: number, targetWindow: Window): void {\n\t\tthis.mapWindowIdToZoomFactor.set(this.getWindowId(targetWindow), zoomFactor);\n\t}\n\n\t// --- Fullscreen\n\n\tprivate readonly _onDidChangeFullscreen = new Emitter();\n\treadonly onDidChangeFullscreen = this._onDidChangeFullscreen.event;\n\n\tprivate readonly mapWindowIdToFullScreen = new Map();\n\n\tsetFullscreen(fullscreen: boolean, targetWindow: Window): void {\n\t\tif (this.isFullscreen(targetWindow) === fullscreen) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst windowId = this.getWindowId(targetWindow);\n\t\tthis.mapWindowIdToFullScreen.set(windowId, fullscreen);\n\t\tthis._onDidChangeFullscreen.fire(windowId);\n\t}\n\tisFullscreen(targetWindow: Window): boolean {\n\t\treturn !!this.mapWindowIdToFullScreen.get(this.getWindowId(targetWindow));\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/** A zoom index, e.g. 1, 2, 3 */\nexport function setZoomLevel(zoomLevel: number, targetWindow: Window): void {\n\tWindowManager.INSTANCE.setZoomLevel(zoomLevel, targetWindow);\n}\nexport function getZoomLevel(targetWindow: Window): number {\n\treturn WindowManager.INSTANCE.getZoomLevel(targetWindow);\n}\nexport const onDidChangeZoomLevel = WindowManager.INSTANCE.onDidChangeZoomLevel;\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}\nexport function setZoomFactor(zoomFactor: number, targetWindow: Window): void {\n\tWindowManager.INSTANCE.setZoomFactor(zoomFactor, targetWindow);\n}\n\nexport function setFullscreen(fullscreen: boolean, targetWindow: Window): void {\n\tWindowManager.INSTANCE.setFullscreen(fullscreen, targetWindow);\n}\nexport function isFullscreen(targetWindow: Window): boolean {\n\treturn WindowManager.INSTANCE.isFullscreen(targetWindow);\n}\nexport const onDidChangeFullscreen = WindowManager.INSTANCE.onDidChangeFullscreen;\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// Visible means that the feature is enabled, not necessarily being rendered\n// e.g. visible is true even in fullscreen mode where the controls are hidden\n// See docs at https://developer.mozilla.org/en-US/docs/Web/API/WindowControlsOverlay/visible\nexport function isWCOEnabled(): boolean {\n\treturn (navigator as any)?.windowControlsOverlay?.visible;\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 IDomEvent {\n\t(element: EventHandler, type: K, useCapture?: boolean): BaseEvent;\n\t(element: EventHandler, type: string, useCapture?: boolean): BaseEvent;\n}\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 { 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","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { IDisposable } from 'vs/base/common/lifecycle';\n\nexport interface CacheResult extends IDisposable {\n\tpromise: Promise;\n}\n\nexport class Cache {\n\n\tprivate result: CacheResult | null = null;\n\tconstructor(private task: (ct: CancellationToken) => Promise) { }\n\n\tget(): CacheResult {\n\t\tif (this.result) {\n\t\t\treturn this.result;\n\t\t}\n\n\t\tconst cts = new CancellationTokenSource();\n\t\tconst promise = this.task(cts.token);\n\n\t\tthis.result = {\n\t\t\tpromise,\n\t\t\tdispose: () => {\n\t\t\t\tthis.result = null;\n\t\t\t\tcts.cancel();\n\t\t\t\tcts.dispose();\n\t\t\t}\n\t\t};\n\n\t\treturn this.result;\n\t}\n}\n\n/**\n * Uses a LRU cache to make a given parametrized function cached.\n * Caches just the last value.\n * The key must be JSON serializable.\n*/\nexport class LRUCachedFunction {\n\tprivate lastCache: TComputed | undefined = undefined;\n\tprivate lastArgKey: string | undefined = undefined;\n\n\tconstructor(private readonly fn: (arg: TArg) => TComputed) {\n\t}\n\n\tpublic get(arg: TArg): TComputed {\n\t\tconst key = JSON.stringify(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 (referential equality) to memoize the results of the given function.\n*/\nexport class CachedFunction {\n\tprivate readonly _map = new Map();\n\tpublic get cachedValues(): ReadonlyMap {\n\t\treturn this._map;\n\t}\n\n\tconstructor(private readonly fn: (arg: TArg) => TValue) { }\n\n\tpublic get(arg: TArg): TValue {\n\t\tif (this._map.has(arg)) {\n\t\t\treturn this._map.get(arg)!;\n\t\t}\n\t\tconst value = this.fn(arg);\n\t\tthis._map.set(arg, 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\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 *--------------------------------------------------------------------------------------------*/\nimport { autorun } from 'vs/base/common/observableInternal/autorun';\nimport { IObservable, IReader, observableValue, transaction } from './base';\nimport { Derived, defaultEqualityComparer, derived } from 'vs/base/common/observableInternal/derived';\nimport { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';\nimport { DebugNameData, Owner } from 'vs/base/common/observableInternal/debugName';\n\nexport class ObservableLazy {\n\tprivate readonly _value = observableValue(this, undefined);\n\n\t/**\n\t * The cached value.\n\t * Does not force a computation of the value.\n\t */\n\tpublic get cachedValue(): IObservable { return this._value; }\n\n\tconstructor(private readonly _computeValue: () => T) {\n\t}\n\n\t/**\n\t * Returns the cached value.\n\t * Computes the value if the value has not been cached yet.\n\t */\n\tpublic getValue() {\n\t\tlet v = this._value.get();\n\t\tif (!v) {\n\t\t\tv = this._computeValue();\n\t\t\tthis._value.set(v, undefined);\n\t\t}\n\t\treturn v;\n\t}\n}\n\n/**\n * A promise whose state is observable.\n */\nexport class ObservablePromise {\n\tprivate readonly _value = observableValue | undefined>(this, undefined);\n\n\t/**\n\t * The promise that this object wraps.\n\t */\n\tpublic readonly promise: Promise;\n\n\t/**\n\t * The current state of the promise.\n\t * Is `undefined` if the promise didn't resolve yet.\n\t */\n\tpublic readonly promiseResult: IObservable | undefined> = this._value;\n\n\tconstructor(promise: Promise) {\n\t\tthis.promise = promise.then(value => {\n\t\t\ttransaction(tx => {\n\t\t\t\t/** @description onPromiseResolved */\n\t\t\t\tthis._value.set(new PromiseResult(value, undefined), tx);\n\t\t\t});\n\t\t\treturn value;\n\t\t}, error => {\n\t\t\ttransaction(tx => {\n\t\t\t\t/** @description onPromiseRejected */\n\t\t\t\tthis._value.set(new PromiseResult(undefined, error), tx);\n\t\t\t});\n\t\t\tthrow error;\n\t\t});\n\t}\n}\n\nexport class PromiseResult {\n\tconstructor(\n\t\t/**\n\t\t * The value of the resolved promise.\n\t\t * Undefined if the promise rejected.\n\t\t */\n\t\tpublic readonly data: T | undefined,\n\n\t\t/**\n\t\t * The error in case of a rejected promise.\n\t\t * Undefined if the promise resolved.\n\t\t */\n\t\tpublic readonly error: unknown | undefined,\n\t) {\n\t}\n\n\t/**\n\t * Returns the value if the promise resolved, otherwise throws the error.\n\t */\n\tpublic getDataOrThrow(): T {\n\t\tif (this.error) {\n\t\t\tthrow this.error;\n\t\t}\n\t\treturn this.data!;\n\t}\n}\n\n/**\n * A lazy promise whose state is observable.\n */\nexport class ObservableLazyPromise {\n\tprivate readonly _lazyValue = new ObservableLazy(() => new ObservablePromise(this._computePromise()));\n\n\t/**\n\t * Does not enforce evaluation of the promise compute function.\n\t * Is undefined if the promise has not been computed yet.\n\t */\n\tpublic readonly cachedPromiseResult = derived(this, reader => this._lazyValue.cachedValue.read(reader)?.promiseResult.read(reader));\n\n\tconstructor(private readonly _computePromise: () => Promise) {\n\t}\n\n\tpublic getPromise(): Promise {\n\t\treturn this._lazyValue.getValue().promise;\n\t}\n}\n\n/**\n * Resolves the promise when the observables state matches the predicate.\n */\nexport function waitForState(observable: IObservable, predicate: (state: T) => state is TState, isError?: (state: T) => boolean | unknown | undefined): Promise;\nexport function waitForState(observable: IObservable, predicate: (state: T) => boolean, isError?: (state: T) => boolean | unknown | undefined): Promise;\nexport function waitForState(observable: IObservable, predicate: (state: T) => boolean, isError?: (state: T) => boolean | unknown | undefined): Promise {\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\tisImmediateRun = false;\n\t\tif (shouldDispose) {\n\t\t\td.dispose();\n\t\t}\n\t});\n}\n\nexport function derivedWithCancellationToken(computeFn: (reader: IReader, cancellationToken: CancellationToken) => T): IObservable;\nexport function derivedWithCancellationToken(owner: object, computeFn: (reader: IReader, cancellationToken: CancellationToken) => T): IObservable;\nexport function derivedWithCancellationToken(computeFnOrOwner: ((reader: IReader, cancellationToken: CancellationToken) => T) | object, computeFnOrUndefined?: ((reader: IReader, cancellationToken: CancellationToken) => T)): IObservable {\n\tlet computeFn: (reader: IReader, store: CancellationToken) => 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\tlet cancellationTokenSource: CancellationTokenSource | undefined = undefined;\n\treturn new Derived(\n\t\tnew DebugNameData(owner, undefined, computeFn),\n\t\tr => {\n\t\t\tif (cancellationTokenSource) {\n\t\t\t\tcancellationTokenSource.dispose(true);\n\t\t\t}\n\t\t\tcancellationTokenSource = new CancellationTokenSource();\n\t\t\treturn computeFn(r, cancellationTokenSource.token);\n\t\t}, undefined,\n\t\tundefined,\n\t\t() => cancellationTokenSource?.dispose(),\n\t\tdefaultEqualityComparer,\n\t);\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (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,\n\tIChangeTracker,\n\tobservableValue,\n\tdisposableObservableValue,\n\ttransaction,\n\tsubtransaction,\n} from 'vs/base/common/observableInternal/base';\nexport {\n\tderived,\n\tderivedOpts,\n\tderivedHandleChanges,\n\tderivedWithStore,\n} from 'vs/base/common/observableInternal/derived';\nexport {\n\tautorun,\n\tautorunDelta,\n\tautorunHandleChanges,\n\tautorunWithStore,\n\tautorunOpts,\n\tautorunWithStoreHandleChanges,\n} from 'vs/base/common/observableInternal/autorun';\nexport {\n\tIObservableSignal,\n\tconstObservable,\n\tdebouncedObservable,\n\tderivedObservableWithCache,\n\tderivedObservableWithWritableCache,\n\tkeepObserved,\n\trecomputeInitiallyAndOnChange,\n\tobservableFromEvent,\n\tobservableFromPromise,\n\tobservableSignal,\n\tobservableSignalFromEvent,\n\twasEventTriggeredRecently,\n} from 'vs/base/common/observableInternal/utils';\nexport {\n\tObservableLazy,\n\tObservableLazyPromise,\n\tObservablePromise,\n\tPromiseResult,\n\twaitForState,\n\tderivedWithCancellationToken,\n} 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 { range } from 'vs/base/common/arrays';\nimport { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';\nimport { CancellationError } from 'vs/base/common/errors';\n\n/**\n * A Pager is a stateless abstraction over a paged collection.\n */\nexport interface IPager {\n\tfirstPage: T[];\n\ttotal: number;\n\tpageSize: number;\n\tgetPage(pageIndex: number, cancellationToken: CancellationToken): Promise;\n}\n\ninterface IPage {\n\tisResolved: boolean;\n\tpromise: Promise | null;\n\tcts: CancellationTokenSource | null;\n\tpromiseIndexes: Set;\n\telements: T[];\n}\n\nfunction createPage(elements?: T[]): IPage {\n\treturn {\n\t\tisResolved: !!elements,\n\t\tpromise: null,\n\t\tcts: null,\n\t\tpromiseIndexes: new Set(),\n\t\telements: elements || []\n\t};\n}\n\n/**\n * A PagedModel is a stateful model over an abstracted paged collection.\n */\nexport interface IPagedModel {\n\tlength: number;\n\tisResolved(index: number): boolean;\n\tget(index: number): T;\n\tresolve(index: number, cancellationToken: CancellationToken): Promise;\n}\n\nexport function singlePagePager(elements: T[]): IPager {\n\treturn {\n\t\tfirstPage: elements,\n\t\ttotal: elements.length,\n\t\tpageSize: elements.length,\n\t\tgetPage: (pageIndex: number, cancellationToken: CancellationToken): Promise => {\n\t\t\treturn Promise.resolve(elements);\n\t\t}\n\t};\n}\n\nexport class PagedModel implements IPagedModel {\n\n\tprivate pager: IPager;\n\tprivate pages: IPage[] = [];\n\n\tget length(): number { return this.pager.total; }\n\n\tconstructor(arg: IPager | T[]) {\n\t\tthis.pager = Array.isArray(arg) ? singlePagePager(arg) : arg;\n\n\t\tconst totalPages = Math.ceil(this.pager.total / this.pager.pageSize);\n\n\t\tthis.pages = [\n\t\t\tcreatePage(this.pager.firstPage.slice()),\n\t\t\t...range(totalPages - 1).map(() => createPage())\n\t\t];\n\t}\n\n\tisResolved(index: number): boolean {\n\t\tconst pageIndex = Math.floor(index / this.pager.pageSize);\n\t\tconst page = this.pages[pageIndex];\n\n\t\treturn !!page.isResolved;\n\t}\n\n\tget(index: number): T {\n\t\tconst pageIndex = Math.floor(index / this.pager.pageSize);\n\t\tconst indexInPage = index % this.pager.pageSize;\n\t\tconst page = this.pages[pageIndex];\n\n\t\treturn page.elements[indexInPage];\n\t}\n\n\tresolve(index: number, cancellationToken: CancellationToken): Promise {\n\t\tif (cancellationToken.isCancellationRequested) {\n\t\t\treturn Promise.reject(new CancellationError());\n\t\t}\n\n\t\tconst pageIndex = Math.floor(index / this.pager.pageSize);\n\t\tconst indexInPage = index % this.pager.pageSize;\n\t\tconst page = this.pages[pageIndex];\n\n\t\tif (page.isResolved) {\n\t\t\treturn Promise.resolve(page.elements[indexInPage]);\n\t\t}\n\n\t\tif (!page.promise) {\n\t\t\tpage.cts = new CancellationTokenSource();\n\t\t\tpage.promise = this.pager.getPage(pageIndex, page.cts.token)\n\t\t\t\t.then(elements => {\n\t\t\t\t\tpage.elements = elements;\n\t\t\t\t\tpage.isResolved = true;\n\t\t\t\t\tpage.promise = null;\n\t\t\t\t\tpage.cts = null;\n\t\t\t\t}, err => {\n\t\t\t\t\tpage.isResolved = false;\n\t\t\t\t\tpage.promise = null;\n\t\t\t\t\tpage.cts = null;\n\t\t\t\t\treturn Promise.reject(err);\n\t\t\t\t});\n\t\t}\n\n\t\tconst listener = cancellationToken.onCancellationRequested(() => {\n\t\t\tif (!page.cts) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tpage.promiseIndexes.delete(index);\n\n\t\t\tif (page.promiseIndexes.size === 0) {\n\t\t\t\tpage.cts.cancel();\n\t\t\t}\n\t\t});\n\n\t\tpage.promiseIndexes.add(index);\n\n\t\treturn page.promise.then(() => page.elements[indexInPage])\n\t\t\t.finally(() => listener.dispose());\n\t}\n}\n\nexport class DelayedPagedModel implements IPagedModel {\n\n\tget length(): number { return this.model.length; }\n\n\tconstructor(private model: IPagedModel, private timeout: number = 500) { }\n\n\tisResolved(index: number): boolean {\n\t\treturn this.model.isResolved(index);\n\t}\n\n\tget(index: number): T {\n\t\treturn this.model.get(index);\n\t}\n\n\tresolve(index: number, cancellationToken: CancellationToken): Promise {\n\t\treturn new Promise((c, e) => {\n\t\t\tif (cancellationToken.isCancellationRequested) {\n\t\t\t\treturn e(new CancellationError());\n\t\t\t}\n\n\t\t\tconst timer = setTimeout(() => {\n\t\t\t\tif (cancellationToken.isCancellationRequested) {\n\t\t\t\t\treturn e(new CancellationError());\n\t\t\t\t}\n\n\t\t\t\ttimeoutCancellation.dispose();\n\t\t\t\tthis.model.resolve(index, cancellationToken).then(c, e);\n\t\t\t}, this.timeout);\n\n\t\t\tconst timeoutCancellation = cancellationToken.onCancellationRequested(() => {\n\t\t\t\tclearTimeout(timer);\n\t\t\t\ttimeoutCancellation.dispose();\n\t\t\t\te(new CancellationError());\n\t\t\t});\n\t\t});\n\t}\n}\n\n/**\n * Similar to array.map, `mapPager` lets you map the elements of an\n * abstract paged collection to another type.\n */\nexport function mapPager(pager: IPager, fn: (t: T) => R): IPager {\n\treturn {\n\t\tfirstPage: pager.firstPage.map(fn),\n\t\ttotal: pager.total,\n\t\tpageSize: pager.pageSize,\n\t\tgetPage: (pageIndex, token) => pager.getPage(pageIndex, token).then(r => r.map(fn))\n\t};\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { CancellationToken } from 'vs/base/common/cancellation';\nimport { onUnexpectedError } from 'vs/base/common/errors';\nimport { DisposableStore, toDisposable } from 'vs/base/common/lifecycle';\n\n/**\n * The payload that flows in readable stream events.\n */\nexport type ReadableStreamEventPayload = T | Error | 'end';\n\nexport interface ReadableStreamEvents {\n\n\t/**\n\t * The 'data' event is emitted whenever the stream is\n\t * relinquishing ownership of a chunk of data to a consumer.\n\t *\n\t * NOTE: PLEASE UNDERSTAND THAT ADDING A DATA LISTENER CAN\n\t * TURN THE STREAM INTO FLOWING MODE. IT IS THEREFOR THE\n\t * LAST LISTENER THAT SHOULD BE ADDED AND NOT THE FIRST\n\t *\n\t * Use `listenStream` as a helper method to listen to\n\t * stream events in the right order.\n\t */\n\ton(event: 'data', callback: (data: T) => void): void;\n\n\t/**\n\t * Emitted when any error occurs.\n\t */\n\ton(event: 'error', callback: (err: Error) => void): void;\n\n\t/**\n\t * The 'end' event is emitted when there is no more data\n\t * to be consumed from the stream. The 'end' event will\n\t * not be emitted unless the data is completely consumed.\n\t */\n\ton(event: 'end', callback: () => void): void;\n}\n\n/**\n * A interface that emulates the API shape of a node.js readable\n * stream for use in native and web environments.\n */\nexport interface ReadableStream extends ReadableStreamEvents {\n\n\t/**\n\t * Stops emitting any events until resume() is called.\n\t */\n\tpause(): void;\n\n\t/**\n\t * Starts emitting events again after pause() was called.\n\t */\n\tresume(): void;\n\n\t/**\n\t * Destroys the stream and stops emitting any event.\n\t */\n\tdestroy(): void;\n\n\t/**\n\t * Allows to remove a listener that was previously added.\n\t */\n\tremoveListener(event: string, callback: Function): void;\n}\n\n/**\n * A interface that emulates the API shape of a node.js readable\n * for use in native and web environments.\n */\nexport interface Readable {\n\n\t/**\n\t * Read data from the underlying source. Will return\n\t * null to indicate that no more data can be read.\n\t */\n\tread(): T | null;\n}\n\nexport function isReadable(obj: unknown): obj is Readable {\n\tconst candidate = obj as Readable | undefined;\n\tif (!candidate) {\n\t\treturn false;\n\t}\n\n\treturn typeof candidate.read === 'function';\n}\n\n/**\n * A interface that emulates the API shape of a node.js writeable\n * stream for use in native and web environments.\n */\nexport interface WriteableStream extends ReadableStream {\n\n\t/**\n\t * Writing data to the stream will trigger the on('data')\n\t * event listener if the stream is flowing and buffer the\n\t * data otherwise until the stream is flowing.\n\t *\n\t * If a `highWaterMark` is configured and writing to the\n\t * stream reaches this mark, a promise will be returned\n\t * that should be awaited on before writing more data.\n\t * Otherwise there is a risk of buffering a large number\n\t * of data chunks without consumer.\n\t */\n\twrite(data: T): void | Promise;\n\n\t/**\n\t * Signals an error to the consumer of the stream via the\n\t * on('error') handler if the stream is flowing.\n\t *\n\t * NOTE: call `end` to signal that the stream has ended,\n\t * this DOES NOT happen automatically from `error`.\n\t */\n\terror(error: Error): void;\n\n\t/**\n\t * Signals the end of the stream to the consumer. If the\n\t * result is provided, will trigger the on('data') event\n\t * listener if the stream is flowing and buffer the data\n\t * otherwise until the stream is flowing.\n\t */\n\tend(result?: T): void;\n}\n\n/**\n * A stream that has a buffer already read. Returns the original stream\n * that was read as well as the chunks that got read.\n *\n * The `ended` flag indicates if the stream has been fully consumed.\n */\nexport interface ReadableBufferedStream {\n\n\t/**\n\t * The original stream that is being read.\n\t */\n\tstream: ReadableStream;\n\n\t/**\n\t * An array of chunks already read from this stream.\n\t */\n\tbuffer: T[];\n\n\t/**\n\t * Signals if the stream has ended or not. If not, consumers\n\t * should continue to read from the stream until consumed.\n\t */\n\tended: boolean;\n}\n\nexport function isReadableStream(obj: unknown): obj is ReadableStream {\n\tconst candidate = obj as ReadableStream | undefined;\n\tif (!candidate) {\n\t\treturn false;\n\t}\n\n\treturn [candidate.on, candidate.pause, candidate.resume, candidate.destroy].every(fn => typeof fn === 'function');\n}\n\nexport function isReadableBufferedStream(obj: unknown): obj is ReadableBufferedStream {\n\tconst candidate = obj as ReadableBufferedStream | undefined;\n\tif (!candidate) {\n\t\treturn false;\n\t}\n\n\treturn isReadableStream(candidate.stream) && Array.isArray(candidate.buffer) && typeof candidate.ended === 'boolean';\n}\n\nexport interface IReducer {\n\t(data: T[]): R;\n}\n\nexport interface IDataTransformer {\n\t(data: Original): Transformed;\n}\n\nexport interface IErrorTransformer {\n\t(error: Error): Error;\n}\n\nexport interface ITransformer {\n\tdata: IDataTransformer;\n\terror?: IErrorTransformer;\n}\n\nexport function newWriteableStream(reducer: IReducer, options?: WriteableStreamOptions): WriteableStream {\n\treturn new WriteableStreamImpl(reducer, options);\n}\n\nexport interface WriteableStreamOptions {\n\n\t/**\n\t * The number of objects to buffer before WriteableStream#write()\n\t * signals back that the buffer is full. Can be used to reduce\n\t * the memory pressure when the stream is not flowing.\n\t */\n\thighWaterMark?: number;\n}\n\nclass WriteableStreamImpl implements WriteableStream {\n\n\tprivate readonly state = {\n\t\tflowing: false,\n\t\tended: false,\n\t\tdestroyed: false\n\t};\n\n\tprivate readonly buffer = {\n\t\tdata: [] as T[],\n\t\terror: [] as Error[]\n\t};\n\n\tprivate readonly listeners = {\n\t\tdata: [] as { (data: T): void }[],\n\t\terror: [] as { (error: Error): void }[],\n\t\tend: [] as { (): void }[]\n\t};\n\n\tprivate readonly pendingWritePromises: Function[] = [];\n\n\tconstructor(private reducer: IReducer, private options?: WriteableStreamOptions) { }\n\n\tpause(): void {\n\t\tif (this.state.destroyed) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.state.flowing = false;\n\t}\n\n\tresume(): void {\n\t\tif (this.state.destroyed) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this.state.flowing) {\n\t\t\tthis.state.flowing = true;\n\n\t\t\t// emit buffered events\n\t\t\tthis.flowData();\n\t\t\tthis.flowErrors();\n\t\t\tthis.flowEnd();\n\t\t}\n\t}\n\n\twrite(data: T): void | Promise {\n\t\tif (this.state.destroyed) {\n\t\t\treturn;\n\t\t}\n\n\t\t// flowing: directly send the data to listeners\n\t\tif (this.state.flowing) {\n\t\t\tthis.emitData(data);\n\t\t}\n\n\t\t// not yet flowing: buffer data until flowing\n\t\telse {\n\t\t\tthis.buffer.data.push(data);\n\n\t\t\t// highWaterMark: if configured, signal back when buffer reached limits\n\t\t\tif (typeof this.options?.highWaterMark === 'number' && this.buffer.data.length > this.options.highWaterMark) {\n\t\t\t\treturn new Promise(resolve => this.pendingWritePromises.push(resolve));\n\t\t\t}\n\t\t}\n\t}\n\n\terror(error: Error): void {\n\t\tif (this.state.destroyed) {\n\t\t\treturn;\n\t\t}\n\n\t\t// flowing: directly send the error to listeners\n\t\tif (this.state.flowing) {\n\t\t\tthis.emitError(error);\n\t\t}\n\n\t\t// not yet flowing: buffer errors until flowing\n\t\telse {\n\t\t\tthis.buffer.error.push(error);\n\t\t}\n\t}\n\n\tend(result?: T): void {\n\t\tif (this.state.destroyed) {\n\t\t\treturn;\n\t\t}\n\n\t\t// end with data if provided\n\t\tif (typeof result !== 'undefined') {\n\t\t\tthis.write(result);\n\t\t}\n\n\t\t// flowing: send end event to listeners\n\t\tif (this.state.flowing) {\n\t\t\tthis.emitEnd();\n\n\t\t\tthis.destroy();\n\t\t}\n\n\t\t// not yet flowing: remember state\n\t\telse {\n\t\t\tthis.state.ended = true;\n\t\t}\n\t}\n\n\tprivate emitData(data: T): void {\n\t\tthis.listeners.data.slice(0).forEach(listener => listener(data)); // slice to avoid listener mutation from delivering event\n\t}\n\n\tprivate emitError(error: Error): void {\n\t\tif (this.listeners.error.length === 0) {\n\t\t\tonUnexpectedError(error); // nobody listened to this error so we log it as unexpected\n\t\t} else {\n\t\t\tthis.listeners.error.slice(0).forEach(listener => listener(error)); // slice to avoid listener mutation from delivering event\n\t\t}\n\t}\n\n\tprivate emitEnd(): void {\n\t\tthis.listeners.end.slice(0).forEach(listener => listener()); // slice to avoid listener mutation from delivering event\n\t}\n\n\ton(event: 'data', callback: (data: T) => void): void;\n\ton(event: 'error', callback: (err: Error) => void): void;\n\ton(event: 'end', callback: () => void): void;\n\ton(event: 'data' | 'error' | 'end', callback: (arg0?: any) => void): void {\n\t\tif (this.state.destroyed) {\n\t\t\treturn;\n\t\t}\n\n\t\tswitch (event) {\n\t\t\tcase 'data':\n\t\t\t\tthis.listeners.data.push(callback);\n\n\t\t\t\t// switch into flowing mode as soon as the first 'data'\n\t\t\t\t// listener is added and we are not yet in flowing mode\n\t\t\t\tthis.resume();\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'end':\n\t\t\t\tthis.listeners.end.push(callback);\n\n\t\t\t\t// emit 'end' event directly if we are flowing\n\t\t\t\t// and the end has already been reached\n\t\t\t\t//\n\t\t\t\t// finish() when it went through\n\t\t\t\tif (this.state.flowing && this.flowEnd()) {\n\t\t\t\t\tthis.destroy();\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'error':\n\t\t\t\tthis.listeners.error.push(callback);\n\n\t\t\t\t// emit buffered 'error' events unless done already\n\t\t\t\t// now that we know that we have at least one listener\n\t\t\t\tif (this.state.flowing) {\n\t\t\t\t\tthis.flowErrors();\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tremoveListener(event: string, callback: Function): void {\n\t\tif (this.state.destroyed) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet listeners: unknown[] | undefined = undefined;\n\n\t\tswitch (event) {\n\t\t\tcase 'data':\n\t\t\t\tlisteners = this.listeners.data;\n\t\t\t\tbreak;\n\n\t\t\tcase 'end':\n\t\t\t\tlisteners = this.listeners.end;\n\t\t\t\tbreak;\n\n\t\t\tcase 'error':\n\t\t\t\tlisteners = this.listeners.error;\n\t\t\t\tbreak;\n\t\t}\n\n\t\tif (listeners) {\n\t\t\tconst index = listeners.indexOf(callback);\n\t\t\tif (index >= 0) {\n\t\t\t\tlisteners.splice(index, 1);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate flowData(): void {\n\t\tif (this.buffer.data.length > 0) {\n\t\t\tconst fullDataBuffer = this.reducer(this.buffer.data);\n\n\t\t\tthis.emitData(fullDataBuffer);\n\n\t\t\tthis.buffer.data.length = 0;\n\n\t\t\t// When the buffer is empty, resolve all pending writers\n\t\t\tconst pendingWritePromises = [...this.pendingWritePromises];\n\t\t\tthis.pendingWritePromises.length = 0;\n\t\t\tpendingWritePromises.forEach(pendingWritePromise => pendingWritePromise());\n\t\t}\n\t}\n\n\tprivate flowErrors(): void {\n\t\tif (this.listeners.error.length > 0) {\n\t\t\tfor (const error of this.buffer.error) {\n\t\t\t\tthis.emitError(error);\n\t\t\t}\n\n\t\t\tthis.buffer.error.length = 0;\n\t\t}\n\t}\n\n\tprivate flowEnd(): boolean {\n\t\tif (this.state.ended) {\n\t\t\tthis.emitEnd();\n\n\t\t\treturn this.listeners.end.length > 0;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tdestroy(): void {\n\t\tif (!this.state.destroyed) {\n\t\t\tthis.state.destroyed = true;\n\t\t\tthis.state.ended = true;\n\n\t\t\tthis.buffer.data.length = 0;\n\t\t\tthis.buffer.error.length = 0;\n\n\t\t\tthis.listeners.data.length = 0;\n\t\t\tthis.listeners.error.length = 0;\n\t\t\tthis.listeners.end.length = 0;\n\n\t\t\tthis.pendingWritePromises.length = 0;\n\t\t}\n\t}\n}\n\n/**\n * Helper to fully read a T readable into a T.\n */\nexport function consumeReadable(readable: Readable, reducer: IReducer): T {\n\tconst chunks: T[] = [];\n\n\tlet chunk: T | null;\n\twhile ((chunk = readable.read()) !== null) {\n\t\tchunks.push(chunk);\n\t}\n\n\treturn reducer(chunks);\n}\n\n/**\n * Helper to read a T readable up to a maximum of chunks. If the limit is\n * reached, will return a readable instead to ensure all data can still\n * be read.\n */\nexport function peekReadable(readable: Readable, reducer: IReducer, maxChunks: number): T | Readable {\n\tconst chunks: T[] = [];\n\n\tlet chunk: T | null | undefined = undefined;\n\twhile ((chunk = readable.read()) !== null && chunks.length < maxChunks) {\n\t\tchunks.push(chunk);\n\t}\n\n\t// If the last chunk is null, it means we reached the end of\n\t// the readable and return all the data at once\n\tif (chunk === null && chunks.length > 0) {\n\t\treturn reducer(chunks);\n\t}\n\n\t// Otherwise, we still have a chunk, it means we reached the maxChunks\n\t// value and as such we return a new Readable that first returns\n\t// the existing read chunks and then continues with reading from\n\t// the underlying readable.\n\treturn {\n\t\tread: () => {\n\n\t\t\t// First consume chunks from our array\n\t\t\tif (chunks.length > 0) {\n\t\t\t\treturn chunks.shift()!;\n\t\t\t}\n\n\t\t\t// Then ensure to return our last read chunk\n\t\t\tif (typeof chunk !== 'undefined') {\n\t\t\t\tconst lastReadChunk = chunk;\n\n\t\t\t\t// explicitly use undefined here to indicate that we consumed\n\t\t\t\t// the chunk, which could have either been null or valued.\n\t\t\t\tchunk = undefined;\n\n\t\t\t\treturn lastReadChunk;\n\t\t\t}\n\n\t\t\t// Finally delegate back to the Readable\n\t\t\treturn readable.read();\n\t\t}\n\t};\n}\n\n/**\n * Helper to fully read a T stream into a T or consuming\n * a stream fully, awaiting all the events without caring\n * about the data.\n */\nexport function consumeStream(stream: ReadableStreamEvents, reducer: IReducer): Promise;\nexport function consumeStream(stream: ReadableStreamEvents): Promise;\nexport function consumeStream(stream: ReadableStreamEvents, reducer?: IReducer): Promise {\n\treturn new Promise((resolve, reject) => {\n\t\tconst chunks: T[] = [];\n\n\t\tlistenStream(stream, {\n\t\t\tonData: chunk => {\n\t\t\t\tif (reducer) {\n\t\t\t\t\tchunks.push(chunk);\n\t\t\t\t}\n\t\t\t},\n\t\t\tonError: error => {\n\t\t\t\tif (reducer) {\n\t\t\t\t\treject(error);\n\t\t\t\t} else {\n\t\t\t\t\tresolve(undefined);\n\t\t\t\t}\n\t\t\t},\n\t\t\tonEnd: () => {\n\t\t\t\tif (reducer) {\n\t\t\t\t\tresolve(reducer(chunks));\n\t\t\t\t} else {\n\t\t\t\t\tresolve(undefined);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t});\n}\n\nexport interface IStreamListener {\n\n\t/**\n\t * The 'data' event is emitted whenever the stream is\n\t * relinquishing ownership of a chunk of data to a consumer.\n\t */\n\tonData(data: T): void;\n\n\t/**\n\t * Emitted when any error occurs.\n\t */\n\tonError(err: Error): void;\n\n\t/**\n\t * The 'end' event is emitted when there is no more data\n\t * to be consumed from the stream. The 'end' event will\n\t * not be emitted unless the data is completely consumed.\n\t */\n\tonEnd(): void;\n}\n\n/**\n * Helper to listen to all events of a T stream in proper order.\n */\nexport function listenStream(stream: ReadableStreamEvents, listener: IStreamListener, token?: CancellationToken): void {\n\n\tstream.on('error', error => {\n\t\tif (!token?.isCancellationRequested) {\n\t\t\tlistener.onError(error);\n\t\t}\n\t});\n\n\tstream.on('end', () => {\n\t\tif (!token?.isCancellationRequested) {\n\t\t\tlistener.onEnd();\n\t\t}\n\t});\n\n\t// Adding the `data` listener will turn the stream\n\t// into flowing mode. As such it is important to\n\t// add this listener last (DO NOT CHANGE!)\n\tstream.on('data', data => {\n\t\tif (!token?.isCancellationRequested) {\n\t\t\tlistener.onData(data);\n\t\t}\n\t});\n}\n\n/**\n * Helper to peek up to `maxChunks` into a stream. The return type signals if\n * the stream has ended or not. If not, caller needs to add a `data` listener\n * to continue reading.\n */\nexport function peekStream(stream: ReadableStream, maxChunks: number): Promise> {\n\treturn new Promise((resolve, reject) => {\n\t\tconst streamListeners = new DisposableStore();\n\t\tconst buffer: T[] = [];\n\n\t\t// Data Listener\n\t\tconst dataListener = (chunk: T) => {\n\n\t\t\t// Add to buffer\n\t\t\tbuffer.push(chunk);\n\n\t\t\t// We reached maxChunks and thus need to return\n\t\t\tif (buffer.length > maxChunks) {\n\n\t\t\t\t// Dispose any listeners and ensure to pause the\n\t\t\t\t// stream so that it can be consumed again by caller\n\t\t\t\tstreamListeners.dispose();\n\t\t\t\tstream.pause();\n\n\t\t\t\treturn resolve({ stream, buffer, ended: false });\n\t\t\t}\n\t\t};\n\n\t\t// Error Listener\n\t\tconst errorListener = (error: Error) => {\n\t\t\tstreamListeners.dispose();\n\n\t\t\treturn reject(error);\n\t\t};\n\n\t\t// End Listener\n\t\tconst endListener = () => {\n\t\t\tstreamListeners.dispose();\n\n\t\t\treturn resolve({ stream, buffer, ended: true });\n\t\t};\n\n\t\tstreamListeners.add(toDisposable(() => stream.removeListener('error', errorListener)));\n\t\tstream.on('error', errorListener);\n\n\t\tstreamListeners.add(toDisposable(() => stream.removeListener('end', endListener)));\n\t\tstream.on('end', endListener);\n\n\t\t// Important: leave the `data` listener last because\n\t\t// this can turn the stream into flowing mode and we\n\t\t// want `error` events to be received as well.\n\t\tstreamListeners.add(toDisposable(() => stream.removeListener('data', dataListener)));\n\t\tstream.on('data', dataListener);\n\t});\n}\n\n/**\n * Helper to create a readable stream from an existing T.\n */\nexport function toStream(t: T, reducer: IReducer): ReadableStream {\n\tconst stream = newWriteableStream(reducer);\n\n\tstream.end(t);\n\n\treturn stream;\n}\n\n/**\n * Helper to create an empty stream\n */\nexport function emptyStream(): ReadableStream {\n\tconst stream = newWriteableStream(() => { throw new Error('not supported'); });\n\tstream.end();\n\n\treturn stream;\n}\n\n/**\n * Helper to convert a T into a Readable.\n */\nexport function toReadable(t: T): Readable {\n\tlet consumed = false;\n\n\treturn {\n\t\tread: () => {\n\t\t\tif (consumed) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconsumed = true;\n\n\t\t\treturn t;\n\t\t}\n\t};\n}\n\n/**\n * Helper to transform a readable stream into another stream.\n */\nexport function transform(stream: ReadableStreamEvents, transformer: ITransformer, reducer: IReducer): ReadableStream {\n\tconst target = newWriteableStream(reducer);\n\n\tlistenStream(stream, {\n\t\tonData: data => target.write(transformer.data(data)),\n\t\tonError: error => target.error(transformer.error ? transformer.error(error) : error),\n\t\tonEnd: () => target.end()\n\t});\n\n\treturn target;\n}\n\n/**\n * Helper to take an existing readable that will\n * have a prefix injected to the beginning.\n */\nexport function prefixedReadable(prefix: T, readable: Readable, reducer: IReducer): Readable {\n\tlet prefixHandled = false;\n\n\treturn {\n\t\tread: () => {\n\t\t\tconst chunk = readable.read();\n\n\t\t\t// Handle prefix only once\n\t\t\tif (!prefixHandled) {\n\t\t\t\tprefixHandled = true;\n\n\t\t\t\t// If we have also a read-result, make\n\t\t\t\t// sure to reduce it to a single result\n\t\t\t\tif (chunk !== null) {\n\t\t\t\t\treturn reducer([prefix, chunk]);\n\t\t\t\t}\n\n\t\t\t\t// Otherwise, just return prefix directly\n\t\t\t\treturn prefix;\n\t\t\t}\n\n\t\t\treturn chunk;\n\t\t}\n\t};\n}\n\n/**\n * Helper to take an existing stream that will\n * have a prefix injected to the beginning.\n */\nexport function prefixedStream(prefix: T, stream: ReadableStream, reducer: IReducer): ReadableStream {\n\tlet prefixHandled = false;\n\n\tconst target = newWriteableStream(reducer);\n\n\tlistenStream(stream, {\n\t\tonData: data => {\n\n\t\t\t// Handle prefix only once\n\t\t\tif (!prefixHandled) {\n\t\t\t\tprefixHandled = true;\n\n\t\t\t\treturn target.write(reducer([prefix, data]));\n\t\t\t}\n\n\t\t\treturn target.write(data);\n\t\t},\n\t\tonError: error => target.error(error),\n\t\tonEnd: () => {\n\n\t\t\t// Handle prefix only once\n\t\t\tif (!prefixHandled) {\n\t\t\t\tprefixHandled = true;\n\n\t\t\t\ttarget.write(prefix);\n\t\t\t}\n\n\t\t\ttarget.end();\n\t\t}\n\t});\n\n\treturn target;\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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';\nimport * as streams from 'vs/base/common/stream';\n\ndeclare const Buffer: any;\n\nconst hasBuffer = (typeof Buffer !== 'undefined');\nconst indexOfTable = new Lazy(() => new Uint8Array(256));\n\nlet textEncoder: TextEncoder | null;\nlet textDecoder: TextDecoder | null;\n\nexport class VSBuffer {\n\n\t/**\n\t * When running in a nodejs context, the backing store for the returned `VSBuffer` instance\n\t * might use a nodejs Buffer allocated from node's Buffer pool, which is not transferrable.\n\t */\n\tstatic alloc(byteLength: number): VSBuffer {\n\t\tif (hasBuffer) {\n\t\t\treturn new VSBuffer(Buffer.allocUnsafe(byteLength));\n\t\t} else {\n\t\t\treturn new VSBuffer(new Uint8Array(byteLength));\n\t\t}\n\t}\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\t/**\n\t * When running in a nodejs context, the backing store for the returned `VSBuffer` instance\n\t * might use a nodejs Buffer allocated from node's Buffer pool, which is not transferrable.\n\t */\n\tstatic fromString(source: string, options?: { dontUseNodeBuffer?: boolean }): VSBuffer {\n\t\tconst dontUseNodeBuffer = options?.dontUseNodeBuffer || false;\n\t\tif (!dontUseNodeBuffer && hasBuffer) {\n\t\t\treturn new VSBuffer(Buffer.from(source));\n\t\t} else {\n\t\t\tif (!textEncoder) {\n\t\t\t\ttextEncoder = new TextEncoder();\n\t\t\t}\n\t\t\treturn new VSBuffer(textEncoder.encode(source));\n\t\t}\n\t}\n\n\t/**\n\t * When running in a nodejs context, the backing store for the returned `VSBuffer` instance\n\t * might use a nodejs Buffer allocated from node's Buffer pool, which is not transferrable.\n\t */\n\tstatic fromByteArray(source: number[]): VSBuffer {\n\t\tconst result = VSBuffer.alloc(source.length);\n\t\tfor (let i = 0, len = source.length; i < len; i++) {\n\t\t\tresult.buffer[i] = source[i];\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * When running in a nodejs context, the backing store for the returned `VSBuffer` instance\n\t * might use a nodejs Buffer allocated from node's Buffer pool, which is not transferrable.\n\t */\n\tstatic concat(buffers: VSBuffer[], totalLength?: number): VSBuffer {\n\t\tif (typeof totalLength === 'undefined') {\n\t\t\ttotalLength = 0;\n\t\t\tfor (let i = 0, len = buffers.length; i < len; i++) {\n\t\t\t\ttotalLength += buffers[i].byteLength;\n\t\t\t}\n\t\t}\n\n\t\tconst ret = VSBuffer.alloc(totalLength);\n\t\tlet offset = 0;\n\t\tfor (let i = 0, len = buffers.length; i < len; i++) {\n\t\t\tconst element = buffers[i];\n\t\t\tret.set(element, offset);\n\t\t\toffset += element.byteLength;\n\t\t}\n\n\t\treturn ret;\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\t/**\n\t * When running in a nodejs context, the backing store for the returned `VSBuffer` instance\n\t * might use a nodejs Buffer allocated from node's Buffer pool, which is not transferrable.\n\t */\n\tclone(): VSBuffer {\n\t\tconst result = VSBuffer.alloc(this.byteLength);\n\t\tresult.set(this);\n\t\treturn result;\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\tslice(start?: number, end?: number): VSBuffer {\n\t\t// IMPORTANT: use subarray instead of slice because TypedArray#slice\n\t\t// creates shallow copy and NodeBuffer#slice doesn't. The use of subarray\n\t\t// ensures the same, performance, behaviour.\n\t\treturn new VSBuffer(this.buffer.subarray(start, end));\n\t}\n\n\tset(array: VSBuffer, offset?: number): void;\n\tset(array: Uint8Array, offset?: number): void;\n\tset(array: ArrayBuffer, offset?: number): void;\n\tset(array: ArrayBufferView, offset?: number): void;\n\tset(array: VSBuffer | Uint8Array | ArrayBuffer | ArrayBufferView, offset?: number): void;\n\tset(array: VSBuffer | Uint8Array | ArrayBuffer | ArrayBufferView, offset?: number): void {\n\t\tif (array instanceof VSBuffer) {\n\t\t\tthis.buffer.set(array.buffer, offset);\n\t\t} else if (array instanceof Uint8Array) {\n\t\t\tthis.buffer.set(array, offset);\n\t\t} else if (array instanceof ArrayBuffer) {\n\t\t\tthis.buffer.set(new Uint8Array(array), offset);\n\t\t} else if (ArrayBuffer.isView(array)) {\n\t\t\tthis.buffer.set(new Uint8Array(array.buffer, array.byteOffset, array.byteLength), offset);\n\t\t} else {\n\t\t\tthrow new Error(`Unknown argument 'array'`);\n\t\t}\n\t}\n\n\treadUInt32BE(offset: number): number {\n\t\treturn readUInt32BE(this.buffer, offset);\n\t}\n\n\twriteUInt32BE(value: number, offset: number): void {\n\t\twriteUInt32BE(this.buffer, value, offset);\n\t}\n\n\treadUInt32LE(offset: number): number {\n\t\treturn readUInt32LE(this.buffer, offset);\n\t}\n\n\twriteUInt32LE(value: number, offset: number): void {\n\t\twriteUInt32LE(this.buffer, value, offset);\n\t}\n\n\treadUInt8(offset: number): number {\n\t\treturn readUInt8(this.buffer, offset);\n\t}\n\n\twriteUInt8(value: number, offset: number): void {\n\t\twriteUInt8(this.buffer, value, offset);\n\t}\n\n\tindexOf(subarray: VSBuffer | Uint8Array, offset = 0) {\n\t\treturn binaryIndexOf(this.buffer, subarray instanceof VSBuffer ? subarray.buffer : subarray, offset);\n\t}\n}\n\n/**\n * Like String.indexOf, but works on Uint8Arrays.\n * Uses the boyer-moore-horspool algorithm to be reasonably speedy.\n */\nexport function binaryIndexOf(haystack: Uint8Array, needle: Uint8Array, offset = 0): number {\n\tconst needleLen = needle.byteLength;\n\tconst haystackLen = haystack.byteLength;\n\n\tif (needleLen === 0) {\n\t\treturn 0;\n\t}\n\n\tif (needleLen === 1) {\n\t\treturn haystack.indexOf(needle[0]);\n\t}\n\n\tif (needleLen > haystackLen - offset) {\n\t\treturn -1;\n\t}\n\n\t// find index of the subarray using boyer-moore-horspool algorithm\n\tconst table = indexOfTable.value;\n\ttable.fill(needle.length);\n\tfor (let i = 0; i < needle.length; i++) {\n\t\ttable[needle[i]] = needle.length - i - 1;\n\t}\n\n\tlet i = offset + needle.length - 1;\n\tlet j = i;\n\tlet result = -1;\n\twhile (i < haystackLen) {\n\t\tif (haystack[i] === needle[j]) {\n\t\t\tif (j === 0) {\n\t\t\t\tresult = i;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\ti--;\n\t\t\tj--;\n\t\t} else {\n\t\t\ti += Math.max(needle.length - j, table[haystack[i]]);\n\t\t\tj = needle.length - 1;\n\t\t}\n\t}\n\n\treturn result;\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 readUInt32LE(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\t((source[offset + 2] << 16) >>> 0) |\n\t\t((source[offset + 3] << 24) >>> 0)\n\t);\n}\n\nexport function writeUInt32LE(destination: Uint8Array, value: number, offset: number): void {\n\tdestination[offset + 0] = (value & 0b11111111);\n\tvalue = value >>> 8;\n\tdestination[offset + 1] = (value & 0b11111111);\n\tvalue = value >>> 8;\n\tdestination[offset + 2] = (value & 0b11111111);\n\tvalue = value >>> 8;\n\tdestination[offset + 3] = (value & 0b11111111);\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\nexport interface VSBufferReadable extends streams.Readable { }\n\nexport interface VSBufferReadableStream extends streams.ReadableStream { }\n\nexport interface VSBufferWriteableStream extends streams.WriteableStream { }\n\nexport interface VSBufferReadableBufferedStream extends streams.ReadableBufferedStream { }\n\nexport function readableToBuffer(readable: VSBufferReadable): VSBuffer {\n\treturn streams.consumeReadable(readable, chunks => VSBuffer.concat(chunks));\n}\n\nexport function bufferToReadable(buffer: VSBuffer): VSBufferReadable {\n\treturn streams.toReadable(buffer);\n}\n\nexport function streamToBuffer(stream: streams.ReadableStream): Promise {\n\treturn streams.consumeStream(stream, chunks => VSBuffer.concat(chunks));\n}\n\nexport async function bufferedStreamToBuffer(bufferedStream: streams.ReadableBufferedStream): Promise {\n\tif (bufferedStream.ended) {\n\t\treturn VSBuffer.concat(bufferedStream.buffer);\n\t}\n\n\treturn VSBuffer.concat([\n\n\t\t// Include already read chunks...\n\t\t...bufferedStream.buffer,\n\n\t\t// ...and all additional chunks\n\t\tawait streamToBuffer(bufferedStream.stream)\n\t]);\n}\n\nexport function bufferToStream(buffer: VSBuffer): streams.ReadableStream {\n\treturn streams.toStream(buffer, chunks => VSBuffer.concat(chunks));\n}\n\nexport function streamToBufferReadableStream(stream: streams.ReadableStreamEvents): streams.ReadableStream {\n\treturn streams.transform(stream, { data: data => typeof data === 'string' ? VSBuffer.fromString(data) : VSBuffer.wrap(data) }, chunks => VSBuffer.concat(chunks));\n}\n\nexport function newWriteableBufferStream(options?: streams.WriteableStreamOptions): streams.WriteableStream {\n\treturn streams.newWriteableStream(chunks => VSBuffer.concat(chunks), options);\n}\n\nexport function prefixedBufferReadable(prefix: VSBuffer, readable: VSBufferReadable): VSBufferReadable {\n\treturn streams.prefixedReadable(prefix, readable, chunks => VSBuffer.concat(chunks));\n}\n\nexport function prefixedBufferStream(prefix: VSBuffer, stream: VSBufferReadableStream): VSBufferReadableStream {\n\treturn streams.prefixedStream(prefix, stream, chunks => VSBuffer.concat(chunks));\n}\n\n/** Decodes base64 to a uint8 array. URL-encoded and unpadded base64 is allowed. */\nexport function decodeBase64(encoded: string) {\n\tlet building = 0;\n\tlet remainder = 0;\n\tlet bufi = 0;\n\n\t// The simpler way to do this is `Uint8Array.from(atob(str), c => c.charCodeAt(0))`,\n\t// but that's about 10-20x slower than this function in current Chromium versions.\n\n\tconst buffer = new Uint8Array(Math.floor(encoded.length / 4 * 3));\n\tconst append = (value: number) => {\n\t\tswitch (remainder) {\n\t\t\tcase 3:\n\t\t\t\tbuffer[bufi++] = building | value;\n\t\t\t\tremainder = 0;\n\t\t\t\tbreak;\n\t\t\tcase 2:\n\t\t\t\tbuffer[bufi++] = building | (value >>> 2);\n\t\t\t\tbuilding = value << 6;\n\t\t\t\tremainder = 3;\n\t\t\t\tbreak;\n\t\t\tcase 1:\n\t\t\t\tbuffer[bufi++] = building | (value >>> 4);\n\t\t\t\tbuilding = value << 4;\n\t\t\t\tremainder = 2;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbuilding = value << 2;\n\t\t\t\tremainder = 1;\n\t\t}\n\t};\n\n\tfor (let i = 0; i < encoded.length; i++) {\n\t\tconst code = encoded.charCodeAt(i);\n\t\t// See https://datatracker.ietf.org/doc/html/rfc4648#section-4\n\t\t// This branchy code is about 3x faster than an indexOf on a base64 char string.\n\t\tif (code >= 65 && code <= 90) {\n\t\t\tappend(code - 65); // A-Z starts ranges from char code 65 to 90\n\t\t} else if (code >= 97 && code <= 122) {\n\t\t\tappend(code - 97 + 26); // a-z starts ranges from char code 97 to 122, starting at byte 26\n\t\t} else if (code >= 48 && code <= 57) {\n\t\t\tappend(code - 48 + 52); // 0-9 starts ranges from char code 48 to 58, starting at byte 52\n\t\t} else if (code === 43 || code === 45) {\n\t\t\tappend(62); // \"+\" or \"-\" for URLS\n\t\t} else if (code === 47 || code === 95) {\n\t\t\tappend(63); // \"/\" or \"_\" for URLS\n\t\t} else if (code === 61) {\n\t\t\tbreak; // \"=\"\n\t\t} else {\n\t\t\tthrow new SyntaxError(`Unexpected base64 character ${encoded[i]}`);\n\t\t}\n\t}\n\n\tconst unpadded = bufi;\n\twhile (remainder > 0) {\n\t\tappend(0);\n\t}\n\n\t// slice is needed to account for overestimation due to padding\n\treturn VSBuffer.wrap(buffer).slice(0, unpadded);\n}\n\nconst base64Alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\nconst base64UrlSafeAlphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';\n\n/** Encodes a buffer to a base64 string. */\nexport function encodeBase64({ buffer }: VSBuffer, padded = true, urlSafe = false) {\n\tconst dictionary = urlSafe ? base64UrlSafeAlphabet : base64Alphabet;\n\tlet output = '';\n\n\tconst remainder = buffer.byteLength % 3;\n\n\tlet i = 0;\n\tfor (; i < buffer.byteLength - remainder; i += 3) {\n\t\tconst a = buffer[i + 0];\n\t\tconst b = buffer[i + 1];\n\t\tconst c = buffer[i + 2];\n\n\t\toutput += dictionary[a >>> 2];\n\t\toutput += dictionary[(a << 4 | b >>> 4) & 0b111111];\n\t\toutput += dictionary[(b << 2 | c >>> 6) & 0b111111];\n\t\toutput += dictionary[c & 0b111111];\n\t}\n\n\tif (remainder === 1) {\n\t\tconst a = buffer[i + 0];\n\t\toutput += dictionary[a >>> 2];\n\t\toutput += dictionary[(a << 4) & 0b111111];\n\t\tif (padded) { output += '=='; }\n\t} else if (remainder === 2) {\n\t\tconst a = buffer[i + 0];\n\t\tconst b = buffer[i + 1];\n\t\toutput += dictionary[a >>> 2];\n\t\toutput += dictionary[(a << 4 | b >>> 4) & 0b111111];\n\t\toutput += dictionary[(b << 2) & 0b111111];\n\t\tif (padded) { output += '='; }\n\t}\n\n\treturn output;\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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\nconst _format2Regexp = /{([^}]+)}/g;\n\n/**\n * Helper to create a string from a template and a string record.\n * Similar to `format` but with objects instead of positional arguments.\n */\nexport function format2(template: string, values: Record): string {\n\tif (Object.keys(values).length === 0) {\n\t\treturn template;\n\t}\n\treturn template.replace(_format2Regexp, (match, group) => (values[group] ?? match) as string);\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 * Counts how often `character` occurs inside `value`.\n */\nexport function count(value: string, character: string): number {\n\tlet result = 0;\n\tconst ch = character.charCodeAt(0);\n\tfor (let i = value.length - 1; i >= 0; i--) {\n\t\tif (value.charCodeAt(i) === ch) {\n\t\t\tresult++;\n\t\t}\n\t}\n\treturn result;\n}\n\nexport function truncate(value: string, maxLength: number, suffix = '…'): string {\n\tif (value.length <= maxLength) {\n\t\treturn value;\n\t}\n\n\treturn `${value.substr(0, maxLength)}${suffix}`;\n}\n\nexport function truncateMiddle(value: string, maxLength: number, suffix = '…'): string {\n\tif (value.length <= maxLength) {\n\t\treturn value;\n\t}\n\n\tconst prefixLength = Math.ceil(maxLength / 2) - suffix.length / 2;\n\tconst suffixLength = Math.floor(maxLength / 2) - suffix.length / 2;\n\n\treturn `${value.substr(0, prefixLength)}${suffix}${value.substr(value.length - suffixLength)}`;\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\n/**\n * Function that works identically to String.prototype.replace, except, the\n * replace function is allowed to be async and return a Promise.\n */\nexport function replaceAsync(str: string, search: RegExp, replacer: (match: string, ...args: any[]) => Promise): Promise {\n\tconst parts: (string | Promise)[] = [];\n\n\tlet last = 0;\n\tfor (const match of str.matchAll(search)) {\n\t\tparts.push(str.slice(last, match.index));\n\t\tif (match.index === undefined) {\n\t\t\tthrow new Error('match.index should be defined');\n\t\t}\n\n\t\tlast = match.index + match[0].length;\n\t\tparts.push(replacer(match[0], ...match.slice(1), match.index, str, match.groups));\n\t}\n\n\tparts.push(str.slice(last));\n\n\treturn Promise.all(parts).then(p => p.join(''));\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\nexport function charCount(str: string): number {\n\tconst iterator = new GraphemeIterator(str);\n\tlet length = 0;\n\twhile (!iterator.eol()) {\n\t\tlength++;\n\t\titerator.nextGraphemeLength();\n\t}\n\treturn length;\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 * Given a string and a max length returns a shorted version. Shorting\n * happens at favorable positions - such as whitespace or punctuation characters.\n * The return value can be longer than the given value of `n`. Leading whitespace is always trimmed.\n */\nexport function lcut(text: string, n: number, prefix = '') {\n\tconst trimmed = text.trimStart();\n\n\tif (trimmed.length < n) {\n\t\treturn trimmed;\n\t}\n\n\tconst re = /\\b/g;\n\tlet i = 0;\n\twhile (re.test(trimmed)) {\n\t\tif (trimmed.length - re.lastIndex < n) {\n\t\t\tbreak;\n\t\t}\n\n\t\ti = re.lastIndex;\n\t\tre.lastIndex += 1;\n\t}\n\n\tif (i === 0) {\n\t\treturn trimmed;\n\t}\n\n\treturn prefix + trimmed.substring(i).trimStart();\n}\n\n// Escape codes, compiled from https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_\nconst CSI_SEQUENCE = /(:?\\x1b\\[|\\x9B)[=?>!]?[\\d;:]*[\"$#'* ]?[a-zA-Z@^`{}|~]/g;\n\n// Plus additional markers for custom `\\x1b]...\\x07` instructions.\nconst CSI_CUSTOM_SEQUENCE = /\\x1b\\].*?\\x07/g;\n\nexport function removeAnsiEscapeCodes(str: string): string {\n\tif (str) {\n\t\tstr = str.replace(CSI_SEQUENCE, '').replace(CSI_CUSTOM_SEQUENCE, '');\n\t}\n\n\treturn str;\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 stripUTF8BOM(str: string): string {\n\treturn startsWithUTF8BOM(str) ? str.substr(1) : str;\n}\n\n/**\n * Checks if the characters of the provided query string are included in the\n * target string. The characters do not have to be contiguous within the string.\n */\nexport function fuzzyContains(target: string, query: string): boolean {\n\tif (!target || !query) {\n\t\treturn false; // return early if target or query are undefined\n\t}\n\n\tif (target.length < query.length) {\n\t\treturn false; // impossible for query to be contained in target\n\t}\n\n\tconst queryLen = query.length;\n\tconst targetLower = target.toLowerCase();\n\n\tlet index = 0;\n\tlet lastIndexOf = -1;\n\twhile (index < queryLen) {\n\t\tconst indexOf = targetLower.indexOf(query[index], lastIndexOf + 1);\n\t\tif (indexOf < 0) {\n\t\t\treturn false;\n\t\t}\n\n\t\tlastIndexOf = indexOf;\n\n\t\tindex++;\n\t}\n\n\treturn true;\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\nexport function uppercaseFirstLetter(str: string): string {\n\treturn str.charAt(0).toUpperCase() + str.slice(1);\n}\n\nexport function getNLines(str: string, n = 1): string {\n\tif (n === 0) {\n\t\treturn '';\n\t}\n\n\tlet idx = -1;\n\tdo {\n\t\tidx = str.indexOf('\\n', idx + 1);\n\t\tn--;\n\t} while (n > 0 && idx >= 0);\n\n\tif (idx === -1) {\n\t\treturn str;\n\t}\n\n\tif (str[idx - 1] === '\\r') {\n\t\tidx--;\n\t}\n\n\treturn str.substr(0, idx);\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\n//#region Unicode Grapheme Break\n\nexport function getGraphemeBreakType(codePoint: number): GraphemeBreakType {\n\tconst graphemeBreakTree = GraphemeBreakTree.getInstance();\n\treturn graphemeBreakTree.getGraphemeBreakType(codePoint);\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>((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 === 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\nexport function fuzzyScoreGraceful(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, false, 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\nexport class Hasher {\n\n\tprivate _value = 0;\n\n\tget value(): number {\n\t\treturn this._value;\n\t}\n\n\thash(obj: any): number {\n\t\tthis._value = doHash(obj, this._value);\n\t\treturn this._value;\n\t}\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 { VSBuffer } from 'vs/base/common/buffer';\nimport { StringSHA1, toHexString } from 'vs/base/common/hash';\n\nexport async function sha1Hex(str: string): Promise {\n\n\t// Prefer to use browser's crypto module\n\tif (globalThis?.crypto?.subtle) {\n\n\t\t// Careful to use `dontUseNodeBuffer` when passing the\n\t\t// buffer to the browser `crypto` API. Users reported\n\t\t// native crashes in certain cases that we could trace\n\t\t// back to passing node.js `Buffer` around\n\t\t// (https://github.com/microsoft/vscode/issues/114227)\n\t\tconst buffer = VSBuffer.fromString(str, { dontUseNodeBuffer: true }).buffer;\n\t\tconst hash = await globalThis.crypto.subtle.digest({ name: 'sha-1' }, buffer);\n\n\t\treturn toHexString(hash);\n\t}\n\n\t// Otherwise fallback to `StringSHA1`\n\telse {\n\t\tconst computer = new StringSHA1();\n\t\tcomputer.update(str);\n\n\t\treturn computer.digest();\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { shuffle } from 'vs/base/common/arrays';\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\tisEmpty(): boolean {\n\t\treturn !this.left && !this.mid && !this.right && !this.value;\n\t}\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 forPaths(ignorePathCasing = false): TernarySearchTree {\n\t\treturn new TernarySearchTree(new PathIterator(undefined, !ignorePathCasing));\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\t/**\n\t * Fill the tree with the same value of the given keys\n\t */\n\tfill(element: V, keys: readonly K[]): void;\n\t/**\n\t * Fill the tree with given [key,value]-tuples\n\t */\n\tfill(values: readonly [K, V][]): void;\n\tfill(values: readonly [K, V][] | V, keys?: readonly K[]): void {\n\t\tif (keys) {\n\t\t\tconst arr = keys.slice(0);\n\t\t\tshuffle(arr);\n\t\t\tfor (const k of arr) {\n\t\t\t\tthis.set(k, (values));\n\t\t\t}\n\t\t} else {\n\t\t\tconst arr = (<[K, V][]>values).slice(0);\n\t\t\tshuffle(arr);\n\t\t\tfor (const entry of arr) {\n\t\t\t\tthis.set(entry[0], entry[1]);\n\t\t\t}\n\t\t}\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\thasElementOrSubtree(key: K): boolean {\n\t\treturn this._findSuperstrOrElement(key, true) !== 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\t// for debug/testing\n\t_isBalanced(): boolean {\n\t\tconst nodeIsBalanced = (node: TernarySearchTreeNode | undefined): boolean => {\n\t\t\tif (!node) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tconst bf = node.balanceFactor();\n\t\t\tif (bf < -1 || bf > 1) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn nodeIsBalanced(node.left) && nodeIsBalanced(node.right);\n\t\t};\n\t\treturn nodeIsBalanced(this._root);\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 text: string;\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 a JavaScript Array and each element in the array is a string.\n */\nexport function isStringArray(value: unknown): value is string[] {\n\treturn Array.isArray(value) && (value).every(elem => isString(elem));\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 * Asserts that each argument passed in is neither undefined nor null.\n */\nexport function assertAllDefined(t1: T1 | null | undefined, t2: T2 | null | undefined): [T1, T2];\nexport function assertAllDefined(t1: T1 | null | undefined, t2: T2 | null | undefined, t3: T3 | null | undefined): [T1, T2, T3];\nexport function assertAllDefined(t1: T1 | null | undefined, t2: T2 | null | undefined, t3: T3 | null | undefined, t4: T4 | null | undefined): [T1, T2, T3, T4];\nexport function assertAllDefined(...args: (unknown | null | undefined)[]): unknown[] {\n\tconst result = [];\n\n\tfor (let i = 0; i < args.length; i++) {\n\t\tconst arg = args[i];\n\n\t\tif (isUndefinedOrNull(arg)) {\n\t\t\tthrow new Error(`Assertion Failed: argument at index ${i} is undefined or null`);\n\t\t}\n\n\t\tresult.push(arg);\n\t}\n\n\treturn result;\n}\n\nconst hasOwnProperty = Object.prototype.hasOwnProperty;\n\n/**\n * @returns whether the provided parameter is an empty JavaScript Object or not.\n */\nexport function isEmptyObject(obj: unknown): obj is object {\n\tif (!isObject(obj)) {\n\t\treturn false;\n\t}\n\n\tfor (const key in obj) {\n\t\tif (hasOwnProperty.call(obj, key)) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn true;\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\n/**\n * @returns whether the provided parameters is are JavaScript Function or not.\n */\nexport function areFunctions(...objects: unknown[]): boolean {\n\treturn objects.length > 0 && objects.every(isFunction);\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\ntype AddFirstParameterToFunction = T extends (...args: any[]) => TargetFunctionsReturnType ?\n\t// Function: add param to function\n\t(firstArg: FirstParameter, ...args: Parameters) => ReturnType :\n\n\t// Else: just leave as is\n\tT;\n\n/**\n * Allows to add a first parameter to functions of a type.\n */\nexport type AddFirstParameterToFunctions = {\n\t// For every property\n\t[K in keyof Target]: AddFirstParameterToFunction;\n};\n\n/**\n * Given an object with all optional properties, requires at least one to be defined.\n * i.e. AtLeastOne;\n */\nexport type AtLeastOne }> = Partial & U[keyof U];\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 * A single object or an array of the objects.\n */\nexport type SingleOrMany = T | T[];\n\n\n/**\n * A type that recursively makes all properties of `T` required\n */\nexport type DeepRequiredNonNullable = {\n\t[P in keyof T]-?: T[P] extends object ? DeepRequiredNonNullable : Required>;\n};\n\n\n/**\n * Represents a type that is a partial version of a given type `T`, where all properties are optional and can be deeply nested.\n */\nexport type DeepPartial = {\n\t[P in keyof T]?: T[P] extends object ? DeepPartial : Partial;\n};\n","/*---------------------------------------------------------------------------------------------\n * 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\nconst _codiconFontCharacters: { [id: string]: number } = Object.create(null);\n\nfunction 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/**\n * Only to be used by the iconRegistry.\n */\nexport function getAllCodicons(): ThemeIcon[] {\n\treturn Object.values(Codicon);\n}\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\n\t// built-in icons, with image name\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\ttagAdd: register('tag-add', 0xea66),\n\ttagRemove: register('tag-remove', 0xea66),\n\tgitPullRequestLabel: register('git-pull-request-label', 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\tdebugBreakpointPending: register('debug-breakpoint-pending', 0xebd9),\n\tdebugHint: register('debug-hint', 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\tdropDownButton: register('drop-down-button', 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\tcircle: register('circle', 0xeabc),\n\tcircleOutline: register('circle-outline', 0xeabc),\n\tdebugBreakpointUnverified: register('debug-breakpoint-unverified', 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\tcompareChanges: register('compare-changes', 0xeafd),\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\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\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\tissueClosed: register('issue-closed', 0xeba4),\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\tbracket: register('bracket', 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\tsymbolCustomColor: register('symbol-customcolor', 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\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\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\tdebugAlt: register('debug-alt', 0xeb91),\n\tserverProcess: register('server-process', 0xeba2),\n\tserverEnvironment: register('server-environment', 0xeba3),\n\tpass: register('pass', 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\texportIcon: 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\tworkspaceUnspecified: register('workspace-unspecified', 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\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\tlayoutSidebarRightOff: register('layout-sidebar-right-off', 0xec00),\n\tlayoutPanelOff: register('layout-panel-off', 0xec01),\n\tlayoutSidebarLeftOff: register('layout-sidebar-left-off', 0xec02),\n\ttarget: register('target', 0xebf8),\n\tindent: register('indent', 0xebf9),\n\trecordSmall: register('record-small', 0xebfa),\n\terrorSmall: register('error-small', 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\theartFilled: register('heart-filled', 0xec04),\n\tmap: register('map', 0xec05),\n\tmapFilled: register('map-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\tgitFetch: register('git-fetch', 0xec1d),\n\tcopilot: register('copilot', 0xec1e),\n\tlightbulbSparkle: register('lightbulb-sparkle', 0xec1f),\n\tlightbulbSparkleAutofix: register('lightbulb-sparkle-autofix', 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\tgitStash: register('git-stash', 0xec26),\n\tgitStashApply: register('git-stash-apply', 0xec27),\n\tgitStashPop: register('git-stash-pop', 0xec28),\n\trunAllCoverage: register('run-all-coverage', 0xec2d),\n\trunCoverage: register('run-all-coverage', 0xec2c),\n\tcoverage: register('coverage', 0xec2e),\n\tgithubProject: register('github-project', 0xec2f),\n\n\t// derived icons, that could become separate icons\n\t// TODO: These mappings should go in the vscode-codicons mapping file\n\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\n\ttreeItemExpanded: register('tree-item-expanded', 'chevron-down'), // collapsed is done with rotation\n\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\n\ttreeItemLoading: register('tree-item-loading', 'loading'),\n\n\tmenuSelection: register('menu-selection', 'check'),\n\tmenuSubmenu: register('menu-submenu', 'chevron-right'),\n\n\tmenuBarMore: register('menubar-more', 'more'),\n\n\tscrollbarButtonLeft: register('scrollbar-button-left', 'triangle-left'),\n\tscrollbarButtonRight: register('scrollbar-button-right', 'triangle-right'),\n\n\tscrollbarButtonUp: register('scrollbar-button-up', 'triangle-up'),\n\tscrollbarButtonDown: register('scrollbar-button-down', 'triangle-down'),\n\n\ttoolBarMore: register('toolbar-more', 'more'),\n\n\tquickInputBack: register('quick-input-back', 'arrow-left')\n\n} as const;\n\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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\n/**\n * Calls `JSON.Stringify` with a replacer to break apart any circular references.\n * This prevents `JSON`.stringify` from throwing the exception\n * \"Uncaught TypeError: Converting circular structure to JSON\"\n */\nexport function safeStringify(obj: any): string {\n\tconst seen = new Set();\n\treturn JSON.stringify(obj, (key, value) => {\n\t\tif (isObject(value) || Array.isArray(value)) {\n\t\t\tif (seen.has(value)) {\n\t\t\t\treturn '[Circular]';\n\t\t\t} else {\n\t\t\t\tseen.add(value);\n\t\t\t}\n\t\t}\n\t\treturn value;\n\t});\n}\n\ntype obj = { [key: string]: any };\n/**\n * Returns an object that has keys for each value that is different in the base object. Keys\n * that do not exist in the target but in the base object are not considered.\n *\n * Note: This is not a deep-diffing method, so the values are strictly taken into the resulting\n * object if they differ.\n *\n * @param base the object to diff against\n * @param obj the object to use for diffing\n */\nexport function distinct(base: obj, target: obj): obj {\n\tconst result = Object.create(null);\n\n\tif (!base || !target) {\n\t\treturn result;\n\t}\n\n\tconst targetKeys = Object.keys(target);\n\ttargetKeys.forEach(k => {\n\t\tconst baseValue = base[k];\n\t\tconst targetValue = target[k];\n\n\t\tif (!equals(baseValue, targetValue)) {\n\t\t\tresult[k] = targetValue;\n\t\t}\n\t});\n\n\treturn result;\n}\n\nexport function getCaseInsensitive(target: obj, key: string): any {\n\tconst lowercaseKey = key.toLowerCase();\n\tconst equivalentKey = Object.keys(target).find(k => k.toLowerCase() === lowercaseKey);\n\treturn equivalentKey ? target[equivalentKey] : target[key];\n}\n\nexport function filter(obj: obj, predicate: (key: string, value: any) => boolean): obj {\n\tconst result = Object.create(null);\n\tfor (const [key, value] of Object.entries(obj)) {\n\t\tif (predicate(key, value)) {\n\t\t\tresult[key] = value;\n\t\t}\n\t}\n\treturn result;\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 ColorIdentifier = string;\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\nexport function themeColorFromId(id: ColorIdentifier) {\n\treturn { id };\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 * Copyright (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\nconst _UUIDPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\nexport function isUUID(value: string): boolean {\n\treturn _UUIDPattern.test(value);\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\treadonly id: string;\n\treadonly name: string;\n\treadonly uri?: URI;\n\tdata(): Promise;\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\t/**\n\t * Check if this data transfer contains data matching `pattern`.\n\t *\n\t * This allows matching for wildcards, such as `image/*`.\n\t *\n\t * Use the special `files` mime type to match any file in the data transfer.\n\t */\n\tmatches(pattern: 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 { isObject } from 'vs/base/common/types';\n\ninterface IVerifier {\n\tverify(value: unknown): T;\n}\n\nabstract class Verifier implements IVerifier {\n\n\tconstructor(protected readonly defaultValue: T) { }\n\n\tverify(value: unknown): T {\n\t\tif (!this.isType(value)) {\n\t\t\treturn this.defaultValue;\n\t\t}\n\n\t\treturn value;\n\t}\n\n\tprotected abstract isType(value: unknown): value is T;\n}\n\nexport class BooleanVerifier extends Verifier {\n\tprotected isType(value: unknown): value is boolean {\n\t\treturn typeof value === 'boolean';\n\t}\n}\n\nexport class NumberVerifier extends Verifier {\n\tprotected isType(value: unknown): value is number {\n\t\treturn typeof value === 'number';\n\t}\n}\n\nexport class SetVerifier extends Verifier> {\n\tprotected isType(value: unknown): value is Set {\n\t\treturn value instanceof Set;\n\t}\n}\n\nexport class EnumVerifier extends Verifier {\n\tprivate readonly allowedValues: ReadonlyArray;\n\n\tconstructor(defaultValue: T, allowedValues: ReadonlyArray) {\n\t\tsuper(defaultValue);\n\t\tthis.allowedValues = allowedValues;\n\t}\n\n\tprotected isType(value: unknown): value is T {\n\t\treturn this.allowedValues.includes(value as T);\n\t}\n}\n\nexport class ObjectVerifier extends Verifier {\n\n\tconstructor(defaultValue: T, private readonly verifier: { [K in keyof T]: IVerifier }) {\n\t\tsuper(defaultValue);\n\t}\n\n\toverride verify(value: unknown): T {\n\t\tif (!this.isType(value)) {\n\t\t\treturn this.defaultValue;\n\t\t}\n\t\treturn verifyObject(this.verifier, value);\n\t}\n\n\tprotected isType(value: unknown): value is T {\n\t\treturn isObject(value);\n\t}\n}\n\nexport function verifyObject(verifiers: { [K in keyof T]: IVerifier }, value: Object): T {\n\tconst result = Object.create(null);\n\n\tfor (const key in verifiers) {\n\t\tif (Object.hasOwnProperty.call(verifiers, key)) {\n\t\t\tconst verifier = verifiers[key];\n\t\t\tresult[key] = verifier.verify((value as any)[key]);\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 { VSBufferReadableStream } from 'vs/base/common/buffer';\n\nconst offlineName = 'Offline';\n\n/**\n * Checks if the given error is offline error\n */\nexport function isOfflineError(error: any): boolean {\n\tif (error instanceof OfflineError) {\n\t\treturn true;\n\t}\n\treturn error instanceof Error && error.name === offlineName && error.message === offlineName;\n}\n\nexport class OfflineError extends Error {\n\tconstructor() {\n\t\tsuper(offlineName);\n\t\tthis.name = this.message;\n\t}\n}\n\nexport interface IHeaders {\n\t[header: string]: string;\n}\n\nexport interface IRequestOptions {\n\ttype?: string;\n\turl?: string;\n\tuser?: string;\n\tpassword?: string;\n\theaders?: IHeaders;\n\ttimeout?: number;\n\tdata?: string;\n\tfollowRedirects?: number;\n\tproxyAuthorization?: string;\n}\n\nexport interface IRequestContext {\n\tres: {\n\t\theaders: IHeaders;\n\t\tstatusCode?: number;\n\t};\n\tstream: VSBufferReadableStream;\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { bufferToStream, VSBuffer } from 'vs/base/common/buffer';\nimport { CancellationToken } from 'vs/base/common/cancellation';\nimport { canceled } from 'vs/base/common/errors';\nimport { IRequestContext, IRequestOptions, OfflineError } from 'vs/base/parts/request/common/request';\n\nexport function request(options: IRequestOptions, token: CancellationToken): Promise {\n\tif (options.proxyAuthorization) {\n\t\toptions.headers = {\n\t\t\t...(options.headers || {}),\n\t\t\t'Proxy-Authorization': options.proxyAuthorization\n\t\t};\n\t}\n\n\tconst xhr = new XMLHttpRequest();\n\treturn new Promise((resolve, reject) => {\n\n\t\txhr.open(options.type || 'GET', options.url || '', true, options.user, options.password);\n\t\tsetRequestHeaders(xhr, options);\n\n\t\txhr.responseType = 'arraybuffer';\n\t\txhr.onerror = e => reject(\n\t\t\tnavigator.onLine ? new Error(xhr.statusText && ('XHR failed: ' + xhr.statusText) || 'XHR failed') : new OfflineError()\n\t\t);\n\t\txhr.onload = (e) => {\n\t\t\tresolve({\n\t\t\t\tres: {\n\t\t\t\t\tstatusCode: xhr.status,\n\t\t\t\t\theaders: getResponseHeaders(xhr)\n\t\t\t\t},\n\t\t\t\tstream: bufferToStream(VSBuffer.wrap(new Uint8Array(xhr.response)))\n\t\t\t});\n\t\t};\n\t\txhr.ontimeout = e => reject(new Error(`XHR timeout: ${options.timeout}ms`));\n\n\t\tif (options.timeout) {\n\t\t\txhr.timeout = options.timeout;\n\t\t}\n\n\t\txhr.send(options.data);\n\n\t\t// cancel\n\t\ttoken.onCancellationRequested(() => {\n\t\t\txhr.abort();\n\t\t\treject(canceled());\n\t\t});\n\t});\n}\n\nfunction setRequestHeaders(xhr: XMLHttpRequest, options: IRequestOptions): void {\n\tif (options.headers) {\n\t\touter: for (const k in options.headers) {\n\t\t\tswitch (k) {\n\t\t\t\tcase 'User-Agent':\n\t\t\t\tcase 'Accept-Encoding':\n\t\t\t\tcase 'Content-Length':\n\t\t\t\t\t// unsafe headers\n\t\t\t\t\tcontinue outer;\n\t\t\t}\n\t\t\txhr.setRequestHeader(k, options.headers[k]);\n\t\t}\n\t}\n}\n\nfunction getResponseHeaders(xhr: XMLHttpRequest): { [name: string]: string } {\n\tconst headers: { [name: string]: string } = Object.create(null);\n\tfor (const line of xhr.getAllResponseHeaders().split(/\\r\\n|\\n|\\r/g)) {\n\t\tif (line) {\n\t\t\tconst idx = line.indexOf(':');\n\t\t\theaders[line.substr(0, idx).trim().toLowerCase()] = line.substr(idx + 1).trim();\n\t\t}\n\t}\n\treturn headers;\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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';\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);\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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\t/**\n\t * Returns the element with the smallest `lineNumber`.\n\t */\n\tpublic static firstLine(ranges: LineVisibleRanges[] | null): LineVisibleRanges | null {\n\t\tif (!ranges) {\n\t\t\treturn null;\n\t\t}\n\t\tlet result: LineVisibleRanges | null = null;\n\t\tfor (const range of ranges) {\n\t\t\tif (!result || range.lineNumber < result.lineNumber) {\n\t\t\t\tresult = range;\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns the element with the largest `lineNumber`.\n\t */\n\tpublic static lastLine(ranges: LineVisibleRanges[] | null): LineVisibleRanges | null {\n\t\tif (!ranges) {\n\t\t\treturn null;\n\t\t}\n\t\tlet result: LineVisibleRanges | null = null;\n\t\tfor (const range of ranges) {\n\t\t\tif (!result || range.lineNumber > result.lineNumber) {\n\t\t\t\tresult = range;\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\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/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 onVisible(): void;\n\tabstract onHide(): 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 getStatusbarColumn(position: IPosition): number {\n\t\treturn this._targetEditor.getStatusbarColumn(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 *--------------------------------------------------------------------------------------------*/\n\nimport { Event } from 'vs/base/common/event';\nimport { IDiffEditorOptions } from 'vs/editor/common/config/editorOptions';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { ContextKeyValue } from 'vs/platform/contextkey/common/contextkey';\n\nexport interface IMultiDiffEditorModel {\n\treadonly documents: readonly LazyPromise[];\n\treadonly onDidChange: Event;\n\treadonly contextKeys?: Record;\n}\n\nexport interface LazyPromise {\n\trequest(): Promise;\n\treadonly value: T | undefined;\n\treadonly onHasValueDidChange: Event;\n}\n\nexport class ConstLazyPromise implements LazyPromise {\n\tpublic readonly onHasValueDidChange = Event.None;\n\n\tconstructor(\n\t\tprivate readonly _value: T\n\t) { }\n\n\tpublic request(): Promise {\n\t\treturn Promise.resolve(this._value);\n\t}\n\n\tpublic get value(): T {\n\t\treturn this._value;\n\t}\n}\n\nexport interface IDocumentDiffItem {\n\t/**\n\t * undefined if the file was created.\n\t */\n\treadonly original: ITextModel | undefined;\n\n\t/**\n\t * undefined if the file was deleted.\n\t */\n\treadonly modified: ITextModel | undefined;\n\treadonly options?: IDiffEditorOptions;\n\treadonly onOptionsDidChange?: Event;\n}\n","/*---------------------------------------------------------------------------------------------\n * 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\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 the value to display as \"Col\" in the status bar.\n\t * @see {@link CursorColumns}\n\t */\n\tpublic static toStatusbarColumn(lineContent: string, column: number, tabSize: number): number {\n\t\tconst text = lineContent.substring(0, Math.min(column - 1, lineContent.length));\n\t\tconst iterator = new strings.CodePointIterator(text);\n\n\t\tlet result = 0;\n\t\twhile (!iterator.eol()) {\n\t\t\tconst codePoint = iterator.nextCodePoint();\n\n\t\t\tif (codePoint === CharCode.Tab) {\n\t\t\t\tresult = CursorColumns.nextRenderTabStop(result, tabSize);\n\t\t\t} else {\n\t\t\t\tresult = result + 1;\n\t\t\t}\n\t\t}\n\n\t\treturn result + 1;\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\treadonly start: number;\n\treadonly endExclusive: number;\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 equals(other: OffsetRange): boolean {\n\t\treturn this.start === other.start && this.endExclusive === other.endExclusive;\n\t}\n\n\tpublic containsRange(other: OffsetRange): boolean {\n\t\treturn this.start <= other.start && other.endExclusive <= 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 intersectsOrTouches(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 map(f: (offset: number) => T): T[] {\n\t\tconst result: T[] = [];\n\t\tfor (let i = this.start; i < this.endExclusive; i++) {\n\t\t\tresult.push(f(i));\n\t\t}\n\t\treturn result;\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 { 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\n\tconstructor(selection: Selection, cursors: Position[]) {\n\t\tthis._selection = selection;\n\t\tthis._cursors = cursors;\n\t\tthis._selectionId = null;\n\t}\n\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\n\t\tconst ops = trimTrailingWhitespace(model, this._cursors);\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[]): 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\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\tpublic static fromRange(range: Range): LineRange {\n\t\treturn new LineRange(range.startLineNumber, range.endLineNumber);\n\t}\n\n\tpublic static fromRangeInclusive(range: Range): LineRange {\n\t\treturn new LineRange(range.startLineNumber, range.endLineNumber + 1);\n\t}\n\n\tpublic static subtract(a: LineRange, b: LineRange | undefined): LineRange[] {\n\t\tif (!b) {\n\t\t\treturn [a];\n\t\t}\n\t\tif (a.startLineNumber < b.startLineNumber && b.endLineNumberExclusive < a.endLineNumberExclusive) {\n\t\t\treturn [\n\t\t\t\tnew LineRange(a.startLineNumber, b.startLineNumber),\n\t\t\t\tnew LineRange(b.endLineNumberExclusive, a.endLineNumberExclusive)\n\t\t\t];\n\t\t} else if (b.startLineNumber <= a.startLineNumber && a.endLineNumberExclusive <= b.endLineNumberExclusive) {\n\t\t\treturn [];\n\t\t} else if (b.endLineNumberExclusive < a.endLineNumberExclusive) {\n\t\t\treturn [new LineRange(Math.max(b.endLineNumberExclusive, a.startLineNumber), a.endLineNumberExclusive)];\n\t\t} else {\n\t\t\treturn [new LineRange(a.startLineNumber, Math.min(b.startLineNumber, a.endLineNumberExclusive))];\n\t\t}\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 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\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 *--------------------------------------------------------------------------------------------*/\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 { 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\tconstructor(wordSeparators: string) {\n\t\tsuper(WordCharacterClass.Regular);\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}\n\nfunction once(computeFn: (input: string) => R): (input: string) => R {\n\tconst cache: { [key: string]: R } = {}; // TODO@Alex unbounded cache\n\treturn (input: string): R => {\n\t\tif (!cache.hasOwnProperty(input)) {\n\t\t\tcache[input] = computeFn(input);\n\t\t}\n\t\treturn cache[input];\n\t};\n}\n\nexport const getMapForWordSeparators = once(\n\t(input) => new WordCharacterClassifier(input)\n);\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { toDisposable } from 'vs/base/common/lifecycle';\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 setDefaultGetWordAtTextConfig(value: IGetWordAtTextConfig) {\n\tconst rm = _defaultConfig.unshift(value);\n\treturn toDisposable(rm);\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\tcompute(sequence1: ISequence, sequence2: ISequence, timeout?: ITimeout): DiffAlgorithmResult;\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 intersectsOrTouches(other: SequenceDiff): boolean {\n\t\treturn this.seq1Range.intersectsOrTouches(other.seq1Range) || this.seq2Range.intersectsOrTouches(other.seq2Range);\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\tpublic disable() {\n\t\tthis.timeout = Number.MAX_SAFE_INTEGER;\n\t\tthis.isValid = () => true;\n\t\tthis.valid = 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 { 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(w1) || next.seq2Range.intersects(w2);\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\tpublic flip(): MovedText {\n\t\treturn new MovedText(this.lineRangeMapping.flip(), this.changes.map(c => c.flip()));\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { LineRange } from 'vs/editor/common/core/lineRange';\nimport { Range } from 'vs/editor/common/core/range';\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\tpublic get changedLineCount() {\n\t\treturn Math.max(this.original.length, this.modified.length);\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\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\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","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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, removeVeryShortMatchingLinesBetweenDiffs, removeVeryShortMatchingTextBetweenLongDiffs, removeShortMatches } from 'vs/editor/common/diff/defaultLinesDiffComputer/heuristicSequenceOptimizations';\nimport { ILinesDiffComputer, ILinesDiffComputerOptions, LinesDiff, MovedText } from 'vs/editor/common/diff/linesDiffComputer';\nimport { DetailedLineRangeMapping, RangeMapping } from '../rangeMapping';\nimport { LinesSliceCharSequence } from 'vs/editor/common/diff/defaultLinesDiffComputer/linesSliceCharSequence';\nimport { LineSequence } from 'vs/editor/common/diff/defaultLinesDiffComputer/lineSequence';\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[0].length + 1),\n\t\t\t\t\t\t\tnew Range(1, 1, modifiedLines.length, modifiedLines[0].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) {\n\t\t\tif (changes.length > 0 && changes[0].original.startLineNumber !== changes[0].modified.startLineNumber) {\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\nexport interface IDiffComputationResult {\n\tquitEarly: boolean;\n\tidentical: boolean;\n\n\t/**\n\t * The changes as (legacy) line change array.\n\t * @deprecated Use `changes2` instead.\n\t */\n\tchanges: ILineChange[];\n\n\t/**\n\t * The changes as (modern) line range mapping array.\n\t */\n\tchanges2: readonly DetailedLineRangeMapping[];\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 { IMarkdownString } from 'vs/base/common/htmlContent';\nimport { IDisposable } from 'vs/base/common/lifecycle';\nimport { ThemeColor } from 'vs/base/common/themables';\nimport { URI, UriComponents } 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, OverviewRulerLane, TrackedRangeStickiness } 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 * Indicates that the editor becomes visible.\n\t * @internal\n\t */\n\tonVisible(): void;\n\n\t/**\n\t * Indicates that the editor becomes hidden.\n\t * @internal\n\t */\n\tonHide(): 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 * Given a position, returns a column number that takes tab-widths into account.\n\t * @internal\n\t */\n\tgetStatusbarColumn(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\t/**\n\t * Get the `original` editor.\n\t */\n\tgetOriginalEditor(): IEditor;\n\n\t/**\n\t * Get the `modified` editor.\n\t */\n\tgetModifiedEditor(): IEditor;\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 * @internal\n */\nexport function isThemeColor(o: any): o is ThemeColor {\n\treturn o && typeof o.id === 'string';\n}\n\n/**\n * @internal\n */\nexport interface IThemeDecorationRenderOptions {\n\tbackgroundColor?: string | ThemeColor;\n\n\toutline?: string;\n\toutlineColor?: string | ThemeColor;\n\toutlineStyle?: string;\n\toutlineWidth?: string;\n\n\tborder?: string;\n\tborderColor?: string | ThemeColor;\n\tborderRadius?: string;\n\tborderSpacing?: string;\n\tborderStyle?: string;\n\tborderWidth?: string;\n\n\tfontStyle?: string;\n\tfontWeight?: string;\n\tfontSize?: string;\n\ttextDecoration?: string;\n\tcursor?: string;\n\tcolor?: string | ThemeColor;\n\topacity?: string;\n\tletterSpacing?: string;\n\n\tgutterIconPath?: UriComponents;\n\tgutterIconSize?: string;\n\n\toverviewRulerColor?: string | ThemeColor;\n\n\t/**\n\t * @deprecated\n\t */\n\tbefore?: IContentDecorationRenderOptions;\n\t/**\n\t * @deprecated\n\t */\n\tafter?: IContentDecorationRenderOptions;\n\n\t/**\n\t * @deprecated\n\t */\n\tbeforeInjectedText?: IContentDecorationRenderOptions & { affectsLetterSpacing?: boolean };\n\t/**\n\t * @deprecated\n\t */\n\tafterInjectedText?: IContentDecorationRenderOptions & { affectsLetterSpacing?: boolean };\n}\n\n/**\n * @internal\n */\nexport interface IContentDecorationRenderOptions {\n\tcontentText?: string;\n\tcontentIconPath?: UriComponents;\n\n\tborder?: string;\n\tborderColor?: string | ThemeColor;\n\tborderRadius?: string;\n\tfontStyle?: string;\n\tfontWeight?: string;\n\tfontSize?: string;\n\tfontFamily?: string;\n\ttextDecoration?: string;\n\tcolor?: string | ThemeColor;\n\tbackgroundColor?: string | ThemeColor;\n\topacity?: string;\n\tverticalAlign?: string;\n\n\tmargin?: string;\n\tpadding?: string;\n\twidth?: string;\n\theight?: string;\n}\n\n/**\n * @internal\n */\nexport interface IDecorationRenderOptions extends IThemeDecorationRenderOptions {\n\tisWholeLine?: boolean;\n\trangeBehavior?: TrackedRangeStickiness;\n\toverviewRulerLane?: OverviewRulerLane;\n\n\tlight?: IThemeDecorationRenderOptions;\n\tdark?: IThemeDecorationRenderOptions;\n}\n\n/**\n * @internal\n */\nexport interface IThemeDecorationInstanceRenderOptions {\n\t/**\n\t * @deprecated\n\t */\n\tbefore?: IContentDecorationRenderOptions;\n\t/**\n\t * @deprecated\n\t */\n\tafter?: IContentDecorationRenderOptions;\n}\n\n/**\n * @internal\n */\nexport interface IDecorationInstanceRenderOptions extends IThemeDecorationInstanceRenderOptions {\n\tlight?: IThemeDecorationInstanceRenderOptions;\n\tdark?: IThemeDecorationInstanceRenderOptions;\n}\n\n/**\n * @internal\n */\nexport interface IDecorationOptions {\n\trange: IRange;\n\thoverMessage?: IMarkdownString | IMarkdownString[];\n\trenderOptions?: IDecorationInstanceRenderOptions;\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 * @internal\n */\nexport interface PastePayload {\n\ttext: string;\n\tpasteOnNewLine: boolean;\n\tmulticursorText: string[] | null;\n\tmode: string | 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 { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';\nimport { IMouseEvent, IMouseWheelEvent } from 'vs/base/browser/mouseEvent';\nimport { IBoundarySashes } from 'vs/base/browser/ui/sash/sash';\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 { IDiffComputationResult, 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 { IEditorWhitespace, IViewModel } from 'vs/editor/common/viewModel';\nimport { OverviewRulerZone } from 'vs/editor/common/viewModel/overviewZoneManager';\nimport { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';\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/**\n * An overlay widgets renders on top of the text.\n */\nexport interface IOverlayWidget {\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}\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 editor's scoped context key service.\n\t * @internal\n\t */\n\treadonly contextKeyService: IContextKeyService;\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 * 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\tsetDecorationsByType(description: string, decorationTypeKey: string, ranges: editorCommon.IDecorationOptions[]): void;\n\n\t/**\n\t * @internal\n\t */\n\tsetDecorationsByTypeFast(decorationTypeKey: string, ranges: IRange[]): 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 view zones.\n\t * @internal\n\t */\n\tgetWhitespaces(): IEditorWhitespace[];\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 * @internal\n\t */\n\tgetTelemetryData(): { [key: string]: any } | undefined;\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 * Saves current view state of the editor in a serializable object.\n\t */\n\tsaveViewState(): editorCommon.ICodeEditorViewState;\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 * @internal\n */\nexport const enum DiffEditorState {\n\tIdle,\n\tComputingDiff,\n\tDiffComputed\n}\n\n/**\n * A rich diff editor.\n */\nexport interface IDiffEditor extends editorCommon.IEditor {\n\n\t/**\n\t * Returns whether the diff editor is ignoring trim whitespace or not.\n\t * @internal\n\t */\n\treadonly ignoreTrimWhitespace: boolean;\n\t/**\n\t * Returns whether the diff editor is rendering side by side or inline.\n\t * @internal\n\t */\n\treadonly renderSideBySide: boolean;\n\t/**\n\t * Timeout in milliseconds after which diff computation is cancelled.\n\t * @internal\n\t */\n\treadonly maxComputationTime: number;\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 * Get the computed diff information.\n\t * @internal\n\t */\n\tgetDiffComputationResult(): IDiffComputationResult | 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 * @internal\n\t */\n\tsetBoundarySashes(sashes: IBoundarySashes): 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/**\n *@internal\n */\nexport function getIEditor(thing: any): editorCommon.IEditor | null {\n\tif (isCodeEditor(thing) || isDiffEditor(thing)) {\n\t\treturn thing;\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\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);\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\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\tgetLineLastNonWhitespaceColumn(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, 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 _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\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 (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\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 (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\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 (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\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 (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, position: Position): IWordAtPosition | null {\n\t\tconst wordSeparators = getMapForWordSeparators(_wordSeparators);\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);\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 = {\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 { findLastMaxBy, findFirstMinBy } 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 findFirstMinBy(\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 findLastMaxBy(\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\tstatic readonly DEFAULT_AUTOCLOSE_BEFORE_WHITESPACE = ' \\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\t/**\n\t * used for testing purposes\n\t */\n\tpublic getThemeTrieElement(): ExternalThemeTrieElement {\n\t\treturn this._root.toExternalThemeTrieElement();\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 ExternalThemeTrieElement {\n\n\tpublic readonly mainRule: ThemeTrieElementRule;\n\tpublic readonly children: Map;\n\n\tconstructor(\n\t\tmainRule: ThemeTrieElementRule,\n\t\tchildren: Map | { [key: string]: ExternalThemeTrieElement } = new Map()\n\t) {\n\t\tthis.mainRule = mainRule;\n\t\tif (children instanceof Map) {\n\t\t\tthis.children = children;\n\t\t} else {\n\t\t\tthis.children = new Map();\n\t\t\tfor (const key in children) {\n\t\t\t\tthis.children.set(key, children[key]);\n\t\t\t}\n\t\t}\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\t/**\n\t * used for testing purposes\n\t */\n\tpublic toExternalThemeTrieElement(): ExternalThemeTrieElement {\n\t\tconst children = new Map();\n\t\tthis._children.forEach((element, index) => {\n\t\t\tchildren.set(index, element.toExternalThemeTrieElement());\n\t\t});\n\t\treturn new ExternalThemeTrieElement(this._mainRule, children);\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 enum MinimapPosition {\n\tInline = 1,\n\tGutter = 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}\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 * Check if the raw text stored in this model equals another raw text.\n\t * @internal\n\t */\n\tequalsTextBuffer(other: ITextBuffer): boolean;\n\n\t/**\n\t * Get the underling text buffer.\n\t * @internal\n\t */\n\tgetTextBuffer(): ITextBuffer;\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\tacceptChunk(chunk: string): void;\n\tfinish(): ITextBufferFactory;\n}\n\n/**\n * @internal\n */\nexport interface ITextBufferFactory {\n\tcreate(defaultEOL: DefaultEndOfLine): { textBuffer: ITextBuffer; disposable: IDisposable };\n\tgetFirstLineText(lengthLimit: number): string;\n}\n\n/**\n * @internal\n */\nexport const enum ModelConstants {\n\tFIRST_LINE_DETECTION_LENGTH_LIMIT = 1000\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\tonDidChangeContent: Event;\n\tequals(other: ITextBuffer): boolean;\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\tgetCharCode(offset: 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';\n\n/**\n * Represents a non-negative length in terms of line and column count.\n * Prefer using {@link Length} for performance reasons.\n*/\nexport class LengthObj {\n\tpublic static zero = new LengthObj(0, 0);\n\n\tpublic static lengthDiffNonNegative(start: LengthObj, end: LengthObj): LengthObj {\n\t\tif (end.isLessThan(start)) {\n\t\t\treturn LengthObj.zero;\n\t\t}\n\t\tif (start.lineCount === end.lineCount) {\n\t\t\treturn new LengthObj(0, end.columnCount - start.columnCount);\n\t\t} else {\n\t\t\treturn new LengthObj(end.lineCount - start.lineCount, end.columnCount);\n\t\t}\n\t}\n\n\tconstructor(\n\t\tpublic readonly lineCount: number,\n\t\tpublic readonly columnCount: number\n\t) { }\n\n\tpublic isZero() {\n\t\treturn this.lineCount === 0 && this.columnCount === 0;\n\t}\n\n\tpublic toLength(): Length {\n\t\treturn toLength(this.lineCount, this.columnCount);\n\t}\n\n\tpublic isLessThan(other: LengthObj): 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 isGreaterThan(other: LengthObj): 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 equals(other: LengthObj): boolean {\n\t\treturn this.lineCount === other.lineCount && this.columnCount === other.columnCount;\n\t}\n\n\tpublic compare(other: LengthObj): number {\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 add(other: LengthObj): LengthObj {\n\t\tif (other.lineCount === 0) {\n\t\t\treturn new LengthObj(this.lineCount, this.columnCount + other.columnCount);\n\t\t} else {\n\t\t\treturn new LengthObj(this.lineCount + other.lineCount, other.columnCount);\n\t\t}\n\t}\n\n\ttoString() {\n\t\treturn `${this.lineCount},${this.columnCount}`;\n\t}\n}\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): LengthObj {\n\tconst l = length as any as number;\n\tconst lineCount = Math.floor(l / factor);\n\tconst columnCount = l - lineCount * factor;\n\treturn new LengthObj(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 lengthToPosition(length: Length): Position {\n\tconst l = length as any as number;\n\tconst lineCount = Math.floor(l / factor);\n\tconst colCount = l - lineCount * factor;\n\treturn new Position(lineCount + 1, colCount + 1);\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 lengthOfRange(range: Range): LengthObj {\n\tif (range.startLineNumber === range.endLineNumber) {\n\t\treturn new LengthObj(0, range.endColumn - range.startColumn);\n\t} else {\n\t\treturn new LengthObj(range.endLineNumber - range.startLineNumber, range.endColumn - 1);\n\t}\n}\n\nexport function lengthCompare(length1: Length, length2: Length): number {\n\tconst l1 = length1 as any as number;\n\tconst l2 = length2 as any as number;\n\treturn l1 - l2;\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\nexport function lengthOfStringObj(str: string): LengthObj {\n\tconst lines = splitLines(str);\n\treturn new LengthObj(lines.length - 1, lines[lines.length - 1].length);\n}\n\n/**\n * Computes a numeric hash of the given length.\n*/\nexport function lengthHash(length: Length): number {\n\treturn length as any;\n}\n\nexport function lengthMax(length1: Length, length2: Length): Length {\n\treturn length1 > length2 ? length1 : length2;\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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, LengthObj, lengthOfString, lengthToObj, positionToLength, toLength } from './length';\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: LengthObj): 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: LengthObj;\n\tpublic readonly endOffsetAfterObj: LengthObj;\n\tpublic readonly offsetObj: LengthObj;\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 has(value: T, keyProvider: IDenseKeyProvider): boolean {\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\treturn (this.items & (1 << key)) !== 0;\n\t\t}\n\t\tidx--;\n\n\t\treturn ((this.additionalItems[idx] || 0) & (1 << (key & 31))) !== 0;\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\tpublic equals(other: SmallImmutableSet): boolean {\n\t\tif (this.items !== other.items) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (this.additionalItems.length !== other.additionalItems.length) {\n\t\t\treturn false;\n\t\t}\n\n\t\tfor (let i = 0; i < this.additionalItems.length; i++) {\n\t\t\tif (this.additionalItems[i] !== other.additionalItems[i]) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\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\treverseLookup(value: number): T | undefined {\n\t\treturn [...this.items].find(([_key, v]) => v === value)?.[0];\n\t}\n\n\treverseLookupSet(set: SmallImmutableSet): T[] {\n\t\tconst result: T[] = [];\n\t\tfor (const [key] of this.items) {\n\t\t\tif (set.has(key, this)) {\n\t\t\t\tresult.push(key);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tkeys(): IterableIterator {\n\t\treturn this.items.keys();\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 * Flattens all lists in this AST. Only for debugging.\n\t */\n\tpublic abstract flattenLists(): AstNode;\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 flattenLists(): PairAstNode {\n\t\treturn PairAstNode.create(\n\t\t\tthis.openingBracket.flattenLists(),\n\t\t\tthis.child && this.child.flattenLists(),\n\t\t\tthis.closingBracket && this.closingBracket.flattenLists()\n\t\t);\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 create(items: AstNode[], immutable: boolean = false): ListAstNode {\n\t\tif (items.length === 0) {\n\t\t\treturn this.getEmpty();\n\t\t} else {\n\t\t\tlet length = items[0].length;\n\t\t\tlet unopenedBrackets = items[0].missingOpeningBracketIds;\n\t\t\tfor (let i = 1; i < items.length; i++) {\n\t\t\t\tlength = lengthAdd(length, items[i].length);\n\t\t\t\tunopenedBrackets = unopenedBrackets.merge(items[i].missingOpeningBracketIds);\n\t\t\t}\n\t\t\treturn immutable\n\t\t\t\t? new ImmutableArrayListAstNode(length, items[0].listHeight + 1, items, unopenedBrackets)\n\t\t\t\t: new ArrayListAstNode(length, items[0].listHeight + 1, items, unopenedBrackets);\n\t\t}\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 flattenLists(): ListAstNode {\n\t\tconst items: AstNode[] = [];\n\t\tfor (const c of this.children) {\n\t\t\tconst normalized = c.flattenLists();\n\t\t\tif (normalized.kind === AstNodeKind.List) {\n\t\t\t\titems.push(...normalized.children);\n\t\t\t} else {\n\t\t\t\titems.push(normalized);\n\t\t\t}\n\t\t}\n\t\treturn ListAstNode.create(items);\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\n\tpublic flattenLists(): this & AstNode {\n\t\treturn this as this & AstNode;\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\t/**\n\t * Reports how many nodes were constructed in the last parse operation.\n\t*/\n\tget nodesConstructed() {\n\t\treturn this._itemsConstructed;\n\t}\n\n\t/**\n\t * Reports how many nodes were reused in the last parse operation.\n\t*/\n\tget nodesReused() {\n\t\treturn this._itemsFromCache;\n\t}\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\treadonly length: Length;\n\n\tread(): Token | null;\n\tpeek(): Token | null;\n\tskip(length: Length): void;\n\n\tgetText(): string;\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\tgetValue(): string;\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\tgetText() {\n\t\treturn this.textModel.getValue();\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\tgetText(): string {\n\t\treturn this.text;\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * 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\tgetToken(value: string, languageId: string): Token | undefined {\n\t\tconst singleLanguageBracketTokens = this.getSingleLanguageBracketTokens(languageId);\n\t\treturn singleLanguageBracketTokens.getToken(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 { 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\n\tgetValue(): string {\n\t\treturn this.lines.map(l => l.getLineContent()).join('\\n');\n\t}\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, TrackedRangeStickiness as ActualTrackedRangeStickiness } 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}\nexport function setNodeStickiness(node: IntervalNode, stickiness: ActualTrackedRangeStickiness): void {\n\t_setNodeStickiness(node, stickiness);\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\tpublic getAllInOrder(): IntervalNode[] {\n\t\treturn search(this, 0, false, 0, false);\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 getCount(): number {\n\t\treturn this.values.length;\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\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}\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 equal(other: PieceTreeBase): boolean {\n\t\tif (this.getLength() !== other.getLength()) {\n\t\t\treturn false;\n\t\t}\n\t\tif (this.getLineCount() !== other.getLineCount()) {\n\t\t\treturn false;\n\t\t}\n\n\t\tlet offset = 0;\n\t\tconst ret = this.iterate(this.root, node => {\n\t\t\tif (node === SENTINEL) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tconst str = this.getNodeContent(node);\n\t\t\tconst len = str.length;\n\t\t\tconst startPosition = other.nodeAt(offset);\n\t\t\tconst endPosition = other.nodeAt(offset + len);\n\t\t\tconst val = other.getValueInRange2(startPosition, endPosition);\n\n\t\t\toffset += len;\n\t\t\treturn str === val;\n\t\t});\n\n\t\treturn ret;\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 getCharCode(offset: number): number {\n\t\tconst nodePos = this.nodeAt(offset);\n\t\treturn this._getCharCode(nodePos);\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 getLinesRawContent(): string {\n\t\treturn this.getContentOfSubTree(this.root);\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\n\tprivate getContentOfSubTree(node: TreeNode): string {\n\t\tlet str = '';\n\n\t\tthis.iterate(node, node => {\n\t\t\tstr += this.getNodeContent(node);\n\t\t\treturn true;\n\t\t});\n\n\t\treturn str;\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';\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\nexport interface ITreeViewsDnDService {\n\treadonly _serviceBrand: undefined;\n\n\tremoveDragOperationTransfer(uuid: string | undefined): Promise | undefined;\n\taddDragOperationTransfer(uuid: string, transferPromise: Promise): void;\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\taddDragOperationTransfer(uuid: string, transferPromise: Promise): void {\n\t\tthis._dragOperations.set(uuid, transferPromise);\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\twordSeparators = 130,\n\twordWrap = 131,\n\twordWrapBreakAfterCharacters = 132,\n\twordWrapBreakBeforeCharacters = 133,\n\twordWrapColumn = 134,\n\twordWrapOverride1 = 135,\n\twordWrapOverride2 = 136,\n\twrappingIndent = 137,\n\twrappingStrategy = 138,\n\tshowDeprecated = 139,\n\tinlayHints = 140,\n\teditorClassName = 141,\n\tpixelRatio = 142,\n\ttabFocusMode = 143,\n\tlayoutInfo = 144,\n\twrappingInfo = 145,\n\tdefaultColorDecorators = 146,\n\tcolorDecoratorsActivatedOn = 147,\n\tinlineCompletionsAccessibilityVerbose = 148\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\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 * 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\n/**\n * A positioning preference for rendering overlay widgets.\n */\nexport enum OverlayWidgetPositionPreference {\n\t/**\n\t * Position the overlay widget in the top right corner\n\t */\n\tTOP_RIGHT_CORNER = 0,\n\t/**\n\t * Position the overlay widget in the bottom right corner\n\t */\n\tBOTTOM_RIGHT_CORNER = 1,\n\t/**\n\t * Position the overlay widget in the top center\n\t */\n\tTOP_CENTER = 2\n}\n\n/**\n * Vertical Lane in the overview ruler of the editor.\n */\nexport enum OverviewRulerLane {\n\tLeft = 1,\n\tCenter = 2,\n\tRight = 4,\n\tFull = 7\n}\n\nexport enum 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\tpublic get closingBracketInfo(): ClosingBracketKind | undefined {\n\t\treturn this.bracketPairNode.closingBracket?.bracketInfo as ClosingBracketKind | undefined;\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\tpublic withText(text: string): LineInjectedText {\n\t\treturn new LineInjectedText(this.ownerId, this.lineNumber, this.column, { ...this.options, content: text }, this.order);\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 type { 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 * Copyright (c) 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 { readUInt32BE, writeUInt32BE } from 'vs/base/common/buffer';\nimport { Position } from 'vs/editor/common/core/position';\nimport { IRange } from 'vs/editor/common/core/range';\nimport { countEOL } from 'vs/editor/common/core/eolCounter';\nimport { ContiguousTokensEditing } from 'vs/editor/common/tokens/contiguousTokensEditing';\nimport { LineRange } from 'vs/editor/common/core/lineRange';\n\n/**\n * Represents contiguous tokens over a contiguous range of lines.\n */\nexport class ContiguousMultilineTokens {\n\tpublic static deserialize(buff: Uint8Array, offset: number, result: ContiguousMultilineTokens[]): number {\n\t\tconst view32 = new Uint32Array(buff.buffer);\n\t\tconst startLineNumber = readUInt32BE(buff, offset); offset += 4;\n\t\tconst count = readUInt32BE(buff, offset); offset += 4;\n\t\tconst tokens: Uint32Array[] = [];\n\t\tfor (let i = 0; i < count; i++) {\n\t\t\tconst byteCount = readUInt32BE(buff, offset); offset += 4;\n\t\t\ttokens.push(view32.subarray(offset / 4, offset / 4 + byteCount / 4));\n\t\t\toffset += byteCount;\n\t\t}\n\t\tresult.push(new ContiguousMultilineTokens(startLineNumber, tokens));\n\t\treturn offset;\n\t}\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\tgetLineRange(): LineRange {\n\t\treturn new LineRange(this._startLineNumber, this._startLineNumber + this._tokens.length);\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\tpublic serializeSize(): number {\n\t\tlet result = 0;\n\t\tresult += 4; // 4 bytes for the start line number\n\t\tresult += 4; // 4 bytes for the line count\n\t\tfor (let i = 0; i < this._tokens.length; i++) {\n\t\t\tconst lineTokens = this._tokens[i];\n\t\t\tif (!(lineTokens instanceof Uint32Array)) {\n\t\t\t\tthrow new Error(`Not supported!`);\n\t\t\t}\n\t\t\tresult += 4; // 4 bytes for the byte count\n\t\t\tresult += lineTokens.byteLength;\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic serialize(destination: Uint8Array, offset: number): number {\n\t\twriteUInt32BE(destination, this._startLineNumber, offset); offset += 4;\n\t\twriteUInt32BE(destination, this._tokens.length, offset); offset += 4;\n\t\tfor (let i = 0; i < this._tokens.length; i++) {\n\t\t\tconst lineTokens = this._tokens[i];\n\t\t\tif (!(lineTokens instanceof Uint32Array)) {\n\t\t\t\tthrow new Error(`Not supported!`);\n\t\t\t}\n\t\t\twriteUInt32BE(destination, lineTokens.byteLength, offset); offset += 4;\n\t\t\tdestination.set(new Uint8Array(lineTokens.buffer), offset); offset += lineTokens.byteLength;\n\t\t}\n\t\treturn offset;\n\t}\n\n\tpublic applyEdit(range: IRange, text: string): void {\n\t\tconst [eolCount, firstLineLength] = countEOL(text);\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\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\tif (firstLineIndex >= this._tokens.length) {\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 >= this._tokens.length) {\n\t\t\t// this deletion completely encompasses this block\n\t\t\tthis._startLineNumber = 0;\n\t\t\tthis._tokens = [];\n\t\t\treturn;\n\t\t}\n\n\t\tif (firstLineIndex === lastLineIndex) {\n\t\t\t// a delete on a single line\n\t\t\tthis._tokens[firstLineIndex] = ContiguousTokensEditing.delete(this._tokens[firstLineIndex], range.startColumn - 1, range.endColumn - 1);\n\t\t\treturn;\n\t\t}\n\n\t\tif (firstLineIndex >= 0) {\n\t\t\t// The first line survives\n\t\t\tthis._tokens[firstLineIndex] = ContiguousTokensEditing.deleteEnding(this._tokens[firstLineIndex], range.startColumn - 1);\n\n\t\t\tif (lastLineIndex < this._tokens.length) {\n\t\t\t\t// The last line survives\n\t\t\t\tconst lastLineTokens = ContiguousTokensEditing.deleteBeginning(this._tokens[lastLineIndex], range.endColumn - 1);\n\n\t\t\t\t// Take remaining text on last line and append it to remaining text on first line\n\t\t\t\tthis._tokens[firstLineIndex] = ContiguousTokensEditing.append(this._tokens[firstLineIndex], lastLineTokens);\n\n\t\t\t\t// Delete middle lines\n\t\t\t\tthis._tokens.splice(firstLineIndex + 1, lastLineIndex - firstLineIndex);\n\t\t\t} else {\n\t\t\t\t// The last line does not survive\n\n\t\t\t\t// Take remaining text on last line and append it to remaining text on first line\n\t\t\t\tthis._tokens[firstLineIndex] = ContiguousTokensEditing.append(this._tokens[firstLineIndex], null);\n\n\t\t\t\t// Delete lines\n\t\t\t\tthis._tokens = this._tokens.slice(0, firstLineIndex + 1);\n\t\t\t}\n\t\t} else {\n\t\t\t// The first line does not survive\n\n\t\t\tconst deletedBefore = -firstLineIndex;\n\t\t\tthis._startLineNumber -= deletedBefore;\n\n\t\t\t// Remove beginning from last line\n\t\t\tthis._tokens[lastLineIndex] = ContiguousTokensEditing.deleteBeginning(this._tokens[lastLineIndex], range.endColumn - 1);\n\n\t\t\t// Delete lines\n\t\t\tthis._tokens = this._tokens.slice(lastLineIndex);\n\t\t}\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 - 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\tif (lineIndex >= this._tokens.length) {\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\tif (eolCount === 0) {\n\t\t\t// Inserting text on one line\n\t\t\tthis._tokens[lineIndex] = ContiguousTokensEditing.insert(this._tokens[lineIndex], position.column - 1, firstLineLength);\n\t\t\treturn;\n\t\t}\n\n\t\tthis._tokens[lineIndex] = ContiguousTokensEditing.deleteEnding(this._tokens[lineIndex], position.column - 1);\n\t\tthis._tokens[lineIndex] = ContiguousTokensEditing.insert(this._tokens[lineIndex], position.column - 1, firstLineLength);\n\n\t\tthis._insertLines(position.lineNumber, eolCount);\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._tokens = arrays.arrayInsert(this._tokens, insertIndex, lineTokens);\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { readUInt32BE, writeUInt32BE } from 'vs/base/common/buffer';\nimport { ContiguousMultilineTokens } from 'vs/editor/common/tokens/contiguousMultilineTokens';\n\nexport class ContiguousMultilineTokensBuilder {\n\n\tpublic static deserialize(buff: Uint8Array): ContiguousMultilineTokens[] {\n\t\tlet offset = 0;\n\t\tconst count = readUInt32BE(buff, offset); offset += 4;\n\t\tconst result: ContiguousMultilineTokens[] = [];\n\t\tfor (let i = 0; i < count; i++) {\n\t\t\toffset = ContiguousMultilineTokens.deserialize(buff, offset, result);\n\t\t}\n\t\treturn result;\n\t}\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\tpublic serialize(): Uint8Array {\n\t\tconst size = this._serializeSize();\n\t\tconst result = new Uint8Array(size);\n\t\tthis._serialize(result);\n\t\treturn result;\n\t}\n\n\tprivate _serializeSize(): number {\n\t\tlet result = 0;\n\t\tresult += 4; // 4 bytes for the count\n\t\tfor (let i = 0; i < this._tokens.length; i++) {\n\t\t\tresult += this._tokens[i].serializeSize();\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate _serialize(destination: Uint8Array): void {\n\t\tlet offset = 0;\n\t\twriteUInt32BE(destination, this._tokens.length, offset); offset += 4;\n\t\tfor (let i = 0; i < this._tokens.length; i++) {\n\t\t\toffset = this._tokens[i].serialize(destination, offset);\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 { 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 _lineHeight: number;\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._lineHeight = options.get(EditorOption.lineHeight);\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._lineHeight = options.get(EditorOption.lineHeight);\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 lineHeight = String(this._lineHeight);\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 lineHeight = String(this._lineHeight);\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, lineHeight, 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, lineHeight, visibleStartLineNumber, output);\n\t\t}\n\t}\n\n\tprivate _renderNormalDecoration(ctx: RenderingContext, range: Range, className: string, shouldFillLineOnLineBreak: boolean, showIfCollapsed: boolean, lineHeight: string, 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 * Returns if there is any whitespace in the document.\n\t */\n\tpublic hasWhitespace(): boolean {\n\t\tthis._checkPendingChanges();\n\t\treturn this.getWhitespacesCount() > 0;\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};\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\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.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\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\t//#endregion\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\tgetLinesViewportDataAtScrollTop(scrollTop: number): 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\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 { 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 class CodeActionKind {\n\tprivate static readonly sep = '.';\n\n\tpublic static readonly None = new CodeActionKind('@@none@@'); // Special code action that contains nothing\n\tpublic static readonly Empty = new CodeActionKind('');\n\tpublic static readonly QuickFix = new CodeActionKind('quickfix');\n\tpublic static readonly Refactor = new CodeActionKind('refactor');\n\tpublic static readonly RefactorExtract = CodeActionKind.Refactor.append('extract');\n\tpublic static readonly RefactorInline = CodeActionKind.Refactor.append('inline');\n\tpublic static readonly RefactorMove = CodeActionKind.Refactor.append('move');\n\tpublic static readonly RefactorRewrite = CodeActionKind.Refactor.append('rewrite');\n\tpublic static readonly Notebook = new CodeActionKind('notebook');\n\tpublic static readonly Source = new CodeActionKind('source');\n\tpublic static readonly SourceOrganizeImports = CodeActionKind.Source.append('organizeImports');\n\tpublic static readonly SourceFixAll = CodeActionKind.Source.append('fixAll');\n\tpublic static readonly SurroundWith = CodeActionKind.Refactor.append('surround');\n\n\tconstructor(\n\t\tpublic readonly value: string\n\t) { }\n\n\tpublic equals(other: CodeActionKind): boolean {\n\t\treturn this.value === other.value;\n\t}\n\n\tpublic contains(other: CodeActionKind): boolean {\n\t\treturn this.equals(other) || this.value === '' || other.value.startsWith(this.value + CodeActionKind.sep);\n\t}\n\n\tpublic intersects(other: CodeActionKind): boolean {\n\t\treturn this.contains(other) || other.contains(this);\n\t}\n\n\tpublic append(part: string): CodeActionKind {\n\t\treturn new CodeActionKind(this.value + CodeActionKind.sep + part);\n\t}\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?: CodeActionKind;\n\treadonly excludes?: readonly CodeActionKind[];\n\treadonly includeSourceActions?: boolean;\n\treadonly onlyIncludePreferredActions?: boolean;\n}\n\nexport function mayIncludeActionsOfKind(filter: CodeActionFilter, providedKind: CodeActionKind): 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 CodeActionKind(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: CodeActionKind, exclude: CodeActionKind, include: CodeActionKind | 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: CodeActionKind; 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: CodeActionKind) {\n\t\treturn typeof arg.kind === 'string'\n\t\t\t? new CodeActionKind(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: CodeActionKind,\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 _tabSize: 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\ttabSize: 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._tabSize = tabSize;\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._tabSize);\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, tabSize: number, isTab: boolean, columnSize: number): number {\n\t\tif (isTab) {\n\t\t\treturn currentVisibleColumn + (tabSize - (currentVisibleColumn % tabSize));\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, tabSize: 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, tabSize, 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 / tabSize) * tabSize;\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, tabSize, 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 matchIndex(index: number): ReplacePiece {\n\t\treturn new ReplacePiece(null, index, 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\thidesLine(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\tpublic get decorationProvider() { return this._decorationProvider; }\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 { 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\tsetEnabled(enabled: boolean): void;\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","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { compareBy } from 'vs/base/common/arrays';\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 { ISingleEditOperation } from 'vs/editor/common/core/editOperation';\nimport { Position } from 'vs/editor/common/core/position';\nimport { IRange, Range } from 'vs/editor/common/core/range';\nimport { IModelDeltaDecoration } from 'vs/editor/common/model';\nimport { TextModel } from 'vs/editor/common/model/textModel';\n\nexport function applyEdits(text: string, edits: { range: IRange; text: string }[]): string {\n\tconst transformer = new PositionOffsetTransformer(text);\n\tconst offsetEdits = edits.map(e => {\n\t\tconst range = Range.lift(e.range);\n\t\treturn ({\n\t\t\tstartOffset: transformer.getOffset(range.getStartPosition()),\n\t\t\tendOffset: transformer.getOffset(range.getEndPosition()),\n\t\t\ttext: e.text\n\t\t});\n\t});\n\n\toffsetEdits.sort((a, b) => b.startOffset - a.startOffset);\n\n\tfor (const edit of offsetEdits) {\n\t\ttext = text.substring(0, edit.startOffset) + edit.text + text.substring(edit.endOffset);\n\t}\n\n\treturn text;\n}\n\nclass PositionOffsetTransformer {\n\tprivate readonly lineStartOffsetByLineIdx: number[];\n\n\tconstructor(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\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\nexport function lengthOfText(text: string): Position {\n\tlet line = 1;\n\tlet column = 1;\n\tfor (const c of text) {\n\t\tif (c === '\\n') {\n\t\t\tline++;\n\t\t\tcolumn = 1;\n\t\t} else {\n\t\t\tcolumn++;\n\t\t}\n\t}\n\treturn new Position(line, column);\n}\n\n/**\n * Given some text edits, this function finds the new ranges of the editted text post application of all edits.\n * Assumes that the edit ranges are disjoint and they are sorted in the order of the ranges\n * @param edits edits applied\n * @returns new ranges post edits for every edit\n */\nexport function getNewRanges(edits: ISingleEditOperation[]): Range[] {\n\tconst newRanges: Range[] = [];\n\tlet previousEditEndLineNumber = 0;\n\tlet lineOffset = 0;\n\tlet columnOffset = 0;\n\n\tfor (const edit of edits) {\n\t\tconst text = edit.text ?? '';\n\t\tconst textLength = lengthOfText(text);\n\t\tconst newRangeStart = Position.lift({\n\t\t\tlineNumber: edit.range.startLineNumber + lineOffset,\n\t\t\tcolumn: edit.range.startColumn + (edit.range.startLineNumber === previousEditEndLineNumber ? columnOffset : 0)\n\t\t});\n\t\tconst newRangeEnd = addPositions(\n\t\t\tnewRangeStart,\n\t\t\ttextLength\n\t\t);\n\t\tnewRanges.push(Range.fromPositions(newRangeStart, newRangeEnd));\n\t\tlineOffset += textLength.lineNumber - edit.range.endLineNumber + edit.range.startLineNumber - 1;\n\t\tcolumnOffset = newRangeEnd.column - edit.range.endColumn;\n\t\tpreviousEditEndLineNumber = edit.range.endLineNumber;\n\t}\n\treturn newRanges;\n}\n\n/**\n * Given a text model and edits, this function finds the inverse text edits\n * @param model model on which to apply the edits\n * @param edits edits applied\n * @returns inverse edits\n */\nexport function inverseEdits(model: TextModel, edits: ISingleEditOperation[]): ISingleEditOperation[] {\n\tconst sortPerm = Permutation.createSortPermutation(edits, compareBy(e => e.range, Range.compareRangesUsingStarts));\n\tconst sortedRanges = getNewRanges(sortPerm.apply(edits));\n\tconst newRanges = sortPerm.inverse().apply(sortedRanges);\n\tconst inverseEdits: ISingleEditOperation[] = [];\n\tfor (let i = 0; i < edits.length; i++) {\n\t\tinverseEdits.push({ range: newRanges[i], text: model.getValueInRange(edits[i].range) });\n\t}\n\treturn inverseEdits;\n}\n\nexport class Permutation {\n\tconstructor(private readonly _indexMap: number[]) { }\n\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\tapply(arr: readonly T[]): T[] {\n\t\treturn arr.map((_, index) => arr[this._indexMap[index]]);\n\t}\n\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 { equals } from 'vs/base/common/arrays';\nimport { splitLines } from 'vs/base/common/strings';\nimport { Range } from 'vs/editor/common/core/range';\nimport { ColumnRange, applyEdits } 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\t/**\n\t * Only used for testing/debugging.\n\t*/\n\trender(documentText: string, debug: boolean = false): string {\n\t\tconst l = this.lineNumber;\n\t\treturn applyEdits(documentText, [\n\t\t\t...this.parts.map(p => ({\n\t\t\t\trange: { startLineNumber: l, endLineNumber: l, startColumn: p.column, endColumn: p.column },\n\t\t\t\ttext: debug ? `[${p.lines.join('\\n')}]` : p.lines.join('\\n')\n\t\t\t})),\n\t\t]);\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 = applyEdits(cappedLineText,\n\t\t\tthis.parts.map(p => ({\n\t\t\t\trange: { startLineNumber: 1, endLineNumber: 1, startColumn: p.column, endColumn: p.column },\n\t\t\t\ttext: p.lines.join('\\n')\n\t\t\t}))\n\t\t);\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\trender(documentText: string, debug: boolean = false): string {\n\t\tconst replaceRange = this.columnRange.toRange(this.lineNumber);\n\n\t\tif (debug) {\n\t\t\treturn applyEdits(documentText, [\n\t\t\t\t{ range: Range.fromPositions(replaceRange.getStartPosition()), text: `(` },\n\t\t\t\t{ range: Range.fromPositions(replaceRange.getEndPosition()), text: `)[${this.newLines.join('\\n')}]` }\n\t\t\t]);\n\t\t} else {\n\t\t\treturn applyEdits(documentText, [\n\t\t\t\t{ range: replaceRange, text: this.newLines.join('\\n') }\n\t\t\t]);\n\t\t}\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 { 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 { EndOfLinePreference, ITextModel } from 'vs/editor/common/model';\nimport { GhostText, GhostTextPart } from 'vs/editor/contrib/inlineCompletions/browser/ghostText';\nimport { addPositions, lengthOfText } from 'vs/editor/contrib/inlineCompletions/browser/utils';\n\nexport class SingleTextEdit {\n\tconstructor(\n\t\tpublic readonly range: Range,\n\t\tpublic readonly text: string\n\t) {\n\t}\n\n\tstatic equals(first: SingleTextEdit, second: SingleTextEdit) {\n\t\treturn first.range.equalsRange(second.range) && first.text === second.text;\n\n\t}\n\n\tremoveCommonPrefix(model: ITextModel, validModelRange?: Range): SingleTextEdit {\n\t\tconst modelRange = validModelRange ? this.range.intersectRanges(validModelRange) : this.range;\n\t\tif (!modelRange) {\n\t\t\treturn this;\n\t\t}\n\t\tconst valueToReplace = model.getValueInRange(modelRange, EndOfLinePreference.LF);\n\t\tconst commonPrefixLen = commonPrefixLength(valueToReplace, this.text);\n\t\tconst start = addPositions(this.range.getStartPosition(), lengthOfText(valueToReplace.substring(0, commonPrefixLen)));\n\t\tconst text = this.text.substring(commonPrefixLen);\n\t\tconst range = Range.fromPositions(start, this.range.getEndPosition());\n\t\treturn new SingleTextEdit(range, text);\n\t}\n\n\taugments(base: SingleTextEdit): boolean {\n\t\t// The augmented completion must replace the base range, but can replace even more\n\t\treturn this.text.startsWith(base.text) && rangeExtends(this.range, base.range);\n\t}\n\n\t/**\n\t * @param previewSuffixLength Sets where to split `inlineCompletion.text`.\n\t * \tIf the text is `hello` and the suffix length is 2, the non-preview part is `hel` and the preview-part is `lo`.\n\t*/\n\tcomputeGhostText(\n\t\tmodel: ITextModel,\n\t\tmode: 'prefix' | 'subword' | 'subwordSmart',\n\t\tcursorPosition?: Position,\n\t\tpreviewSuffixLength = 0\n\t): GhostText | undefined {\n\t\tlet edit = this.removeCommonPrefix(model);\n\n\t\tif (edit.range.endLineNumber !== edit.range.startLineNumber) {\n\t\t\t// This edit might span multiple lines, but the first lines must be a common prefix.\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst sourceLine = model.getLineContent(edit.range.startLineNumber);\n\t\tconst sourceIndentationLength = getLeadingWhitespace(sourceLine).length;\n\n\t\tconst suggestionTouchesIndentation = edit.range.startColumn - 1 <= sourceIndentationLength;\n\t\tif (suggestionTouchesIndentation) {\n\t\t\t// source: ··········[······abc]\n\t\t\t// ^^^^^^^^^ inlineCompletion.range\n\t\t\t// ^^^^^^^^^^ ^^^^^^ sourceIndentationLength\n\t\t\t// ^^^^^^ replacedIndentation.length\n\t\t\t// ^^^ rangeThatDoesNotReplaceIndentation\n\n\t\t\t// inlineCompletion.text: '··foo'\n\t\t\t// ^^ suggestionAddedIndentationLength\n\n\t\t\tconst suggestionAddedIndentationLength = getLeadingWhitespace(edit.text).length;\n\n\t\t\tconst replacedIndentation = sourceLine.substring(edit.range.startColumn - 1, sourceIndentationLength);\n\n\t\t\tconst [startPosition, endPosition] = [edit.range.getStartPosition(), edit.range.getEndPosition()];\n\t\t\tconst newStartPosition =\n\t\t\t\tstartPosition.column + replacedIndentation.length <= endPosition.column\n\t\t\t\t\t? startPosition.delta(0, replacedIndentation.length)\n\t\t\t\t\t: endPosition;\n\t\t\tconst rangeThatDoesNotReplaceIndentation = Range.fromPositions(newStartPosition, endPosition);\n\n\t\t\tconst suggestionWithoutIndentationChange =\n\t\t\t\tedit.text.startsWith(replacedIndentation)\n\t\t\t\t\t// Adds more indentation without changing existing indentation: We can add ghost text for this\n\t\t\t\t\t? edit.text.substring(replacedIndentation.length)\n\t\t\t\t\t// Changes or removes existing indentation. Only add ghost text for the non-indentation part.\n\t\t\t\t\t: edit.text.substring(suggestionAddedIndentationLength);\n\n\t\t\tedit = new SingleTextEdit(rangeThatDoesNotReplaceIndentation, suggestionWithoutIndentationChange);\n\t\t}\n\n\t\t// This is a single line string\n\t\tconst valueToBeReplaced = model.getValueInRange(edit.range);\n\n\t\tconst changes = cachingDiff(valueToBeReplaced, edit.text);\n\n\t\tif (!changes) {\n\t\t\t// No ghost text in case the diff would be too slow to compute\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst lineNumber = edit.range.startLineNumber;\n\n\t\tconst parts = new Array();\n\n\t\tif (mode === 'prefix') {\n\t\t\tconst filteredChanges = changes.filter(c => c.originalLength === 0);\n\t\t\tif (filteredChanges.length > 1 || filteredChanges.length === 1 && filteredChanges[0].originalStart !== valueToBeReplaced.length) {\n\t\t\t\t// Prefixes only have a single change.\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t}\n\n\t\tconst previewStartInCompletionText = edit.text.length - previewSuffixLength;\n\n\t\tfor (const c of changes) {\n\t\t\tconst insertColumn = edit.range.startColumn + c.originalStart + c.originalLength;\n\n\t\t\tif (mode === 'subwordSmart' && cursorPosition && cursorPosition.lineNumber === edit.range.startLineNumber && insertColumn < cursorPosition.column) {\n\t\t\t\t// No ghost text before cursor\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\tif (c.originalLength > 0) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\tif (c.modifiedLength === 0) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst modifiedEnd = c.modifiedStart + c.modifiedLength;\n\t\t\tconst nonPreviewTextEnd = Math.max(c.modifiedStart, Math.min(modifiedEnd, previewStartInCompletionText));\n\t\t\tconst nonPreviewText = edit.text.substring(c.modifiedStart, nonPreviewTextEnd);\n\t\t\tconst italicText = edit.text.substring(nonPreviewTextEnd, Math.max(c.modifiedStart, modifiedEnd));\n\n\t\t\tif (nonPreviewText.length > 0) {\n\t\t\t\tparts.push(new GhostTextPart(insertColumn, nonPreviewText, false));\n\t\t\t}\n\t\t\tif (italicText.length > 0) {\n\t\t\t\tparts.push(new GhostTextPart(insertColumn, italicText, true));\n\t\t\t}\n\t\t}\n\n\t\treturn new GhostText(lineNumber, parts);\n\t}\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\nexport const inlineEditAcceptId = 'editor.action.inlineEdit.accept';\nexport const inlineEditTriggerId = 'editor.action.inlineEdit.trigger';\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\tabstract toTextmateString(): string;\n\n\tlen(): number {\n\t\treturn 0;\n\t}\n\n\tabstract clone(): Marker;\n}\n\nexport class Text extends Marker {\n\n\tstatic escape(value: string): string {\n\t\treturn value.replace(/\\$|}|\\\\/g, '\\\\$&');\n\t}\n\n\tconstructor(public value: string) {\n\t\tsuper();\n\t}\n\toverride toString() {\n\t\treturn this.value;\n\t}\n\ttoTextmateString(): string {\n\t\treturn Text.escape(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\ttoTextmateString(): string {\n\t\tlet transformString = '';\n\t\tif (this.transform) {\n\t\t\ttransformString = this.transform.toTextmateString();\n\t\t}\n\t\tif (this.children.length === 0 && !this.transform) {\n\t\t\treturn `\\$${this.index}`;\n\t\t} else if (this.children.length === 0) {\n\t\t\treturn `\\${${this.index}${transformString}}`;\n\t\t} else if (this.choice) {\n\t\t\treturn `\\${${this.index}|${this.choice.toTextmateString()}|${transformString}}`;\n\t\t} else {\n\t\t\treturn `\\${${this.index}:${this.children.map(child => child.toTextmateString()).join('')}${transformString}}`;\n\t\t}\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\ttoTextmateString(): string {\n\t\treturn this.options\n\t\t\t.map(option => option.value.replace(/\\||,|\\\\/g, '\\\\$&'))\n\t\t\t.join(',');\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\ttoTextmateString(): string {\n\t\treturn `/${this.regexp.source}/${this.children.map(c => c.toTextmateString())}/${(this.regexp.ignoreCase ? 'i' : '') + (this.regexp.global ? 'g' : '')}`;\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\ttoTextmateString(): string {\n\t\tlet value = '${';\n\t\tvalue += this.index;\n\t\tif (this.shorthandName) {\n\t\t\tvalue += `:/${this.shorthandName}`;\n\n\t\t} else if (this.ifValue && this.elseValue) {\n\t\t\tvalue += `:?${this.ifValue}:${this.elseValue}`;\n\t\t} else if (this.ifValue) {\n\t\t\tvalue += `:+${this.ifValue}`;\n\t\t} else if (this.elseValue) {\n\t\t\tvalue += `:-${this.elseValue}`;\n\t\t}\n\t\tvalue += '}';\n\t\treturn value;\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\ttoTextmateString(): string {\n\t\tlet transformString = '';\n\t\tif (this.transform) {\n\t\t\ttransformString = this.transform.toTextmateString();\n\t\t}\n\t\tif (this.children.length === 0) {\n\t\t\treturn `\\${${this.name}${transformString}}`;\n\t\t} else {\n\t\t\treturn `\\${${this.name}:${this.children.map(child => child.toTextmateString()).join('')}${transformString}}`;\n\t\t}\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\ttoTextmateString(): string {\n\t\treturn this.children.reduce((prev, cur) => prev + cur.toTextmateString(), '');\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\t/**\n\t * Takes a snippet and returns the insertable string, e.g return the snippet-string\n\t * without any placeholder, tabstop, variables etc...\n\t */\n\tstatic asInsertText(value: string): string {\n\t\treturn new SnippetParser().parse(value).toString();\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\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\treadonly from?: string;\n\treadonly target?: string;\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; enabled?: boolean; checked?: boolean; class?: string; run: Function }): IAction {\n\treturn {\n\t\tid: props.id,\n\t\tlabel: 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\ttooltip: props.label\n\t};\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { AsyncDataTree } from 'vs/base/browser/ui/tree/asyncDataTree';\nimport { Action } from 'vs/base/common/actions';\nimport * as nls from 'vs/nls';\n\nexport class CollapseAllAction extends Action {\n\n\tconstructor(private viewer: AsyncDataTree, enabled: boolean) {\n\t\tsuper('vs.tree.collapse', nls.localize('collapse all', \"Collapse All\"), 'collapse-all', enabled);\n\t}\n\n\toverride async run(): Promise {\n\t\tthis.viewer.collapseAll();\n\t\tthis.viewer.setSelection([]);\n\t\tthis.viewer.setFocus([]);\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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: () => any) {\n\t\tsuper();\n\t}\n\n\tprotected override runAction(action: IAction, _context?: unknown): Promise {\n\t\treturn super.runAction(action, this._getContext());\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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';\n\nconst minute = 60;\nconst hour = minute * 60;\nconst day = hour * 24;\nconst week = day * 7;\nconst month = day * 30;\nconst year = day * 365;\n\n/**\n * Create a localized difference of the time between now and the specified date.\n * @param date The date to generate the difference from.\n * @param appendAgoLabel Whether to append the \" ago\" to the end.\n * @param useFullTimeWords Whether to use full words (eg. seconds) instead of\n * shortened (eg. secs).\n * @param disallowNow Whether to disallow the string \"now\" when the difference\n * is less than 30 seconds.\n */\nexport function fromNow(date: number | Date, appendAgoLabel?: boolean, useFullTimeWords?: boolean, disallowNow?: boolean): string {\n\tif (typeof date !== 'number') {\n\t\tdate = date.getTime();\n\t}\n\n\tconst seconds = Math.round((new Date().getTime() - date) / 1000);\n\tif (seconds < -30) {\n\t\treturn localize('date.fromNow.in', 'in {0}', fromNow(new Date().getTime() + seconds * 1000, false));\n\t}\n\n\tif (!disallowNow && seconds < 30) {\n\t\treturn localize('date.fromNow.now', 'now');\n\t}\n\n\tlet value: number;\n\tif (seconds < minute) {\n\t\tvalue = seconds;\n\n\t\tif (appendAgoLabel) {\n\t\t\tif (value === 1) {\n\t\t\t\treturn useFullTimeWords\n\t\t\t\t\t? localize('date.fromNow.seconds.singular.ago.fullWord', '{0} second ago', value)\n\t\t\t\t\t: localize('date.fromNow.seconds.singular.ago', '{0} sec ago', value);\n\t\t\t} else {\n\t\t\t\treturn useFullTimeWords\n\t\t\t\t\t? localize('date.fromNow.seconds.plural.ago.fullWord', '{0} seconds ago', value)\n\t\t\t\t\t: localize('date.fromNow.seconds.plural.ago', '{0} secs ago', value);\n\t\t\t}\n\t\t} else {\n\t\t\tif (value === 1) {\n\t\t\t\treturn useFullTimeWords\n\t\t\t\t\t? localize('date.fromNow.seconds.singular.fullWord', '{0} second', value)\n\t\t\t\t\t: localize('date.fromNow.seconds.singular', '{0} sec', value);\n\t\t\t} else {\n\t\t\t\treturn useFullTimeWords\n\t\t\t\t\t? localize('date.fromNow.seconds.plural.fullWord', '{0} seconds', value)\n\t\t\t\t\t: localize('date.fromNow.seconds.plural', '{0} secs', value);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (seconds < hour) {\n\t\tvalue = Math.floor(seconds / minute);\n\t\tif (appendAgoLabel) {\n\t\t\tif (value === 1) {\n\t\t\t\treturn useFullTimeWords\n\t\t\t\t\t? localize('date.fromNow.minutes.singular.ago.fullWord', '{0} minute ago', value)\n\t\t\t\t\t: localize('date.fromNow.minutes.singular.ago', '{0} min ago', value);\n\t\t\t} else {\n\t\t\t\treturn useFullTimeWords\n\t\t\t\t\t? localize('date.fromNow.minutes.plural.ago.fullWord', '{0} minutes ago', value)\n\t\t\t\t\t: localize('date.fromNow.minutes.plural.ago', '{0} mins ago', value);\n\t\t\t}\n\t\t} else {\n\t\t\tif (value === 1) {\n\t\t\t\treturn useFullTimeWords\n\t\t\t\t\t? localize('date.fromNow.minutes.singular.fullWord', '{0} minute', value)\n\t\t\t\t\t: localize('date.fromNow.minutes.singular', '{0} min', value);\n\t\t\t} else {\n\t\t\t\treturn useFullTimeWords\n\t\t\t\t\t? localize('date.fromNow.minutes.plural.fullWord', '{0} minutes', value)\n\t\t\t\t\t: localize('date.fromNow.minutes.plural', '{0} mins', value);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (seconds < day) {\n\t\tvalue = Math.floor(seconds / hour);\n\t\tif (appendAgoLabel) {\n\t\t\tif (value === 1) {\n\t\t\t\treturn useFullTimeWords\n\t\t\t\t\t? localize('date.fromNow.hours.singular.ago.fullWord', '{0} hour ago', value)\n\t\t\t\t\t: localize('date.fromNow.hours.singular.ago', '{0} hr ago', value);\n\t\t\t} else {\n\t\t\t\treturn useFullTimeWords\n\t\t\t\t\t? localize('date.fromNow.hours.plural.ago.fullWord', '{0} hours ago', value)\n\t\t\t\t\t: localize('date.fromNow.hours.plural.ago', '{0} hrs ago', value);\n\t\t\t}\n\t\t} else {\n\t\t\tif (value === 1) {\n\t\t\t\treturn useFullTimeWords\n\t\t\t\t\t? localize('date.fromNow.hours.singular.fullWord', '{0} hour', value)\n\t\t\t\t\t: localize('date.fromNow.hours.singular', '{0} hr', value);\n\t\t\t} else {\n\t\t\t\treturn useFullTimeWords\n\t\t\t\t\t? localize('date.fromNow.hours.plural.fullWord', '{0} hours', value)\n\t\t\t\t\t: localize('date.fromNow.hours.plural', '{0} hrs', value);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (seconds < week) {\n\t\tvalue = Math.floor(seconds / day);\n\t\tif (appendAgoLabel) {\n\t\t\treturn value === 1\n\t\t\t\t? localize('date.fromNow.days.singular.ago', '{0} day ago', value)\n\t\t\t\t: localize('date.fromNow.days.plural.ago', '{0} days ago', value);\n\t\t} else {\n\t\t\treturn value === 1\n\t\t\t\t? localize('date.fromNow.days.singular', '{0} day', value)\n\t\t\t\t: localize('date.fromNow.days.plural', '{0} days', value);\n\t\t}\n\t}\n\n\tif (seconds < month) {\n\t\tvalue = Math.floor(seconds / week);\n\t\tif (appendAgoLabel) {\n\t\t\tif (value === 1) {\n\t\t\t\treturn useFullTimeWords\n\t\t\t\t\t? localize('date.fromNow.weeks.singular.ago.fullWord', '{0} week ago', value)\n\t\t\t\t\t: localize('date.fromNow.weeks.singular.ago', '{0} wk ago', value);\n\t\t\t} else {\n\t\t\t\treturn useFullTimeWords\n\t\t\t\t\t? localize('date.fromNow.weeks.plural.ago.fullWord', '{0} weeks ago', value)\n\t\t\t\t\t: localize('date.fromNow.weeks.plural.ago', '{0} wks ago', value);\n\t\t\t}\n\t\t} else {\n\t\t\tif (value === 1) {\n\t\t\t\treturn useFullTimeWords\n\t\t\t\t\t? localize('date.fromNow.weeks.singular.fullWord', '{0} week', value)\n\t\t\t\t\t: localize('date.fromNow.weeks.singular', '{0} wk', value);\n\t\t\t} else {\n\t\t\t\treturn useFullTimeWords\n\t\t\t\t\t? localize('date.fromNow.weeks.plural.fullWord', '{0} weeks', value)\n\t\t\t\t\t: localize('date.fromNow.weeks.plural', '{0} wks', value);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (seconds < year) {\n\t\tvalue = Math.floor(seconds / month);\n\t\tif (appendAgoLabel) {\n\t\t\tif (value === 1) {\n\t\t\t\treturn useFullTimeWords\n\t\t\t\t\t? localize('date.fromNow.months.singular.ago.fullWord', '{0} month ago', value)\n\t\t\t\t\t: localize('date.fromNow.months.singular.ago', '{0} mo ago', value);\n\t\t\t} else {\n\t\t\t\treturn useFullTimeWords\n\t\t\t\t\t? localize('date.fromNow.months.plural.ago.fullWord', '{0} months ago', value)\n\t\t\t\t\t: localize('date.fromNow.months.plural.ago', '{0} mos ago', value);\n\t\t\t}\n\t\t} else {\n\t\t\tif (value === 1) {\n\t\t\t\treturn useFullTimeWords\n\t\t\t\t\t? localize('date.fromNow.months.singular.fullWord', '{0} month', value)\n\t\t\t\t\t: localize('date.fromNow.months.singular', '{0} mo', value);\n\t\t\t} else {\n\t\t\t\treturn useFullTimeWords\n\t\t\t\t\t? localize('date.fromNow.months.plural.fullWord', '{0} months', value)\n\t\t\t\t\t: localize('date.fromNow.months.plural', '{0} mos', value);\n\t\t\t}\n\t\t}\n\t}\n\n\tvalue = Math.floor(seconds / year);\n\tif (appendAgoLabel) {\n\t\tif (value === 1) {\n\t\t\treturn useFullTimeWords\n\t\t\t\t? localize('date.fromNow.years.singular.ago.fullWord', '{0} year ago', value)\n\t\t\t\t: localize('date.fromNow.years.singular.ago', '{0} yr ago', value);\n\t\t} else {\n\t\t\treturn useFullTimeWords\n\t\t\t\t? localize('date.fromNow.years.plural.ago.fullWord', '{0} years ago', value)\n\t\t\t\t: localize('date.fromNow.years.plural.ago', '{0} yrs ago', value);\n\t\t}\n\t} else {\n\t\tif (value === 1) {\n\t\t\treturn useFullTimeWords\n\t\t\t\t? localize('date.fromNow.years.singular.fullWord', '{0} year', value)\n\t\t\t\t: localize('date.fromNow.years.singular', '{0} yr', value);\n\t\t} else {\n\t\t\treturn useFullTimeWords\n\t\t\t\t? localize('date.fromNow.years.plural.fullWord', '{0} years', value)\n\t\t\t\t: localize('date.fromNow.years.plural', '{0} yrs', value);\n\t\t}\n\t}\n}\n\n/**\n * Gets a readable duration with intelligent/lossy precision. For example \"40ms\" or \"3.040s\")\n * @param ms The duration to get in milliseconds.\n * @param useFullTimeWords Whether to use full words (eg. seconds) instead of\n * shortened (eg. secs).\n */\nexport function getDurationString(ms: number, useFullTimeWords?: boolean) {\n\tconst seconds = Math.abs(ms / 1000);\n\tif (seconds < 1) {\n\t\treturn useFullTimeWords\n\t\t\t? localize('duration.ms.full', '{0} milliseconds', ms)\n\t\t\t: localize('duration.ms', '{0}ms', ms);\n\t}\n\tif (seconds < minute) {\n\t\treturn useFullTimeWords\n\t\t\t? localize('duration.s.full', '{0} seconds', Math.round(ms) / 1000)\n\t\t\t: localize('duration.s', '{0}s', Math.round(ms) / 1000);\n\t}\n\tif (seconds < hour) {\n\t\treturn useFullTimeWords\n\t\t\t? localize('duration.m.full', '{0} minutes', Math.round(ms / (1000 * minute)))\n\t\t\t: localize('duration.m', '{0} mins', Math.round(ms / (1000 * minute)));\n\t}\n\tif (seconds < day) {\n\t\treturn useFullTimeWords\n\t\t\t? localize('duration.h.full', '{0} hours', Math.round(ms / (1000 * hour)))\n\t\t\t: localize('duration.h', '{0} hrs', Math.round(ms / (1000 * hour)));\n\t}\n\treturn localize('duration.d', '{0} days', Math.round(ms / (1000 * day)));\n}\n\nexport function toLocalISOString(date: Date): string {\n\treturn date.getFullYear() +\n\t\t'-' + String(date.getMonth() + 1).padStart(2, '0') +\n\t\t'-' + String(date.getDate()).padStart(2, '0') +\n\t\t'T' + String(date.getHours()).padStart(2, '0') +\n\t\t':' + String(date.getMinutes()).padStart(2, '0') +\n\t\t':' + String(date.getSeconds()).padStart(2, '0') +\n\t\t'.' + (date.getMilliseconds() / 1000).toFixed(3).slice(2, 5) +\n\t\t'Z';\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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';\nimport { IAction } from 'vs/base/common/actions';\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\nexport interface IErrorWithActions extends Error {\n\tactions: IAction[];\n}\n\nexport function isErrorWithActions(obj: unknown): obj is IErrorWithActions {\n\tconst candidate = obj as IErrorWithActions | undefined;\n\n\treturn candidate instanceof Error && Array.isArray(candidate.actions);\n}\n\nexport function createErrorWithActions(messageOrError: string | Error, actions: IAction[]): IErrorWithActions {\n\tlet error: IErrorWithActions;\n\tif (typeof messageOrError === 'string') {\n\t\terror = new Error(messageOrError) as IErrorWithActions;\n\t} else {\n\t\terror = messageOrError as IErrorWithActions;\n\t}\n\n\terror.actions = actions;\n\n\treturn error;\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { toErrorMessage } from 'vs/base/common/errorMessage';\nimport { ErrorNoTelemetry, getErrorMessage } from 'vs/base/common/errors';\nimport { mark } from 'vs/base/common/performance';\n\nclass MissingStoresError extends Error {\n\tconstructor(readonly db: IDBDatabase) {\n\t\tsuper('Missing stores');\n\t}\n}\n\nexport class DBClosedError extends Error {\n\treadonly code = 'DBClosed';\n\tconstructor(dbName: string) {\n\t\tsuper(`IndexedDB database '${dbName}' is closed.`);\n\t}\n}\n\nexport class IndexedDB {\n\n\tstatic async create(name: string, version: number | undefined, stores: string[]): Promise {\n\t\tconst database = await IndexedDB.openDatabase(name, version, stores);\n\t\treturn new IndexedDB(database, name);\n\t}\n\n\tprivate static async openDatabase(name: string, version: number | undefined, stores: string[]): Promise {\n\t\tmark(`code/willOpenDatabase/${name}`);\n\t\ttry {\n\t\t\treturn await IndexedDB.doOpenDatabase(name, version, stores);\n\t\t} catch (err) {\n\t\t\tif (err instanceof MissingStoresError) {\n\t\t\t\tconsole.info(`Attempting to recreate the IndexedDB once.`, name);\n\n\t\t\t\ttry {\n\t\t\t\t\t// Try to delete the db\n\t\t\t\t\tawait IndexedDB.deleteDatabase(err.db);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconsole.error(`Error while deleting the IndexedDB`, getErrorMessage(error));\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\n\t\t\t\treturn await IndexedDB.doOpenDatabase(name, version, stores);\n\t\t\t}\n\n\t\t\tthrow err;\n\t\t} finally {\n\t\t\tmark(`code/didOpenDatabase/${name}`);\n\t\t}\n\t}\n\n\tprivate static doOpenDatabase(name: string, version: number | undefined, stores: string[]): Promise {\n\t\treturn new Promise((c, e) => {\n\t\t\tconst request = indexedDB.open(name, version);\n\t\t\trequest.onerror = () => e(request.error);\n\t\t\trequest.onsuccess = () => {\n\t\t\t\tconst db = request.result;\n\t\t\t\tfor (const store of stores) {\n\t\t\t\t\tif (!db.objectStoreNames.contains(store)) {\n\t\t\t\t\t\tconsole.error(`Error while opening IndexedDB. Could not find '${store}'' object store`);\n\t\t\t\t\t\te(new MissingStoresError(db));\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tc(db);\n\t\t\t};\n\t\t\trequest.onupgradeneeded = () => {\n\t\t\t\tconst db = request.result;\n\t\t\t\tfor (const store of stores) {\n\t\t\t\t\tif (!db.objectStoreNames.contains(store)) {\n\t\t\t\t\t\tdb.createObjectStore(store);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\t\t});\n\t}\n\n\tprivate static deleteDatabase(database: IDBDatabase): Promise {\n\t\treturn new Promise((c, e) => {\n\t\t\t// Close any opened connections\n\t\t\tdatabase.close();\n\n\t\t\t// Delete the db\n\t\t\tconst deleteRequest = indexedDB.deleteDatabase(database.name);\n\t\t\tdeleteRequest.onerror = (err) => e(deleteRequest.error);\n\t\t\tdeleteRequest.onsuccess = () => c();\n\t\t});\n\t}\n\n\tprivate database: IDBDatabase | null = null;\n\tprivate readonly pendingTransactions: IDBTransaction[] = [];\n\n\tconstructor(database: IDBDatabase, private readonly name: string) {\n\t\tthis.database = database;\n\t}\n\n\thasPendingTransactions(): boolean {\n\t\treturn this.pendingTransactions.length > 0;\n\t}\n\n\tclose(): void {\n\t\tif (this.pendingTransactions.length) {\n\t\t\tthis.pendingTransactions.splice(0, this.pendingTransactions.length).forEach(transaction => transaction.abort());\n\t\t}\n\t\tthis.database?.close();\n\t\tthis.database = null;\n\t}\n\n\trunInTransaction(store: string, transactionMode: IDBTransactionMode, dbRequestFn: (store: IDBObjectStore) => IDBRequest[]): Promise;\n\trunInTransaction(store: string, transactionMode: IDBTransactionMode, dbRequestFn: (store: IDBObjectStore) => IDBRequest): Promise;\n\tasync runInTransaction(store: string, transactionMode: IDBTransactionMode, dbRequestFn: (store: IDBObjectStore) => IDBRequest | IDBRequest[]): Promise {\n\t\tif (!this.database) {\n\t\t\tthrow new DBClosedError(this.name);\n\t\t}\n\t\tconst transaction = this.database.transaction(store, transactionMode);\n\t\tthis.pendingTransactions.push(transaction);\n\t\treturn new Promise((c, e) => {\n\t\t\ttransaction.oncomplete = () => {\n\t\t\t\tif (Array.isArray(request)) {\n\t\t\t\t\tc(request.map(r => r.result));\n\t\t\t\t} else {\n\t\t\t\t\tc(request.result);\n\t\t\t\t}\n\t\t\t};\n\t\t\ttransaction.onerror = () => e(transaction.error ? ErrorNoTelemetry.fromError(transaction.error) : new ErrorNoTelemetry('unknown error'));\n\t\t\ttransaction.onabort = () => e(transaction.error ? ErrorNoTelemetry.fromError(transaction.error) : new ErrorNoTelemetry('unknown error'));\n\t\t\tconst request = dbRequestFn(transaction.objectStore(store));\n\t\t}).finally(() => this.pendingTransactions.splice(this.pendingTransactions.indexOf(transaction), 1));\n\t}\n\n\tasync getKeyValues(store: string, isValid: (value: unknown) => value is V): Promise> {\n\t\tif (!this.database) {\n\t\t\tthrow new DBClosedError(this.name);\n\t\t}\n\t\tconst transaction = this.database.transaction(store, 'readonly');\n\t\tthis.pendingTransactions.push(transaction);\n\t\treturn new Promise>(resolve => {\n\t\t\tconst items = new Map();\n\n\t\t\tconst objectStore = transaction.objectStore(store);\n\n\t\t\t// Open a IndexedDB Cursor to iterate over key/values\n\t\t\tconst cursor = objectStore.openCursor();\n\t\t\tif (!cursor) {\n\t\t\t\treturn resolve(items); // this means the `ItemTable` was empty\n\t\t\t}\n\n\t\t\t// Iterate over rows of `ItemTable` until the end\n\t\t\tcursor.onsuccess = () => {\n\t\t\t\tif (cursor.result) {\n\n\t\t\t\t\t// Keep cursor key/value in our map\n\t\t\t\t\tif (isValid(cursor.result.value)) {\n\t\t\t\t\t\titems.set(cursor.result.key.toString(), cursor.result.value);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Advance cursor to next row\n\t\t\t\t\tcursor.result.continue();\n\t\t\t\t} else {\n\t\t\t\t\tresolve(items); // reached end of table\n\t\t\t\t}\n\t\t\t};\n\n\t\t\t// Error handlers\n\t\t\tconst onError = (error: Error | null) => {\n\t\t\t\tconsole.error(`IndexedDB getKeyValues(): ${toErrorMessage(error, true)}`);\n\n\t\t\t\tresolve(items);\n\t\t\t};\n\t\t\tcursor.onerror = () => onError(cursor.error);\n\t\t\ttransaction.onerror = () => onError(transaction.error);\n\t\t}).finally(() => this.pendingTransactions.splice(this.pendingTransactions.indexOf(transaction), 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/**\n * Extracted from json.ts to keep json nls free.\n */\nimport { localize } from 'vs/nls';\nimport { ParseErrorCode } from './json';\n\nexport function getParseErrorMessage(errorCode: ParseErrorCode): string {\n\tswitch (errorCode) {\n\t\tcase ParseErrorCode.InvalidSymbol: return localize('error.invalidSymbol', 'Invalid symbol');\n\t\tcase ParseErrorCode.InvalidNumberFormat: return localize('error.invalidNumberFormat', 'Invalid number format');\n\t\tcase ParseErrorCode.PropertyNameExpected: return localize('error.propertyNameExpected', 'Property name expected');\n\t\tcase ParseErrorCode.ValueExpected: return localize('error.valueExpected', 'Value expected');\n\t\tcase ParseErrorCode.ColonExpected: return localize('error.colonExpected', 'Colon expected');\n\t\tcase ParseErrorCode.CommaExpected: return localize('error.commaExpected', 'Comma expected');\n\t\tcase ParseErrorCode.CloseBraceExpected: return localize('error.closeBraceExpected', 'Closing brace expected');\n\t\tcase ParseErrorCode.CloseBracketExpected: return localize('error.closeBracketExpected', 'Closing bracket expected');\n\t\tcase ParseErrorCode.EndOfFileExpected: return localize('error.endOfFileExpected', 'End of file expected');\n\t\tdefault:\n\t\t\treturn '';\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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\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') {\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}\nexport type PlatformName = 'Web' | 'Windows' | 'Mac' | 'Linux';\n\nexport function PlatformToString(platform: Platform): PlatformName {\n\tswitch (platform) {\n\t\tcase Platform.Web: return 'Web';\n\t\tcase Platform.Mac: return 'Mac';\n\t\tcase Platform.Linux: return 'Linux';\n\t\tcase Platform.Windows: return 'Windows';\n\t}\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 isLinuxSnap = _isLinuxSnap;\nexport const isNative = _isNative;\nexport const isElectron = _isElectron;\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;\n/**\n * Whether we run inside a CI environment, such as\n * GH actions or Azure Pipelines.\n */\nexport const isCI = _isCI;\nexport const platform = _platform;\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 namespace Language {\n\n\texport function value(): string {\n\t\treturn language;\n\t}\n\n\texport function isDefaultVariant(): boolean {\n\t\tif (language.length === 2) {\n\t\t\treturn language === 'en';\n\t\t} else if (language.length >= 3) {\n\t\t\treturn language[0] === 'e' && language[1] === 'n' && language[2] === '-';\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\texport function isDefault(): boolean {\n\t\treturn language === 'en';\n\t}\n}\n\n/**\n * The OS locale or the locale specified by --locale. The format of\n * the string is all lower case (e.g. zh-tw for Traditional\n * Chinese). The UI is not necessarily shown in the provided locale.\n */\nexport const locale = _locale;\n\n/**\n * This will always be set to the OS/browser's locale regardless of\n * what was specified by --locale. The format of the string is all\n * lower case (e.g. zh-tw for Traditional Chinese). The UI is not\n * necessarily shown in the provided locale.\n */\nexport const platformLocale = _platformLocale;\n\n/**\n * The translations that are available through language packs.\n */\nexport const translationsConfigFile = _translationsConfigFile;\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\nexport function isBigSurOrNewer(osVersion: string): boolean {\n\treturn parseFloat(osVersion) >= 20;\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 * 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 function printKeyboardEvent(e: KeyboardEvent): string {\n\tconst modifiers: string[] = [];\n\tif (e.ctrlKey) {\n\t\tmodifiers.push(`ctrl`);\n\t}\n\tif (e.shiftKey) {\n\t\tmodifiers.push(`shift`);\n\t}\n\tif (e.altKey) {\n\t\tmodifiers.push(`alt`);\n\t}\n\tif (e.metaKey) {\n\t\tmodifiers.push(`meta`);\n\t}\n\treturn `modifiers: [${modifiers.join(',')}], code: ${e.code}, keyCode: ${e.keyCode}, key: ${e.key}`;\n}\n\nexport function printStandardKeyboardEvent(e: StandardKeyboardEvent): string {\n\tconst modifiers: string[] = [];\n\tif (e.ctrlKey) {\n\t\tmodifiers.push(`ctrl`);\n\t}\n\tif (e.shiftKey) {\n\t\tmodifiers.push(`shift`);\n\t}\n\tif (e.altKey) {\n\t\tmodifiers.push(`alt`);\n\t}\n\tif (e.metaKey) {\n\t\tmodifiers.push(`meta`);\n\t}\n\treturn `modifiers: [${modifiers.join(',')}], code: ${e.code}, keyCode: ${e.keyCode} ('${KeyCodeUtils.toString(e.keyCode)}')`;\n}\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 class DragMouseEvent extends StandardMouseEvent {\n\n\tpublic readonly dataTransfer: DataTransfer;\n\n\tconstructor(targetWindow: Window, e: MouseEvent) {\n\t\tsuper(targetWindow, e);\n\t\tthis.dataTransfer = (e).dataTransfer;\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 { 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/**\n * Provides safe access to the `arch` method in node.js, sandboxed or web\n * environments.\n * Note: `arch` is `undefined` in web\n */\nexport const arch = safeProcess.arch;\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 isAbsolute = (platformIsWin32 ? win32.isAbsolute : posix.isAbsolute);\nexport const join = (platformIsWin32 ? win32.join : posix.join);\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 format = (platformIsWin32 ? win32.format : posix.format);\nexport const parse = (platformIsWin32 ? win32.parse : posix.parse);\nexport const toNamespacedPath = (platformIsWin32 ? win32.toNamespacedPath : posix.toNamespacedPath);\nexport const sep = (platformIsWin32 ? win32.sep : posix.sep);\nexport const delimiter = (platformIsWin32 ? win32.delimiter : posix.delimiter);\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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';\nimport { sep } from 'vs/base/common/path';\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\n/** Compares full filenames without grouping by case. */\nexport function compareFileNamesDefault(one: string | null, other: string | null): number {\n\tconst collatorNumeric = intlFileNameCollatorNumeric.value.collator;\n\tone = one || '';\n\tother = other || '';\n\n\treturn compareAndDisambiguateByLength(collatorNumeric, one, other);\n}\n\n/** Compares full filenames grouping uppercase names before lowercase. */\nexport function compareFileNamesUpper(one: string | null, other: string | null) {\n\tconst collatorNumeric = intlFileNameCollatorNumeric.value.collator;\n\tone = one || '';\n\tother = other || '';\n\n\treturn compareCaseUpperFirst(one, other) || compareAndDisambiguateByLength(collatorNumeric, one, other);\n}\n\n/** Compares full filenames grouping lowercase names before uppercase. */\nexport function compareFileNamesLower(one: string | null, other: string | null) {\n\tconst collatorNumeric = intlFileNameCollatorNumeric.value.collator;\n\tone = one || '';\n\tother = other || '';\n\n\treturn compareCaseLowerFirst(one, other) || compareAndDisambiguateByLength(collatorNumeric, one, other);\n}\n\n/** Compares full filenames by unicode value. */\nexport function compareFileNamesUnicode(one: string | null, other: string | null) {\n\tone = one || '';\n\tother = other || '';\n\n\tif (one === other) {\n\t\treturn 0;\n\t}\n\n\treturn one < other ? -1 : 1;\n}\n\n/** Compares filenames by extension, then by name. Disambiguates by unicode comparison. */\nexport function compareFileExtensions(one: string | null, other: string | null): number {\n\tconst [oneName, oneExtension] = extractNameAndExtension(one);\n\tconst [otherName, otherExtension] = extractNameAndExtension(other);\n\n\tlet result = intlFileNameCollatorBaseNumeric.value.collator.compare(oneExtension, otherExtension);\n\n\tif (result === 0) {\n\t\t// Using the numeric option will make compare(`foo1`, `foo01`) === 0. Disambiguate.\n\t\tif (intlFileNameCollatorBaseNumeric.value.collatorIsNumeric && oneExtension !== otherExtension) {\n\t\t\treturn oneExtension < otherExtension ? -1 : 1;\n\t\t}\n\n\t\t// Extensions are equal, compare filenames\n\t\tresult = intlFileNameCollatorBaseNumeric.value.collator.compare(oneName, otherName);\n\n\t\tif (intlFileNameCollatorBaseNumeric.value.collatorIsNumeric && result === 0 && oneName !== otherName) {\n\t\t\treturn oneName < otherName ? -1 : 1;\n\t\t}\n\t}\n\n\treturn result;\n}\n\n/** Compares filenames by extension, then by full filename. Mixes uppercase and lowercase names together. */\nexport function compareFileExtensionsDefault(one: string | null, other: string | null): number {\n\tone = one || '';\n\tother = other || '';\n\tconst oneExtension = extractExtension(one);\n\tconst otherExtension = extractExtension(other);\n\tconst collatorNumeric = intlFileNameCollatorNumeric.value.collator;\n\tconst collatorNumericCaseInsensitive = intlFileNameCollatorNumericCaseInsensitive.value.collator;\n\n\treturn compareAndDisambiguateByLength(collatorNumericCaseInsensitive, oneExtension, otherExtension) ||\n\t\tcompareAndDisambiguateByLength(collatorNumeric, one, other);\n}\n\n/** Compares filenames by extension, then case, then full filename. Groups uppercase names before lowercase. */\nexport function compareFileExtensionsUpper(one: string | null, other: string | null): number {\n\tone = one || '';\n\tother = other || '';\n\tconst oneExtension = extractExtension(one);\n\tconst otherExtension = extractExtension(other);\n\tconst collatorNumeric = intlFileNameCollatorNumeric.value.collator;\n\tconst collatorNumericCaseInsensitive = intlFileNameCollatorNumericCaseInsensitive.value.collator;\n\n\treturn compareAndDisambiguateByLength(collatorNumericCaseInsensitive, oneExtension, otherExtension) ||\n\t\tcompareCaseUpperFirst(one, other) ||\n\t\tcompareAndDisambiguateByLength(collatorNumeric, one, other);\n}\n\n/** Compares filenames by extension, then case, then full filename. Groups lowercase names before uppercase. */\nexport function compareFileExtensionsLower(one: string | null, other: string | null): number {\n\tone = one || '';\n\tother = other || '';\n\tconst oneExtension = extractExtension(one);\n\tconst otherExtension = extractExtension(other);\n\tconst collatorNumeric = intlFileNameCollatorNumeric.value.collator;\n\tconst collatorNumericCaseInsensitive = intlFileNameCollatorNumericCaseInsensitive.value.collator;\n\n\treturn compareAndDisambiguateByLength(collatorNumericCaseInsensitive, oneExtension, otherExtension) ||\n\t\tcompareCaseLowerFirst(one, other) ||\n\t\tcompareAndDisambiguateByLength(collatorNumeric, one, other);\n}\n\n/** Compares filenames by case-insensitive extension unicode value, then by full filename unicode value. */\nexport function compareFileExtensionsUnicode(one: string | null, other: string | null) {\n\tone = one || '';\n\tother = other || '';\n\tconst oneExtension = extractExtension(one).toLowerCase();\n\tconst otherExtension = extractExtension(other).toLowerCase();\n\n\t// Check for extension differences\n\tif (oneExtension !== otherExtension) {\n\t\treturn oneExtension < otherExtension ? -1 : 1;\n\t}\n\n\t// Check for full filename differences.\n\tif (one !== other) {\n\t\treturn one < other ? -1 : 1;\n\t}\n\n\treturn 0;\n}\n\nconst FileNameMatch = /^(.*?)(\\.([^.]*))?$/;\n\n/** Extracts the name and extension from a full filename, with optional special handling for dotfiles */\nfunction extractNameAndExtension(str?: string | null, dotfilesAsNames = false): [string, string] {\n\tconst match = str ? FileNameMatch.exec(str) as Array : ([] as Array);\n\n\tlet result: [string, string] = [(match && match[1]) || '', (match && match[3]) || ''];\n\n\t// if the dotfilesAsNames option is selected, treat an empty filename with an extension\n\t// or a filename that starts with a dot, as a dotfile name\n\tif (dotfilesAsNames && (!result[0] && result[1] || result[0] && result[0].charAt(0) === '.')) {\n\t\tresult = [result[0] + '.' + result[1], ''];\n\t}\n\n\treturn result;\n}\n\n/** Extracts the extension from a full filename. Treats dotfiles as names, not extensions. */\nfunction extractExtension(str?: string | null): string {\n\tconst match = str ? FileNameMatch.exec(str) as Array : ([] as Array);\n\n\treturn (match && match[1] && match[1].charAt(0) !== '.' && match[3]) || '';\n}\n\nfunction compareAndDisambiguateByLength(collator: Intl.Collator, one: string, other: string) {\n\t// Check for differences\n\tconst result = collator.compare(one, other);\n\tif (result !== 0) {\n\t\treturn result;\n\t}\n\n\t// In a numeric comparison, `foo1` and `foo01` will compare as equivalent.\n\t// Disambiguate by sorting the shorter string first.\n\tif (one.length !== other.length) {\n\t\treturn one.length < other.length ? -1 : 1;\n\t}\n\n\treturn 0;\n}\n\n/** @returns `true` if the string is starts with a lowercase letter. Otherwise, `false`. */\nfunction startsWithLower(string: string) {\n\tconst character = string.charAt(0);\n\n\treturn (character.toLocaleUpperCase() !== character) ? true : false;\n}\n\n/** @returns `true` if the string starts with an uppercase letter. Otherwise, `false`. */\nfunction startsWithUpper(string: string) {\n\tconst character = string.charAt(0);\n\n\treturn (character.toLocaleLowerCase() !== character) ? true : false;\n}\n\n/**\n * Compares the case of the provided strings - lowercase before uppercase\n *\n * @returns\n * ```text\n * -1 if one is lowercase and other is uppercase\n * 1 if one is uppercase and other is lowercase\n * 0 otherwise\n * ```\n */\nfunction compareCaseLowerFirst(one: string, other: string): number {\n\tif (startsWithLower(one) && startsWithUpper(other)) {\n\t\treturn -1;\n\t}\n\treturn (startsWithUpper(one) && startsWithLower(other)) ? 1 : 0;\n}\n\n/**\n * Compares the case of the provided strings - uppercase before lowercase\n *\n * @returns\n * ```text\n * -1 if one is uppercase and other is lowercase\n * 1 if one is lowercase and other is uppercase\n * 0 otherwise\n * ```\n */\nfunction compareCaseUpperFirst(one: string, other: string): number {\n\tif (startsWithUpper(one) && startsWithLower(other)) {\n\t\treturn -1;\n\t}\n\treturn (startsWithLower(one) && startsWithUpper(other)) ? 1 : 0;\n}\n\nfunction comparePathComponents(one: string, other: string, caseSensitive = false): number {\n\tif (!caseSensitive) {\n\t\tone = one && one.toLowerCase();\n\t\tother = other && other.toLowerCase();\n\t}\n\n\tif (one === other) {\n\t\treturn 0;\n\t}\n\n\treturn one < other ? -1 : 1;\n}\n\nexport function comparePaths(one: string, other: string, caseSensitive = false): number {\n\tconst oneParts = one.split(sep);\n\tconst otherParts = other.split(sep);\n\n\tconst lastOne = oneParts.length - 1;\n\tconst lastOther = otherParts.length - 1;\n\tlet endOne: boolean, endOther: boolean;\n\n\tfor (let i = 0; ; i++) {\n\t\tendOne = lastOne === i;\n\t\tendOther = lastOther === i;\n\n\t\tif (endOne && endOther) {\n\t\t\treturn compareFileNames(oneParts[i], otherParts[i], caseSensitive);\n\t\t} else if (endOne) {\n\t\t\treturn -1;\n\t\t} else if (endOther) {\n\t\t\treturn 1;\n\t\t}\n\n\t\tconst result = comparePathComponents(oneParts[i], otherParts[i], caseSensitive);\n\n\t\tif (result !== 0) {\n\t\t\treturn result;\n\t\t}\n\t}\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","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { isAbsolute, join, normalize, posix, sep } from 'vs/base/common/path';\nimport { isWindows } from 'vs/base/common/platform';\nimport { equalsIgnoreCase, rtrim, startsWithIgnoreCase } from 'vs/base/common/strings';\nimport { isNumber } from 'vs/base/common/types';\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 * Check if the path follows this pattern: `\\\\hostname\\sharename`.\n *\n * @see https://msdn.microsoft.com/en-us/library/gg465305.aspx\n * @return A boolean indication if the path is a UNC path, on none-windows\n * always false.\n */\nexport function isUNC(path: string): boolean {\n\tif (!isWindows) {\n\t\t// UNC is a windows concept\n\t\treturn false;\n\t}\n\n\tif (!path || path.length < 5) {\n\t\t// at least \\\\a\\b\n\t\treturn false;\n\t}\n\n\tlet code = path.charCodeAt(0);\n\tif (code !== CharCode.Backslash) {\n\t\treturn false;\n\t}\n\n\tcode = path.charCodeAt(1);\n\n\tif (code !== CharCode.Backslash) {\n\t\treturn false;\n\t}\n\n\tlet pos = 2;\n\tconst start = pos;\n\tfor (; pos < path.length; pos++) {\n\t\tcode = path.charCodeAt(pos);\n\t\tif (code === CharCode.Backslash) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (start === pos) {\n\t\treturn false;\n\t}\n\n\tcode = path.charCodeAt(pos + 1);\n\n\tif (isNaN(code) || code === CharCode.Backslash) {\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\n// Reference: https://en.wikipedia.org/wiki/Filename\nconst WINDOWS_INVALID_FILE_CHARS = /[\\\\/:\\*\\?\"<>\\|]/g;\nconst UNIX_INVALID_FILE_CHARS = /[\\\\/]/g;\nconst WINDOWS_FORBIDDEN_NAMES = /^(con|prn|aux|clock\\$|nul|lpt[0-9]|com[0-9])(\\.(.*?))?$/i;\nexport function isValidBasename(name: string | null | undefined, isWindowsOS: boolean = isWindows): boolean {\n\tconst invalidFileChars = isWindowsOS ? WINDOWS_INVALID_FILE_CHARS : UNIX_INVALID_FILE_CHARS;\n\n\tif (!name || name.length === 0 || /^\\s+$/.test(name)) {\n\t\treturn false; // require a name that is not just whitespace\n\t}\n\n\tinvalidFileChars.lastIndex = 0; // the holy grail of software development\n\tif (invalidFileChars.test(name)) {\n\t\treturn false; // check for certain invalid file characters\n\t}\n\n\tif (isWindowsOS && WINDOWS_FORBIDDEN_NAMES.test(name)) {\n\t\treturn false; // check for certain invalid file names\n\t}\n\n\tif (name === '.' || name === '..') {\n\t\treturn false; // check for reserved values\n\t}\n\n\tif (isWindowsOS && name[name.length - 1] === '.') {\n\t\treturn false; // Windows: file cannot end with a \".\"\n\t}\n\n\tif (isWindowsOS && name.length !== name.trim().length) {\n\t\treturn false; // Windows: file cannot end with a whitespace\n\t}\n\n\tif (name.length > 255) {\n\t\treturn false; // most file systems do not allow files > 255 length\n\t}\n\n\treturn true;\n}\n\n/**\n * @deprecated please use `IUriIdentityService.extUri.isEqual` instead. If you are\n * in a context without services, consider to pass down the `extUri` from the outside\n * or use `extUriBiasedIgnorePathCase` if you know what you are doing.\n */\nexport function isEqual(pathA: string, pathB: string, ignoreCase?: boolean): boolean {\n\tconst identityEquals = (pathA === pathB);\n\tif (!ignoreCase || identityEquals) {\n\t\treturn identityEquals;\n\t}\n\n\tif (!pathA || !pathB) {\n\t\treturn false;\n\t}\n\n\treturn equalsIgnoreCase(pathA, pathB);\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 sanitizeFilePath(candidate: string, cwd: string): string {\n\n\t// Special case: allow to open a drive letter without trailing backslash\n\tif (isWindows && candidate.endsWith(':')) {\n\t\tcandidate += sep;\n\t}\n\n\t// Ensure absolute\n\tif (!isAbsolute(candidate)) {\n\t\tcandidate = join(cwd, candidate);\n\t}\n\n\t// Ensure normalized\n\tcandidate = normalize(candidate);\n\n\t// Ensure no trailing slash/backslash\n\tif (isWindows) {\n\t\tcandidate = rtrim(candidate, sep);\n\n\t\t// Special case: allow to open drive root ('C:\\')\n\t\tif (candidate.endsWith(':')) {\n\t\t\tcandidate += sep;\n\t\t}\n\n\t} else {\n\t\tcandidate = rtrim(candidate, sep);\n\n\t\t// Special case: allow to open root ('/')\n\t\tif (!candidate) {\n\t\t\tcandidate = sep;\n\t\t}\n\t}\n\n\treturn candidate;\n}\n\nexport function isRootOrDriveLetter(path: string): boolean {\n\tconst pathNormalized = normalize(path);\n\n\tif (isWindows) {\n\t\tif (path.length > 3) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn hasDriveLetter(pathNormalized) &&\n\t\t\t(path.length === 2 || pathNormalized.charCodeAt(2) === CharCode.Backslash);\n\t}\n\n\treturn pathNormalized === posix.sep;\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\nexport function getDriveLetter(path: string, isWindowsOS: boolean = isWindows): string | undefined {\n\treturn hasDriveLetter(path, isWindowsOS) ? path[0] : undefined;\n}\n\nexport function indexOfPath(path: string, candidate: string, ignoreCase?: boolean): number {\n\tif (candidate.length > path.length) {\n\t\treturn -1;\n\t}\n\n\tif (path === candidate) {\n\t\treturn 0;\n\t}\n\n\tif (ignoreCase) {\n\t\tpath = path.toLowerCase();\n\t\tcandidate = candidate.toLowerCase();\n\t}\n\n\treturn path.indexOf(candidate);\n}\n\nexport interface IPathWithLineAndColumn {\n\tpath: string;\n\tline?: number;\n\tcolumn?: number;\n}\n\nexport function parseLineAndColumnAware(rawPath: string): IPathWithLineAndColumn {\n\tconst segments = rawPath.split(':'); // C:\\file.txt::\n\n\tlet path: string | undefined = undefined;\n\tlet line: number | undefined = undefined;\n\tlet column: number | undefined = undefined;\n\n\tfor (const segment of segments) {\n\t\tconst segmentAsNumber = Number(segment);\n\t\tif (!isNumber(segmentAsNumber)) {\n\t\t\tpath = !!path ? [path, segment].join(':') : segment; // a colon can well be part of a path (e.g. C:\\...)\n\t\t} else if (line === undefined) {\n\t\t\tline = segmentAsNumber;\n\t\t} else if (column === undefined) {\n\t\t\tcolumn = segmentAsNumber;\n\t\t}\n\t}\n\n\tif (!path) {\n\t\tthrow new Error('Format for `--goto` should be: `FILE:LINE(:COLUMN)`');\n\t}\n\n\treturn {\n\t\tpath,\n\t\tline: line !== undefined ? line : undefined,\n\t\tcolumn: column !== undefined ? column : line !== undefined ? 1 : undefined // if we have a line, make sure column is also set\n\t};\n}\n\nconst pathChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';\nconst windowsSafePathFirstChars = 'BDEFGHIJKMOQRSTUVWXYZbdefghijkmoqrstuvwxyz0123456789';\n\nexport function randomPath(parent?: string, prefix?: string, randomLength = 8): string {\n\tlet suffix = '';\n\tfor (let i = 0; i < randomLength; i++) {\n\t\tlet pathCharsTouse: string;\n\t\tif (i === 0 && isWindows && !prefix && (randomLength === 3 || randomLength === 4)) {\n\n\t\t\t// Windows has certain reserved file names that cannot be used, such\n\t\t\t// as AUX, CON, PRN, etc. We want to avoid generating a random name\n\t\t\t// that matches that pattern, so we use a different set of characters\n\t\t\t// for the first character of the name that does not include any of\n\t\t\t// the reserved names first characters.\n\n\t\t\tpathCharsTouse = windowsSafePathFirstChars;\n\t\t} else {\n\t\t\tpathCharsTouse = pathChars;\n\t\t}\n\n\t\tsuffix += pathCharsTouse.charAt(Math.floor(Math.random() * pathCharsTouse.length));\n\t}\n\n\tlet randomFileName: string;\n\tif (prefix) {\n\t\trandomFileName = `${prefix}-${suffix}`;\n\t} else {\n\t\trandomFileName = suffix;\n\t}\n\n\tif (parent) {\n\t\treturn join(parent, randomFileName);\n\t}\n\n\treturn randomFileName;\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { compareAnything } from 'vs/base/common/comparers';\nimport { createMatches as createFuzzyMatches, fuzzyScore, IMatch, isUpper, matchesPrefix } from 'vs/base/common/filters';\nimport { hash } from 'vs/base/common/hash';\nimport { sep } from 'vs/base/common/path';\nimport { isLinux, isWindows } from 'vs/base/common/platform';\nimport { equalsIgnoreCase, stripWildcards } from 'vs/base/common/strings';\n\n//#region Fuzzy scorer\n\nexport type FuzzyScore = [number /* score */, number[] /* match positions */];\nexport type FuzzyScorerCache = { [key: string]: IItemScore };\n\nconst NO_MATCH = 0;\nconst NO_SCORE: FuzzyScore = [NO_MATCH, []];\n\n// const DEBUG = true;\n// const DEBUG_MATRIX = false;\n\nexport function scoreFuzzy(target: string, query: string, queryLower: string, allowNonContiguousMatches: boolean): FuzzyScore {\n\tif (!target || !query) {\n\t\treturn NO_SCORE; // return early if target or query are undefined\n\t}\n\n\tconst targetLength = target.length;\n\tconst queryLength = query.length;\n\n\tif (targetLength < queryLength) {\n\t\treturn NO_SCORE; // impossible for query to be contained in target\n\t}\n\n\t// if (DEBUG) {\n\t// \tconsole.group(`Target: ${target}, Query: ${query}`);\n\t// }\n\n\tconst targetLower = target.toLowerCase();\n\tconst res = doScoreFuzzy(query, queryLower, queryLength, target, targetLower, targetLength, allowNonContiguousMatches);\n\n\t// if (DEBUG) {\n\t// \tconsole.log(`%cFinal Score: ${res[0]}`, 'font-weight: bold');\n\t// \tconsole.groupEnd();\n\t// }\n\n\treturn res;\n}\n\nfunction doScoreFuzzy(query: string, queryLower: string, queryLength: number, target: string, targetLower: string, targetLength: number, allowNonContiguousMatches: boolean): FuzzyScore {\n\tconst scores: number[] = [];\n\tconst matches: number[] = [];\n\n\t//\n\t// Build Scorer Matrix:\n\t//\n\t// The matrix is composed of query q and target t. For each index we score\n\t// q[i] with t[i] and compare that with the previous score. If the score is\n\t// equal or larger, we keep the match. In addition to the score, we also keep\n\t// the length of the consecutive matches to use as boost for the score.\n\t//\n\t// t a r g e t\n\t// q\n\t// u\n\t// e\n\t// r\n\t// y\n\t//\n\tfor (let queryIndex = 0; queryIndex < queryLength; queryIndex++) {\n\t\tconst queryIndexOffset = queryIndex * targetLength;\n\t\tconst queryIndexPreviousOffset = queryIndexOffset - targetLength;\n\n\t\tconst queryIndexGtNull = queryIndex > 0;\n\n\t\tconst queryCharAtIndex = query[queryIndex];\n\t\tconst queryLowerCharAtIndex = queryLower[queryIndex];\n\n\t\tfor (let targetIndex = 0; targetIndex < targetLength; targetIndex++) {\n\t\t\tconst targetIndexGtNull = targetIndex > 0;\n\n\t\t\tconst currentIndex = queryIndexOffset + targetIndex;\n\t\t\tconst leftIndex = currentIndex - 1;\n\t\t\tconst diagIndex = queryIndexPreviousOffset + targetIndex - 1;\n\n\t\t\tconst leftScore = targetIndexGtNull ? scores[leftIndex] : 0;\n\t\t\tconst diagScore = queryIndexGtNull && targetIndexGtNull ? scores[diagIndex] : 0;\n\n\t\t\tconst matchesSequenceLength = queryIndexGtNull && targetIndexGtNull ? matches[diagIndex] : 0;\n\n\t\t\t// If we are not matching on the first query character any more, we only produce a\n\t\t\t// score if we had a score previously for the last query index (by looking at the diagScore).\n\t\t\t// This makes sure that the query always matches in sequence on the target. For example\n\t\t\t// given a target of \"ede\" and a query of \"de\", we would otherwise produce a wrong high score\n\t\t\t// for query[1] (\"e\") matching on target[0] (\"e\") because of the \"beginning of word\" boost.\n\t\t\tlet score: number;\n\t\t\tif (!diagScore && queryIndexGtNull) {\n\t\t\t\tscore = 0;\n\t\t\t} else {\n\t\t\t\tscore = computeCharScore(queryCharAtIndex, queryLowerCharAtIndex, target, targetLower, targetIndex, matchesSequenceLength);\n\t\t\t}\n\n\t\t\t// We have a score and its equal or larger than the left score\n\t\t\t// Match: sequence continues growing from previous diag value\n\t\t\t// Score: increases by diag score value\n\t\t\tconst isValidScore = score && diagScore + score >= leftScore;\n\t\t\tif (isValidScore && (\n\t\t\t\t// We don't need to check if it's contiguous if we allow non-contiguous matches\n\t\t\t\tallowNonContiguousMatches ||\n\t\t\t\t// We must be looking for a contiguous match.\n\t\t\t\t// Looking at an index higher than 0 in the query means we must have already\n\t\t\t\t// found out this is contiguous otherwise there wouldn't have been a score\n\t\t\t\tqueryIndexGtNull ||\n\t\t\t\t// lastly check if the query is completely contiguous at this index in the target\n\t\t\t\ttargetLower.startsWith(queryLower, targetIndex)\n\t\t\t)) {\n\t\t\t\tmatches[currentIndex] = matchesSequenceLength + 1;\n\t\t\t\tscores[currentIndex] = diagScore + score;\n\t\t\t}\n\n\t\t\t// We either have no score or the score is lower than the left score\n\t\t\t// Match: reset to 0\n\t\t\t// Score: pick up from left hand side\n\t\t\telse {\n\t\t\t\tmatches[currentIndex] = NO_MATCH;\n\t\t\t\tscores[currentIndex] = leftScore;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Restore Positions (starting from bottom right of matrix)\n\tconst positions: number[] = [];\n\tlet queryIndex = queryLength - 1;\n\tlet targetIndex = targetLength - 1;\n\twhile (queryIndex >= 0 && targetIndex >= 0) {\n\t\tconst currentIndex = queryIndex * targetLength + targetIndex;\n\t\tconst match = matches[currentIndex];\n\t\tif (match === NO_MATCH) {\n\t\t\ttargetIndex--; // go left\n\t\t} else {\n\t\t\tpositions.push(targetIndex);\n\n\t\t\t// go up and left\n\t\t\tqueryIndex--;\n\t\t\ttargetIndex--;\n\t\t}\n\t}\n\n\t// Print matrix\n\t// if (DEBUG_MATRIX) {\n\t// \tprintMatrix(query, target, matches, scores);\n\t// }\n\n\treturn [scores[queryLength * targetLength - 1], positions.reverse()];\n}\n\nfunction computeCharScore(queryCharAtIndex: string, queryLowerCharAtIndex: string, target: string, targetLower: string, targetIndex: number, matchesSequenceLength: number): number {\n\tlet score = 0;\n\n\tif (!considerAsEqual(queryLowerCharAtIndex, targetLower[targetIndex])) {\n\t\treturn score; // no match of characters\n\t}\n\n\t// if (DEBUG) {\n\t// \tconsole.groupCollapsed(`%cFound a match of char: ${queryLowerCharAtIndex} at index ${targetIndex}`, 'font-weight: normal');\n\t// }\n\n\t// Character match bonus\n\tscore += 1;\n\n\t// if (DEBUG) {\n\t// \tconsole.log(`%cCharacter match bonus: +1`, 'font-weight: normal');\n\t// }\n\n\t// Consecutive match bonus\n\tif (matchesSequenceLength > 0) {\n\t\tscore += (matchesSequenceLength * 5);\n\n\t\t// if (DEBUG) {\n\t\t// \tconsole.log(`Consecutive match bonus: +${matchesSequenceLength * 5}`);\n\t\t// }\n\t}\n\n\t// Same case bonus\n\tif (queryCharAtIndex === target[targetIndex]) {\n\t\tscore += 1;\n\n\t\t// if (DEBUG) {\n\t\t// \tconsole.log('Same case bonus: +1');\n\t\t// }\n\t}\n\n\t// Start of word bonus\n\tif (targetIndex === 0) {\n\t\tscore += 8;\n\n\t\t// if (DEBUG) {\n\t\t// \tconsole.log('Start of word bonus: +8');\n\t\t// }\n\t}\n\n\telse {\n\n\t\t// After separator bonus\n\t\tconst separatorBonus = scoreSeparatorAtPos(target.charCodeAt(targetIndex - 1));\n\t\tif (separatorBonus) {\n\t\t\tscore += separatorBonus;\n\n\t\t\t// if (DEBUG) {\n\t\t\t// \tconsole.log(`After separator bonus: +${separatorBonus}`);\n\t\t\t// }\n\t\t}\n\n\t\t// Inside word upper case bonus (camel case). We only give this bonus if we're not in a contiguous sequence.\n\t\t// For example:\n\t\t// NPE => NullPointerException = boost\n\t\t// HTTP => HTTP = not boost\n\t\telse if (isUpper(target.charCodeAt(targetIndex)) && matchesSequenceLength === 0) {\n\t\t\tscore += 2;\n\n\t\t\t// if (DEBUG) {\n\t\t\t// \tconsole.log('Inside word upper case bonus: +2');\n\t\t\t// }\n\t\t}\n\t}\n\n\t// if (DEBUG) {\n\t// \tconsole.log(`Total score: ${score}`);\n\t// \tconsole.groupEnd();\n\t// }\n\n\treturn score;\n}\n\nfunction considerAsEqual(a: string, b: string): boolean {\n\tif (a === b) {\n\t\treturn true;\n\t}\n\n\t// Special case path separators: ignore platform differences\n\tif (a === '/' || a === '\\\\') {\n\t\treturn b === '/' || b === '\\\\';\n\t}\n\n\treturn false;\n}\n\nfunction scoreSeparatorAtPos(charCode: number): number {\n\tswitch (charCode) {\n\t\tcase CharCode.Slash:\n\t\tcase CharCode.Backslash:\n\t\t\treturn 5; // prefer path separators...\n\t\tcase CharCode.Underline:\n\t\tcase CharCode.Dash:\n\t\tcase CharCode.Period:\n\t\tcase CharCode.Space:\n\t\tcase CharCode.SingleQuote:\n\t\tcase CharCode.DoubleQuote:\n\t\tcase CharCode.Colon:\n\t\t\treturn 4; // ...over other separators\n\t\tdefault:\n\t\t\treturn 0;\n\t}\n}\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\t/**\n\t * Matches within the label.\n\t */\n\tlabelMatch?: IMatch[];\n\n\t/**\n\t * Matches within the description.\n\t */\n\tdescriptionMatch?: IMatch[];\n}\n\nconst NO_ITEM_SCORE = Object.freeze({ score: 0 });\n\nexport interface IItemAccessor {\n\n\t/**\n\t * Just the label of the item to score on.\n\t */\n\tgetItemLabel(item: T): string | undefined;\n\n\t/**\n\t * The optional description of the item to score on.\n\t */\n\tgetItemDescription(item: T): string | undefined;\n\n\t/**\n\t * If the item is a file, the path of the file to score on.\n\t */\n\tgetItemPath(file: T): string | undefined;\n}\n\nconst PATH_IDENTITY_SCORE = 1 << 18;\nconst LABEL_PREFIX_SCORE_THRESHOLD = 1 << 17;\nconst LABEL_SCORE_THRESHOLD = 1 << 16;\n\nfunction getCacheHash(label: string, description: string | undefined, allowNonContiguousMatches: boolean, query: IPreparedQuery) {\n\tconst values = query.values ? query.values : [query];\n\tconst cacheHash = hash({\n\t\t[query.normalized]: {\n\t\t\tvalues: values.map(v => ({ value: v.normalized, expectContiguousMatch: v.expectContiguousMatch })),\n\t\t\tlabel,\n\t\t\tdescription,\n\t\t\tallowNonContiguousMatches\n\t\t}\n\t});\n\treturn cacheHash;\n}\n\nexport function scoreItemFuzzy(item: T, query: IPreparedQuery, allowNonContiguousMatches: boolean, accessor: IItemAccessor, cache: FuzzyScorerCache): IItemScore {\n\tif (!item || !query.normalized) {\n\t\treturn NO_ITEM_SCORE; // we need an item and query to score on at least\n\t}\n\n\tconst label = accessor.getItemLabel(item);\n\tif (!label) {\n\t\treturn NO_ITEM_SCORE; // we need a label at least\n\t}\n\n\tconst description = accessor.getItemDescription(item);\n\n\t// in order to speed up scoring, we cache the score with a unique hash based on:\n\t// - label\n\t// - description (if provided)\n\t// - whether non-contiguous matching is enabled or not\n\t// - hash of the query (normalized) values\n\tconst cacheHash = getCacheHash(label, description, allowNonContiguousMatches, query);\n\tconst cached = cache[cacheHash];\n\tif (cached) {\n\t\treturn cached;\n\t}\n\n\tconst itemScore = doScoreItemFuzzy(label, description, accessor.getItemPath(item), query, allowNonContiguousMatches);\n\tcache[cacheHash] = itemScore;\n\n\treturn itemScore;\n}\n\nfunction doScoreItemFuzzy(label: string, description: string | undefined, path: string | undefined, query: IPreparedQuery, allowNonContiguousMatches: boolean): IItemScore {\n\tconst preferLabelMatches = !path || !query.containsPathSeparator;\n\n\t// Treat identity matches on full path highest\n\tif (path && (isLinux ? query.pathNormalized === path : equalsIgnoreCase(query.pathNormalized, path))) {\n\t\treturn { score: PATH_IDENTITY_SCORE, labelMatch: [{ start: 0, end: label.length }], descriptionMatch: description ? [{ start: 0, end: description.length }] : undefined };\n\t}\n\n\t// Score: multiple inputs\n\tif (query.values && query.values.length > 1) {\n\t\treturn doScoreItemFuzzyMultiple(label, description, path, query.values, preferLabelMatches, allowNonContiguousMatches);\n\t}\n\n\t// Score: single input\n\treturn doScoreItemFuzzySingle(label, description, path, query, preferLabelMatches, allowNonContiguousMatches);\n}\n\nfunction doScoreItemFuzzyMultiple(label: string, description: string | undefined, path: string | undefined, query: IPreparedQueryPiece[], preferLabelMatches: boolean, allowNonContiguousMatches: boolean): IItemScore {\n\tlet totalScore = 0;\n\tconst totalLabelMatches: IMatch[] = [];\n\tconst totalDescriptionMatches: IMatch[] = [];\n\n\tfor (const queryPiece of query) {\n\t\tconst { score, labelMatch, descriptionMatch } = doScoreItemFuzzySingle(label, description, path, queryPiece, preferLabelMatches, allowNonContiguousMatches);\n\t\tif (score === NO_MATCH) {\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_ITEM_SCORE;\n\t\t}\n\n\t\ttotalScore += score;\n\t\tif (labelMatch) {\n\t\t\ttotalLabelMatches.push(...labelMatch);\n\t\t}\n\n\t\tif (descriptionMatch) {\n\t\t\ttotalDescriptionMatches.push(...descriptionMatch);\n\t\t}\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 {\n\t\tscore: totalScore,\n\t\tlabelMatch: normalizeMatches(totalLabelMatches),\n\t\tdescriptionMatch: normalizeMatches(totalDescriptionMatches)\n\t};\n}\n\nfunction doScoreItemFuzzySingle(label: string, description: string | undefined, path: string | undefined, query: IPreparedQueryPiece, preferLabelMatches: boolean, allowNonContiguousMatches: boolean): IItemScore {\n\n\t// Prefer label matches if told so or we have no description\n\tif (preferLabelMatches || !description) {\n\t\tconst [labelScore, labelPositions] = scoreFuzzy(\n\t\t\tlabel,\n\t\t\tquery.normalized,\n\t\t\tquery.normalizedLowercase,\n\t\t\tallowNonContiguousMatches && !query.expectContiguousMatch);\n\t\tif (labelScore) {\n\n\t\t\t// If we have a prefix match on the label, we give a much\n\t\t\t// higher baseScore to elevate these matches over others\n\t\t\t// This ensures that typing a file name wins over results\n\t\t\t// that are present somewhere in the label, but not the\n\t\t\t// beginning.\n\t\t\tconst labelPrefixMatch = matchesPrefix(query.normalized, label);\n\t\t\tlet baseScore: number;\n\t\t\tif (labelPrefixMatch) {\n\t\t\t\tbaseScore = LABEL_PREFIX_SCORE_THRESHOLD;\n\n\t\t\t\t// We give another boost to labels that are short, e.g. given\n\t\t\t\t// files \"window.ts\" and \"windowActions.ts\" and a query of\n\t\t\t\t// \"window\", we want \"window.ts\" to receive a higher score.\n\t\t\t\t// As such we compute the percentage the query has within the\n\t\t\t\t// label and add that to the baseScore.\n\t\t\t\tconst prefixLengthBoost = Math.round((query.normalized.length / label.length) * 100);\n\t\t\t\tbaseScore += prefixLengthBoost;\n\t\t\t} else {\n\t\t\t\tbaseScore = LABEL_SCORE_THRESHOLD;\n\t\t\t}\n\n\t\t\treturn { score: baseScore + labelScore, labelMatch: labelPrefixMatch || createMatches(labelPositions) };\n\t\t}\n\t}\n\n\t// Finally compute description + label scores if we have a description\n\tif (description) {\n\t\tlet descriptionPrefix = description;\n\t\tif (!!path) {\n\t\t\tdescriptionPrefix = `${description}${sep}`; // assume this is a file path\n\t\t}\n\n\t\tconst descriptionPrefixLength = descriptionPrefix.length;\n\t\tconst descriptionAndLabel = `${descriptionPrefix}${label}`;\n\n\t\tconst [labelDescriptionScore, labelDescriptionPositions] = scoreFuzzy(\n\t\t\tdescriptionAndLabel,\n\t\t\tquery.normalized,\n\t\t\tquery.normalizedLowercase,\n\t\t\tallowNonContiguousMatches && !query.expectContiguousMatch);\n\t\tif (labelDescriptionScore) {\n\t\t\tconst labelDescriptionMatches = createMatches(labelDescriptionPositions);\n\t\t\tconst labelMatch: IMatch[] = [];\n\t\t\tconst descriptionMatch: IMatch[] = [];\n\n\t\t\t// We have to split the matches back onto the label and description portions\n\t\t\tlabelDescriptionMatches.forEach(h => {\n\n\t\t\t\t// Match overlaps label and description part, we need to split it up\n\t\t\t\tif (h.start < descriptionPrefixLength && h.end > descriptionPrefixLength) {\n\t\t\t\t\tlabelMatch.push({ start: 0, end: h.end - descriptionPrefixLength });\n\t\t\t\t\tdescriptionMatch.push({ start: h.start, end: descriptionPrefixLength });\n\t\t\t\t}\n\n\t\t\t\t// Match on label part\n\t\t\t\telse if (h.start >= descriptionPrefixLength) {\n\t\t\t\t\tlabelMatch.push({ start: h.start - descriptionPrefixLength, end: h.end - descriptionPrefixLength });\n\t\t\t\t}\n\n\t\t\t\t// Match on description part\n\t\t\t\telse {\n\t\t\t\t\tdescriptionMatch.push(h);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\treturn { score: labelDescriptionScore, labelMatch, descriptionMatch };\n\t\t}\n\t}\n\n\treturn NO_ITEM_SCORE;\n}\n\nfunction createMatches(offsets: number[] | undefined): IMatch[] {\n\tconst ret: IMatch[] = [];\n\tif (!offsets) {\n\t\treturn ret;\n\t}\n\n\tlet last: IMatch | undefined;\n\tfor (const pos of offsets) {\n\t\tif (last && last.end === pos) {\n\t\t\tlast.end += 1;\n\t\t} else {\n\t\t\tlast = { start: pos, end: pos + 1 };\n\t\t\tret.push(last);\n\t\t}\n\t}\n\n\treturn ret;\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 Comparers\n\nexport function compareItemsByFuzzyScore(itemA: T, itemB: T, query: IPreparedQuery, allowNonContiguousMatches: boolean, accessor: IItemAccessor, cache: FuzzyScorerCache): number {\n\tconst itemScoreA = scoreItemFuzzy(itemA, query, allowNonContiguousMatches, accessor, cache);\n\tconst itemScoreB = scoreItemFuzzy(itemB, query, allowNonContiguousMatches, accessor, cache);\n\n\tconst scoreA = itemScoreA.score;\n\tconst scoreB = itemScoreB.score;\n\n\t// 1.) identity matches have highest score\n\tif (scoreA === PATH_IDENTITY_SCORE || scoreB === PATH_IDENTITY_SCORE) {\n\t\tif (scoreA !== scoreB) {\n\t\t\treturn scoreA === PATH_IDENTITY_SCORE ? -1 : 1;\n\t\t}\n\t}\n\n\t// 2.) matches on label are considered higher compared to label+description matches\n\tif (scoreA > LABEL_SCORE_THRESHOLD || scoreB > LABEL_SCORE_THRESHOLD) {\n\t\tif (scoreA !== scoreB) {\n\t\t\treturn scoreA > scoreB ? -1 : 1;\n\t\t}\n\n\t\t// prefer more compact matches over longer in label (unless this is a prefix match where\n\t\t// longer prefix matches are actually preferred)\n\t\tif (scoreA < LABEL_PREFIX_SCORE_THRESHOLD && scoreB < LABEL_PREFIX_SCORE_THRESHOLD) {\n\t\t\tconst comparedByMatchLength = compareByMatchLength(itemScoreA.labelMatch, itemScoreB.labelMatch);\n\t\t\tif (comparedByMatchLength !== 0) {\n\t\t\t\treturn comparedByMatchLength;\n\t\t\t}\n\t\t}\n\n\t\t// prefer shorter labels over longer labels\n\t\tconst labelA = accessor.getItemLabel(itemA) || '';\n\t\tconst labelB = accessor.getItemLabel(itemB) || '';\n\t\tif (labelA.length !== labelB.length) {\n\t\t\treturn labelA.length - labelB.length;\n\t\t}\n\t}\n\n\t// 3.) compare by score in label+description\n\tif (scoreA !== scoreB) {\n\t\treturn scoreA > scoreB ? -1 : 1;\n\t}\n\n\t// 4.) scores are identical: prefer matches in label over non-label matches\n\tconst itemAHasLabelMatches = Array.isArray(itemScoreA.labelMatch) && itemScoreA.labelMatch.length > 0;\n\tconst itemBHasLabelMatches = Array.isArray(itemScoreB.labelMatch) && itemScoreB.labelMatch.length > 0;\n\tif (itemAHasLabelMatches && !itemBHasLabelMatches) {\n\t\treturn -1;\n\t} else if (itemBHasLabelMatches && !itemAHasLabelMatches) {\n\t\treturn 1;\n\t}\n\n\t// 5.) scores are identical: prefer more compact matches (label and description)\n\tconst itemAMatchDistance = computeLabelAndDescriptionMatchDistance(itemA, itemScoreA, accessor);\n\tconst itemBMatchDistance = computeLabelAndDescriptionMatchDistance(itemB, itemScoreB, accessor);\n\tif (itemAMatchDistance && itemBMatchDistance && itemAMatchDistance !== itemBMatchDistance) {\n\t\treturn itemBMatchDistance > itemAMatchDistance ? -1 : 1;\n\t}\n\n\t// 6.) scores are identical: start to use the fallback compare\n\treturn fallbackCompare(itemA, itemB, query, accessor);\n}\n\nfunction computeLabelAndDescriptionMatchDistance(item: T, score: IItemScore, accessor: IItemAccessor): number {\n\tlet matchStart: number = -1;\n\tlet matchEnd: number = -1;\n\n\t// If we have description matches, the start is first of description match\n\tif (score.descriptionMatch && score.descriptionMatch.length) {\n\t\tmatchStart = score.descriptionMatch[0].start;\n\t}\n\n\t// Otherwise, the start is the first label match\n\telse if (score.labelMatch && score.labelMatch.length) {\n\t\tmatchStart = score.labelMatch[0].start;\n\t}\n\n\t// If we have label match, the end is the last label match\n\t// If we had a description match, we add the length of the description\n\t// as offset to the end to indicate this.\n\tif (score.labelMatch && score.labelMatch.length) {\n\t\tmatchEnd = score.labelMatch[score.labelMatch.length - 1].end;\n\t\tif (score.descriptionMatch && score.descriptionMatch.length) {\n\t\t\tconst itemDescription = accessor.getItemDescription(item);\n\t\t\tif (itemDescription) {\n\t\t\t\tmatchEnd += itemDescription.length;\n\t\t\t}\n\t\t}\n\t}\n\n\t// If we have just a description match, the end is the last description match\n\telse if (score.descriptionMatch && score.descriptionMatch.length) {\n\t\tmatchEnd = score.descriptionMatch[score.descriptionMatch.length - 1].end;\n\t}\n\n\treturn matchEnd - matchStart;\n}\n\nfunction compareByMatchLength(matchesA?: IMatch[], matchesB?: IMatch[]): number {\n\tif ((!matchesA && !matchesB) || ((!matchesA || !matchesA.length) && (!matchesB || !matchesB.length))) {\n\t\treturn 0; // make sure to not cause bad comparing when matches are not provided\n\t}\n\n\tif (!matchesB || !matchesB.length) {\n\t\treturn -1;\n\t}\n\n\tif (!matchesA || !matchesA.length) {\n\t\treturn 1;\n\t}\n\n\t// Compute match length of A (first to last match)\n\tconst matchStartA = matchesA[0].start;\n\tconst matchEndA = matchesA[matchesA.length - 1].end;\n\tconst matchLengthA = matchEndA - matchStartA;\n\n\t// Compute match length of B (first to last match)\n\tconst matchStartB = matchesB[0].start;\n\tconst matchEndB = matchesB[matchesB.length - 1].end;\n\tconst matchLengthB = matchEndB - matchStartB;\n\n\t// Prefer shorter match length\n\treturn matchLengthA === matchLengthB ? 0 : matchLengthB < matchLengthA ? 1 : -1;\n}\n\nfunction fallbackCompare(itemA: T, itemB: T, query: IPreparedQuery, accessor: IItemAccessor): number {\n\n\t// check for label + description length and prefer shorter\n\tconst labelA = accessor.getItemLabel(itemA) || '';\n\tconst labelB = accessor.getItemLabel(itemB) || '';\n\n\tconst descriptionA = accessor.getItemDescription(itemA);\n\tconst descriptionB = accessor.getItemDescription(itemB);\n\n\tconst labelDescriptionALength = labelA.length + (descriptionA ? descriptionA.length : 0);\n\tconst labelDescriptionBLength = labelB.length + (descriptionB ? descriptionB.length : 0);\n\n\tif (labelDescriptionALength !== labelDescriptionBLength) {\n\t\treturn labelDescriptionALength - labelDescriptionBLength;\n\t}\n\n\t// check for path length and prefer shorter\n\tconst pathA = accessor.getItemPath(itemA);\n\tconst pathB = accessor.getItemPath(itemB);\n\n\tif (pathA && pathB && pathA.length !== pathB.length) {\n\t\treturn pathA.length - pathB.length;\n\t}\n\n\t// 7.) finally we have equal scores and equal length, we fallback to comparer\n\n\t// compare by label\n\tif (labelA !== labelB) {\n\t\treturn compareAnything(labelA, labelB, query.normalized);\n\t}\n\n\t// compare by description\n\tif (descriptionA && descriptionB && descriptionA !== descriptionB) {\n\t\treturn compareAnything(descriptionA, descriptionB, query.normalized);\n\t}\n\n\t// compare by path\n\tif (pathA && pathB && pathA !== pathB) {\n\t\treturn compareAnything(pathA, pathB, query.normalized);\n\t}\n\n\t// equal\n\treturn 0;\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","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { extname } from 'vs/base/common/path';\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\ninterface MapExtToMediaMimes {\n\t[index: string]: string;\n}\n\nconst mapExtToTextMimes: MapExtToMediaMimes = {\n\t'.css': 'text/css',\n\t'.csv': 'text/csv',\n\t'.htm': 'text/html',\n\t'.html': 'text/html',\n\t'.ics': 'text/calendar',\n\t'.js': 'text/javascript',\n\t'.mjs': 'text/javascript',\n\t'.txt': 'text/plain',\n\t'.xml': 'text/xml'\n};\n\n// Known media mimes that we can handle\nconst mapExtToMediaMimes: MapExtToMediaMimes = {\n\t'.aac': 'audio/x-aac',\n\t'.avi': 'video/x-msvideo',\n\t'.bmp': 'image/bmp',\n\t'.flv': 'video/x-flv',\n\t'.gif': 'image/gif',\n\t'.ico': 'image/x-icon',\n\t'.jpe': 'image/jpg',\n\t'.jpeg': 'image/jpg',\n\t'.jpg': 'image/jpg',\n\t'.m1v': 'video/mpeg',\n\t'.m2a': 'audio/mpeg',\n\t'.m2v': 'video/mpeg',\n\t'.m3a': 'audio/mpeg',\n\t'.mid': 'audio/midi',\n\t'.midi': 'audio/midi',\n\t'.mk3d': 'video/x-matroska',\n\t'.mks': 'video/x-matroska',\n\t'.mkv': 'video/x-matroska',\n\t'.mov': 'video/quicktime',\n\t'.movie': 'video/x-sgi-movie',\n\t'.mp2': 'audio/mpeg',\n\t'.mp2a': 'audio/mpeg',\n\t'.mp3': 'audio/mpeg',\n\t'.mp4': 'video/mp4',\n\t'.mp4a': 'audio/mp4',\n\t'.mp4v': 'video/mp4',\n\t'.mpe': 'video/mpeg',\n\t'.mpeg': 'video/mpeg',\n\t'.mpg': 'video/mpeg',\n\t'.mpg4': 'video/mp4',\n\t'.mpga': 'audio/mpeg',\n\t'.oga': 'audio/ogg',\n\t'.ogg': 'audio/ogg',\n\t'.opus': 'audio/opus',\n\t'.ogv': 'video/ogg',\n\t'.png': 'image/png',\n\t'.psd': 'image/vnd.adobe.photoshop',\n\t'.qt': 'video/quicktime',\n\t'.spx': 'audio/ogg',\n\t'.svg': 'image/svg+xml',\n\t'.tga': 'image/x-tga',\n\t'.tif': 'image/tiff',\n\t'.tiff': 'image/tiff',\n\t'.wav': 'audio/x-wav',\n\t'.webm': 'video/webm',\n\t'.webp': 'image/webp',\n\t'.wma': 'audio/x-ms-wma',\n\t'.wmv': 'video/x-ms-wmv',\n\t'.woff': 'application/font-woff',\n};\n\nexport function getMediaOrTextMime(path: string): string | undefined {\n\tconst ext = extname(path);\n\tconst textMime = mapExtToTextMimes[ext.toLowerCase()];\n\tif (textMime !== undefined) {\n\t\treturn textMime;\n\t} else {\n\t\treturn getMediaMime(path);\n\t}\n}\n\nexport function getMediaMime(path: string): string | undefined {\n\tconst ext = extname(path);\n\treturn mapExtToMediaMimes[ext.toLowerCase()];\n}\n\nexport function getExtensionForMimeType(mimeType: string): string | undefined {\n\tfor (const extension in mapExtToMediaMimes) {\n\t\tif (mapExtToMediaMimes[extension] === mimeType) {\n\t\t\treturn extension;\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\nconst _simplePattern = /^(.+)\\/(.+?)(;.+)?$/;\n\nexport function normalizeMimeType(mimeType: string): string;\nexport function normalizeMimeType(mimeType: string, strict: true): string | undefined;\nexport function normalizeMimeType(mimeType: string, strict?: true): string | undefined {\n\n\tconst match = _simplePattern.exec(mimeType);\n\tif (!match) {\n\t\treturn strict\n\t\t\t? undefined\n\t\t\t: mimeType;\n\t}\n\t// https://datatracker.ietf.org/doc/html/rfc2045#section-5.1\n\t// media and subtype must ALWAYS be lowercase, parameter not\n\treturn `${match[1].toLowerCase()}/${match[2].toLowerCase()}${match[3] ?? ''}`;\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { IProcessEnvironment, isLinux, isMacintosh } from 'vs/base/common/platform';\n\n/**\n * Options to be passed to the external program or shell.\n */\nexport interface CommandOptions {\n\t/**\n\t * The current working directory of the executed program or shell.\n\t * If omitted VSCode's current workspace root is used.\n\t */\n\tcwd?: string;\n\n\t/**\n\t * The environment of the executed program or shell. If omitted\n\t * the parent process' environment is used.\n\t */\n\tenv?: { [key: string]: string };\n}\n\nexport interface Executable {\n\t/**\n\t * The command to be executed. Can be an external program or a shell\n\t * command.\n\t */\n\tcommand: string;\n\n\t/**\n\t * Specifies whether the command is a shell command and therefore must\n\t * be executed in a shell interpreter (e.g. cmd.exe, bash, ...).\n\t */\n\tisShellCommand: boolean;\n\n\t/**\n\t * The arguments passed to the command.\n\t */\n\targs: string[];\n\n\t/**\n\t * The command options used when the command is executed. Can be omitted.\n\t */\n\toptions?: CommandOptions;\n}\n\nexport interface ForkOptions extends CommandOptions {\n\texecArgv?: string[];\n}\n\nexport const enum Source {\n\tstdout,\n\tstderr\n}\n\n/**\n * The data send via a success callback\n */\nexport interface SuccessData {\n\terror?: Error;\n\tcmdCode?: number;\n\tterminated?: boolean;\n}\n\n/**\n * The data send via a error callback\n */\nexport interface ErrorData {\n\terror?: Error;\n\tterminated?: boolean;\n\tstdout?: string;\n\tstderr?: string;\n}\n\nexport interface TerminateResponse {\n\tsuccess: boolean;\n\tcode?: TerminateResponseCode;\n\terror?: any;\n}\n\nexport const enum TerminateResponseCode {\n\tSuccess = 0,\n\tUnknown = 1,\n\tAccessDenied = 2,\n\tProcessNotFound = 3,\n}\n\nexport interface ProcessItem {\n\tname: string;\n\tcmd: string;\n\tpid: number;\n\tppid: number;\n\tload: number;\n\tmem: number;\n\n\tchildren?: ProcessItem[];\n}\n\n/**\n * Sanitizes a VS Code process environment by removing all Electron/VS Code-related values.\n */\nexport function sanitizeProcessEnvironment(env: IProcessEnvironment, ...preserve: string[]): void {\n\tconst set = preserve.reduce((set, key) => {\n\t\tset[key] = true;\n\t\treturn set;\n\t}, {} as Record);\n\tconst keysToRemove = [\n\t\t/^ELECTRON_.+$/,\n\t\t/^VSCODE_(?!(PORTABLE|SHELL_LOGIN|ENV_REPLACE|ENV_APPEND|ENV_PREPEND)).+$/,\n\t\t/^SNAP(|_.*)$/,\n\t\t/^GDK_PIXBUF_.+$/,\n\t];\n\tconst envKeys = Object.keys(env);\n\tenvKeys\n\t\t.filter(key => !set[key])\n\t\t.forEach(envKey => {\n\t\t\tfor (let i = 0; i < keysToRemove.length; i++) {\n\t\t\t\tif (envKey.search(keysToRemove[i]) !== -1) {\n\t\t\t\t\tdelete env[envKey];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n}\n\n/**\n * Remove dangerous environment variables that have caused crashes\n * in forked processes (i.e. in ELECTRON_RUN_AS_NODE processes)\n *\n * @param env The env object to change\n */\nexport function removeDangerousEnvVariables(env: IProcessEnvironment | undefined): void {\n\tif (!env) {\n\t\treturn;\n\t}\n\n\t// Unset `DEBUG`, as an invalid value might lead to process crashes\n\t// See https://github.com/microsoft/vscode/issues/130072\n\tdelete env['DEBUG'];\n\n\tif (isMacintosh) {\n\t\t// Unset `DYLD_LIBRARY_PATH`, as it leads to process crashes\n\t\t// See https://github.com/microsoft/vscode/issues/104525\n\t\t// See https://github.com/microsoft/vscode/issues/105848\n\t\tdelete env['DYLD_LIBRARY_PATH'];\n\t}\n\n\tif (isLinux) {\n\t\t// Unset `LD_PRELOAD`, as it might lead to process crashes\n\t\t// See https://github.com/microsoft/vscode/issues/134177\n\t\tdelete env['LD_PRELOAD'];\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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\nexport function isUriComponents(thing: any): thing is UriComponents {\n\tif (!thing || typeof thing !== 'object') {\n\t\treturn false;\n\t}\n\treturn typeof (thing).scheme === 'string'\n\t\t&& (typeof (thing).authority === 'string' || typeof (thing).authority === 'undefined')\n\t\t&& (typeof (thing).path === 'string' || typeof (thing).path === 'undefined')\n\t\t&& (typeof (thing).query === 'string' || typeof (thing).query === 'undefined')\n\t\t&& (typeof (thing).fragment === 'string' || typeof (thing).fragment === 'undefined');\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/**\n * Mapped-type that replaces all occurrences of URI with UriComponents\n */\nexport type UriDto = { [K in keyof T]: T[K] extends URI\n\t? UriComponents\n\t: UriDto };\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 interface IRemoteConsoleLog {\n\ttype: string;\n\tseverity: string;\n\targuments: string;\n}\n\nexport interface IStackArgument {\n\t__$stack: string;\n}\n\nexport interface IStackFrame {\n\turi: URI;\n\tline: number;\n\tcolumn: number;\n}\n\nexport function isRemoteConsoleLog(obj: any): obj is IRemoteConsoleLog {\n\tconst entry = obj as IRemoteConsoleLog;\n\n\treturn entry && typeof entry.type === 'string' && typeof entry.severity === 'string';\n}\n\nexport function parse(entry: IRemoteConsoleLog): { args: any[]; stack?: string } {\n\tconst args: any[] = [];\n\tlet stack: string | undefined;\n\n\t// Parse Entry\n\ttry {\n\t\tconst parsedArguments: any[] = JSON.parse(entry.arguments);\n\n\t\t// Check for special stack entry as last entry\n\t\tconst stackArgument = parsedArguments[parsedArguments.length - 1] as IStackArgument;\n\t\tif (stackArgument && stackArgument.__$stack) {\n\t\t\tparsedArguments.pop(); // stack is handled specially\n\t\t\tstack = stackArgument.__$stack;\n\t\t}\n\n\t\targs.push(...parsedArguments);\n\t} catch (error) {\n\t\targs.push('Unable to log remote console arguments', entry.arguments);\n\t}\n\n\treturn { args, stack };\n}\n\nexport function getFirstFrame(entry: IRemoteConsoleLog): IStackFrame | undefined;\nexport function getFirstFrame(stack: string | undefined): IStackFrame | undefined;\nexport function getFirstFrame(arg0: IRemoteConsoleLog | string | undefined): IStackFrame | undefined {\n\tif (typeof arg0 !== 'string') {\n\t\treturn getFirstFrame(parse(arg0!).stack);\n\t}\n\n\t// Parse a source information out of the stack if we have one. Format can be:\n\t// at vscode.commands.registerCommand (/Users/someone/Desktop/test-ts/out/src/extension.js:18:17)\n\t// or\n\t// at /Users/someone/Desktop/test-ts/out/src/extension.js:18:17\n\t// or\n\t// at c:\\Users\\someone\\Desktop\\end-js\\extension.js:19:17\n\t// or\n\t// at e.$executeContributedCommand(c:\\Users\\someone\\Desktop\\end-js\\extension.js:19:17)\n\tconst stack = arg0;\n\tif (stack) {\n\t\tconst topFrame = findFirstFrame(stack);\n\n\t\t// at [^\\/]* => line starts with \"at\" followed by any character except '/' (to not capture unix paths too late)\n\t\t// (?:(?:[a-zA-Z]+:)|(?:[\\/])|(?:\\\\\\\\) => windows drive letter OR unix root OR unc root\n\t\t// (?:.+) => simple pattern for the path, only works because of the line/col pattern after\n\t\t// :(?:\\d+):(?:\\d+) => :line:column data\n\t\tconst matches = /at [^\\/]*((?:(?:[a-zA-Z]+:)|(?:[\\/])|(?:\\\\\\\\))(?:.+)):(\\d+):(\\d+)/.exec(topFrame || '');\n\t\tif (matches && matches.length === 4) {\n\t\t\treturn {\n\t\t\t\turi: URI.file(matches[1]),\n\t\t\t\tline: Number(matches[2]),\n\t\t\t\tcolumn: Number(matches[3])\n\t\t\t};\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\nfunction findFirstFrame(stack: string | undefined): string | undefined {\n\tif (!stack) {\n\t\treturn stack;\n\t}\n\n\tconst newlineIndex = stack.indexOf('\\n');\n\tif (newlineIndex === -1) {\n\t\treturn stack;\n\t}\n\n\treturn stack.substring(0, newlineIndex);\n}\n\nexport function log(entry: IRemoteConsoleLog, label: string): void {\n\tconst { args, stack } = parse(entry);\n\n\tconst isOneStringArg = typeof args[0] === 'string' && args.length === 1;\n\n\tlet topFrame = findFirstFrame(stack);\n\tif (topFrame) {\n\t\ttopFrame = `(${topFrame.trim()})`;\n\t}\n\n\tlet consoleArgs: string[] = [];\n\n\t// First arg is a string\n\tif (typeof args[0] === 'string') {\n\t\tif (topFrame && isOneStringArg) {\n\t\t\tconsoleArgs = [`%c[${label}] %c${args[0]} %c${topFrame}`, color('blue'), color(''), color('grey')];\n\t\t} else {\n\t\t\tconsoleArgs = [`%c[${label}] %c${args[0]}`, color('blue'), color(''), ...args.slice(1)];\n\t\t}\n\t}\n\n\t// First arg is something else, just apply all\n\telse {\n\t\tconsoleArgs = [`%c[${label}]%`, color('blue'), ...args];\n\t}\n\n\t// Stack: add to args unless already added\n\tif (topFrame && !isOneStringArg) {\n\t\tconsoleArgs.push(topFrame);\n\t}\n\n\t// Log it\n\tif (typeof (console as any)[entry.severity] !== 'function') {\n\t\tthrow new Error('Unknown console method');\n\t}\n\t(console as any)[entry.severity].apply(console, consoleArgs);\n}\n\nfunction color(color: string): string {\n\treturn `color: ${color}`;\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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';\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 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 special rendering of settings in the release notes\n\t */\n\texport const codeSetting = 'code-setting';\n\n\t/**\n\t * Scheme used for special rendering of features in the release notes\n\t */\n\texport const codeFeature = 'code-feature';\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}\n\nexport const connectionTokenCookieName = 'vscode-tkn';\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 _remoteResourcesPath: string = `/${Schemas.vscodeRemoteResource}`;\n\n\tsetPreferredWebSchema(schema: 'http' | 'https') {\n\t\tthis._preferredWebSchema = schema;\n\t}\n\n\tsetDelegate(delegate: (uri: URI) => URI): void {\n\t\tthis._delegate = delegate;\n\t}\n\n\tsetServerRootPath(serverRootPath: string): void {\n\t\tthis._remoteResourcesPath = `${serverRootPath}/${Schemas.vscodeRemoteResource}`;\n\t}\n\n\tset(authority: string, host: string, port: number): void {\n\t\tthis._hosts[authority] = host;\n\t\tthis._ports[authority] = port;\n\t}\n\n\tsetConnectionToken(authority: string, connectionToken: string): void {\n\t\tthis._connectionTokens[authority] = connectionToken;\n\t}\n\n\tgetPreferredWebSchema(): 'http' | 'https' {\n\t\treturn this._preferredWebSchema;\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\n/**\n * A string pointing to a path inside the app. It should not begin with ./ or ../\n */\nexport type AppResourcePath = (\n\t`a${string}` | `b${string}` | `c${string}` | `d${string}` | `e${string}` | `f${string}`\n\t| `g${string}` | `h${string}` | `i${string}` | `j${string}` | `k${string}` | `l${string}`\n\t| `m${string}` | `n${string}` | `o${string}` | `p${string}` | `q${string}` | `r${string}`\n\t| `s${string}` | `t${string}` | `u${string}` | `v${string}` | `w${string}` | `x${string}`\n\t| `y${string}` | `z${string}`\n);\n\nexport const builtinExtensionsPath: AppResourcePath = 'vs/../../extensions';\nexport const nodeModulesPath: AppResourcePath = 'vs/../../node_modules';\nexport const nodeModulesAsarPath: AppResourcePath = 'vs/../../node_modules.asar';\nexport const nodeModulesAsarUnpackedPath: AppResourcePath = 'vs/../../node_modules.asar.unpacked';\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\tasBrowserUri(resourcePath: AppResourcePath | ''): URI {\n\t\tconst uri = this.toUri(resourcePath, require);\n\t\treturn this.uriToBrowserUri(uri);\n\t}\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\t/**\n\t * Returns the `file` URI to use in contexts where node.js\n\t * is responsible for loading.\n\t */\n\tasFileUri(resourcePath: AppResourcePath | ''): URI {\n\t\tconst uri = this.toUri(resourcePath, require);\n\t\treturn this.uriToFileUri(uri);\n\t}\n\n\t/**\n\t * Returns the `file` URI to use in contexts where node.js\n\t * is responsible for loading.\n\t */\n\turiToFileUri(uri: URI): URI {\n\t\t// Only convert the URI if it is `vscode-file:` scheme\n\t\tif (uri.scheme === Schemas.vscodeFileResource) {\n\t\t\treturn uri.with({\n\t\t\t\tscheme: Schemas.file,\n\t\t\t\t// Only preserve the `authority` if it is different from\n\t\t\t\t// our fallback authority. This ensures we properly preserve\n\t\t\t\t// Windows UNC paths that come with their own authority.\n\t\t\t\tauthority: uri.authority !== FileAccessImpl.FALLBACK_AUTHORITY ? uri.authority : null,\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\tprivate toUri(uriOrModule: URI | string, moduleIdToUrl: { toUrl(moduleId: string): string }): URI {\n\t\tif (URI.isUri(uriOrModule)) {\n\t\t\treturn uriOrModule;\n\t\t}\n\n\t\treturn URI.parse(moduleIdToUrl.toUrl(uriOrModule));\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 { isESM } from 'vs/base/common/amd';\nimport { AppResourcePath, FileAccess, nodeModulesAsarPath, nodeModulesPath } from 'vs/base/common/network';\nimport * as platform from 'vs/base/common/platform';\nimport { IProductConfiguration } from 'vs/base/common/product';\nimport { URI } from 'vs/base/common/uri';\n\n\nclass DefineCall {\n\tconstructor(\n\t\tpublic readonly id: string | null | undefined,\n\t\tpublic readonly dependencies: string[] | null | undefined,\n\t\tpublic readonly callback: any\n\t) { }\n}\n\nclass AMDModuleImporter {\n\tpublic static INSTANCE = new AMDModuleImporter();\n\n\tprivate readonly _isWebWorker = (typeof self === 'object' && self.constructor && self.constructor.name === 'DedicatedWorkerGlobalScope');\n\tprivate readonly _isRenderer = typeof document === 'object';\n\n\tprivate readonly _defineCalls: DefineCall[] = [];\n\tprivate _initialized = false;\n\tprivate _amdPolicy: Pick, 'name' | 'createScriptURL'> | undefined;\n\n\tconstructor() { }\n\n\tprivate _initialize(): void {\n\t\tif (this._initialized) {\n\t\t\treturn;\n\t\t}\n\t\tthis._initialized = true;\n\n\t\t(globalThis).define = (id: any, dependencies: any, callback: any) => {\n\t\t\tif (typeof id !== 'string') {\n\t\t\t\tcallback = dependencies;\n\t\t\t\tdependencies = id;\n\t\t\t\tid = null;\n\t\t\t}\n\t\t\tif (typeof dependencies !== 'object' || !Array.isArray(dependencies)) {\n\t\t\t\tcallback = dependencies;\n\t\t\t\tdependencies = null;\n\t\t\t}\n\t\t\t// if (!dependencies) {\n\t\t\t// \tdependencies = ['require', 'exports', 'module'];\n\t\t\t// }\n\t\t\tthis._defineCalls.push(new DefineCall(id, dependencies, callback));\n\t\t};\n\n\t\t(globalThis).define.amd = true;\n\n\t\tif (this._isRenderer) {\n\t\t\t// eslint-disable-next-line no-restricted-globals\n\t\t\tthis._amdPolicy = window.trustedTypes?.createPolicy('amdLoader', {\n\t\t\t\tcreateScriptURL(value) {\n\t\t\t\t\t// eslint-disable-next-line no-restricted-globals\n\t\t\t\t\tif (value.startsWith(window.location.origin)) {\n\t\t\t\t\t\treturn value;\n\t\t\t\t\t}\n\t\t\t\t\tif (value.startsWith('vscode-file://vscode-app')) {\n\t\t\t\t\t\treturn value;\n\t\t\t\t\t}\n\t\t\t\t\tthrow new Error(`[trusted_script_src] Invalid script url: ${value}`);\n\t\t\t\t}\n\t\t\t});\n\t\t} else if (this._isWebWorker) {\n\t\t\tthis._amdPolicy = (globalThis).trustedTypes?.createPolicy('amdLoader', {\n\t\t\t\tcreateScriptURL(value: string) {\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\tpublic async load(scriptSrc: string): Promise {\n\t\tthis._initialize();\n\t\tconst defineCall = await (this._isWebWorker ? this._workerLoadScript(scriptSrc) : this._isRenderer ? this._rendererLoadScript(scriptSrc) : this._nodeJSLoadScript(scriptSrc));\n\t\tif (!defineCall) {\n\t\t\tthrow new Error(`Did not receive a define call from script ${scriptSrc}`);\n\t\t}\n\t\t// TODO require, exports, module\n\t\tif (Array.isArray(defineCall.dependencies) && defineCall.dependencies.length > 0) {\n\t\t\tthrow new Error(`Cannot resolve dependencies for script ${scriptSrc}. The dependencies are: ${defineCall.dependencies.join(', ')}`);\n\t\t}\n\t\tif (typeof defineCall.callback === 'function') {\n\t\t\treturn defineCall.callback([]);\n\t\t} else {\n\t\t\treturn defineCall.callback;\n\t\t}\n\t}\n\n\tprivate _rendererLoadScript(scriptSrc: string): Promise {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst scriptElement = document.createElement('script');\n\t\t\tscriptElement.setAttribute('async', 'async');\n\t\t\tscriptElement.setAttribute('type', 'text/javascript');\n\n\t\t\tconst unbind = () => {\n\t\t\t\tscriptElement.removeEventListener('load', loadEventListener);\n\t\t\t\tscriptElement.removeEventListener('error', errorEventListener);\n\t\t\t};\n\n\t\t\tconst loadEventListener = (e: any) => {\n\t\t\t\tunbind();\n\t\t\t\tresolve(this._defineCalls.pop());\n\t\t\t};\n\n\t\t\tconst errorEventListener = (e: any) => {\n\t\t\t\tunbind();\n\t\t\t\treject(e);\n\t\t\t};\n\n\t\t\tscriptElement.addEventListener('load', loadEventListener);\n\t\t\tscriptElement.addEventListener('error', errorEventListener);\n\t\t\tif (this._amdPolicy) {\n\t\t\t\tscriptSrc = this._amdPolicy.createScriptURL(scriptSrc) as any as string;\n\t\t\t}\n\t\t\tscriptElement.setAttribute('src', scriptSrc);\n\t\t\t// eslint-disable-next-line no-restricted-globals\n\t\t\twindow.document.getElementsByTagName('head')[0].appendChild(scriptElement);\n\t\t});\n\t}\n\n\tprivate _workerLoadScript(scriptSrc: string): Promise {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\ttry {\n\t\t\t\tif (this._amdPolicy) {\n\t\t\t\t\tscriptSrc = this._amdPolicy.createScriptURL(scriptSrc) as any as string;\n\t\t\t\t}\n\t\t\t\timportScripts(scriptSrc);\n\t\t\t\tresolve(this._defineCalls.pop());\n\t\t\t} catch (err) {\n\t\t\t\treject(err);\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate async _nodeJSLoadScript(scriptSrc: string): Promise {\n\t\ttry {\n\t\t\tconst fs = globalThis._VSCODE_NODE_MODULES['fs'];\n\t\t\tconst vm = globalThis._VSCODE_NODE_MODULES['vm'];\n\t\t\tconst module = globalThis._VSCODE_NODE_MODULES['module'];\n\n\t\t\tconst filePath = URI.parse(scriptSrc).fsPath;\n\t\t\tconst content = fs.readFileSync(filePath).toString();\n\t\t\tconst scriptSource = module.wrap(content.replace(/^#!.*/, ''));\n\t\t\tconst script = new vm.Script(scriptSource);\n\t\t\tconst compileWrapper = script.runInThisContext();\n\t\t\tcompileWrapper.apply();\n\t\t\treturn this._defineCalls.pop();\n\n\t\t} catch (error) {\n\t\t\tthrow error;\n\t\t}\n\t}\n}\n\nconst cache = new Map>();\n\nlet _paths: Record = {};\nif (typeof globalThis.require === 'object') {\n\t_paths = (>globalThis.require).paths ?? {};\n}\n\n/**\n * Utility for importing an AMD node module. This util supports AMD and ESM contexts and should be used while the ESM adoption\n * is on its way.\n *\n * e.g. pass in `vscode-textmate/release/main.js`\n */\nexport async function importAMDNodeModule(nodeModuleName: string, pathInsideNodeModule: string, isBuilt?: boolean): Promise {\n\tif (isESM) {\n\n\t\tif (isBuilt === undefined) {\n\t\t\tconst product = globalThis._VSCODE_PRODUCT_JSON as unknown as IProductConfiguration;\n\t\t\tisBuilt = Boolean((product ?? (globalThis).vscode?.context?.configuration()?.product)?.commit);\n\t\t}\n\n\t\tif (_paths[nodeModuleName]) {\n\t\t\tnodeModuleName = _paths[nodeModuleName];\n\t\t}\n\n\t\tconst nodeModulePath = `${nodeModuleName}/${pathInsideNodeModule}`;\n\t\tif (cache.has(nodeModulePath)) {\n\t\t\treturn cache.get(nodeModulePath)!;\n\t\t}\n\t\tlet scriptSrc: string;\n\t\tif (/^\\w[\\w\\d+.-]*:\\/\\//.test(nodeModulePath)) {\n\t\t\t// looks like a URL\n\t\t\t// bit of a special case for: src/vs/workbench/services/languageDetection/browser/languageDetectionSimpleWorker.ts\n\t\t\tscriptSrc = nodeModulePath;\n\t\t} else {\n\t\t\tconst useASAR = (isBuilt && !platform.isWeb);\n\t\t\tconst actualNodeModulesPath = (useASAR ? nodeModulesAsarPath : nodeModulesPath);\n\t\t\tconst resourcePath: AppResourcePath = `${actualNodeModulesPath}/${nodeModulePath}`;\n\t\t\tscriptSrc = FileAccess.asBrowserUri(resourcePath).toString(true);\n\t\t}\n\t\tconst result = AMDModuleImporter.INSTANCE.load(scriptSrc);\n\t\tcache.set(nodeModulePath, result);\n\t\treturn result;\n\t} else {\n\t\treturn await import(nodeModuleName);\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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\t// --- identity\n\n\t/**\n\t * Compares two uris.\n\t *\n\t * @param uri1 Uri\n\t * @param uri2 Uri\n\t * @param ignoreFragment Ignore the fragment (defaults to `false`)\n\t */\n\tcompare(uri1: URI, uri2: URI, ignoreFragment?: boolean): number;\n\n\t/**\n\t * Tests whether two uris are equal\n\t *\n\t * @param uri1 Uri\n\t * @param uri2 Uri\n\t * @param ignoreFragment Ignore the fragment (defaults to `false`)\n\t */\n\tisEqual(uri1: URI | undefined, uri2: URI | undefined, ignoreFragment?: boolean): boolean;\n\n\t/**\n\t * Tests whether a `candidate` URI is a parent or equal of a given `base` URI.\n\t *\n\t * @param base A uri which is \"longer\" or at least same length as `parentCandidate`\n\t * @param parentCandidate A uri which is \"shorter\" or up to same length as `base`\n\t * @param ignoreFragment Ignore the fragment (defaults to `false`)\n\t */\n\tisEqualOrParent(base: URI, parentCandidate: URI, ignoreFragment?: boolean): boolean;\n\n\t/**\n\t * Creates a key from a resource URI to be used to resource comparison and for resource maps.\n\t * @see {@link ResourceMap}\n\t * @param uri Uri\n\t * @param ignoreFragment Ignore the fragment (defaults to `false`)\n\t */\n\tgetComparisonKey(uri: URI, ignoreFragment?: boolean): string;\n\n\t/**\n\t * Whether the casing of the path-component of the uri should be ignored.\n\t */\n\tignorePathCasing(uri: URI): boolean;\n\n\t// --- path math\n\n\tbasenameOrAuthority(resource: URI): string;\n\n\t/**\n\t * Returns the basename of the path component of an uri.\n\t * @param resource\n\t */\n\tbasename(resource: URI): string;\n\n\t/**\n\t * Returns the extension of the path component of an uri.\n\t * @param resource\n\t */\n\textname(resource: URI): string;\n\t/**\n\t * Return a URI representing the directory of a URI path.\n\t *\n\t * @param resource The input URI.\n\t * @returns The URI representing the directory of the input URI.\n\t */\n\tdirname(resource: URI): URI;\n\t/**\n\t * Join a URI path with path fragments and normalizes the resulting path.\n\t *\n\t * @param resource 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\tjoinPath(resource: URI, ...pathFragment: string[]): URI;\n\t/**\n\t * Normalizes the path part of a URI: Resolves `.` and `..` elements with directory names.\n\t *\n\t * @param resource The URI to normalize the path.\n\t * @returns The URI with the normalized path.\n\t */\n\tnormalizePath(resource: URI): URI;\n\t/**\n\t *\n\t * @param from\n\t * @param to\n\t */\n\trelativePath(from: URI, to: URI): string | undefined;\n\t/**\n\t * Resolves an absolute or relative path against a base URI.\n\t * The path can be relative or absolute posix or a Windows path\n\t */\n\tresolvePath(base: URI, path: string): URI;\n\n\t// --- misc\n\n\t/**\n\t * Returns true if the URI path is absolute.\n\t */\n\tisAbsolutePath(resource: URI): boolean;\n\t/**\n\t * Tests whether the two authorities are the same\n\t */\n\tisEqualAuthority(a1: string, a2: string): boolean;\n\t/**\n\t * Returns true if the URI path has a trailing path separator\n\t */\n\thasTrailingPathSeparator(resource: URI, sep?: string): boolean;\n\t/**\n\t * Removes a trailing path separator, if there's one.\n\t * Important: Doesn't remove the first slash, it would make the URI invalid\n\t */\n\tremoveTrailingPathSeparator(resource: URI, sep?: string): URI;\n\t/**\n\t * Adds a trailing path separator to the URI if there isn't one already.\n\t * For example, c:\\ would be unchanged, but c:\\users would become c:\\users\\\n\t */\n\taddTrailingPathSeparator(resource: URI, sep?: string): URI;\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\tignorePathCasing(uri: URI): boolean {\n\t\treturn this._ignorePathCasing(uri);\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//#endregion\n\nexport function distinctParents(items: T[], resourceAccessor: (item: T) => URI): T[] {\n\tconst distinctParents: T[] = [];\n\tfor (let i = 0; i < items.length; i++) {\n\t\tconst candidateResource = resourceAccessor(items[i]);\n\t\tif (items.some((otherItem, index) => {\n\t\t\tif (index === i) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn isEqualOrParent(candidateResource, resourceAccessor(otherItem));\n\t\t})) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tdistinctParents.push(items[i]);\n\t}\n\n\treturn distinctParents;\n}\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\nexport function toLocalResource(resource: URI, authority: string | undefined, localScheme: string): URI {\n\tif (authority) {\n\t\tlet path = resource.path;\n\t\tif (path && path[0] !== paths.posix.sep) {\n\t\t\tpath = paths.posix.sep + path;\n\t\t}\n\n\t\treturn resource.with({ scheme: localScheme, authority, path });\n\t}\n\n\treturn resource.with({ scheme: localScheme });\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { Disposable, DisposableMap, DisposableStore, IDisposable, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle';\nimport { extUri as defaultExtUri, IExtUri } from 'vs/base/common/resources';\nimport { URI } from 'vs/base/common/uri';\nimport { setTimeout0 } from 'vs/base/common/platform';\nimport { MicrotaskDelay } from './symbols';\nimport { Lazy } from 'vs/base/common/lazy';\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\n/**\n * Returns a promise that rejects with an {@CancellationError} as soon as the passed token is cancelled.\n * @see {@link raceCancellation}\n */\nexport function raceCancellationError(promise: Promise, token: CancellationToken): Promise {\n\treturn new Promise((resolve, reject) => {\n\t\tconst ref = token.onCancellationRequested(() => {\n\t\t\tref.dispose();\n\t\t\treject(new CancellationError());\n\t\t});\n\t\tpromise.then(resolve, reject).finally(() => ref.dispose());\n\t});\n}\n\n/**\n * Returns as soon as one of the promises resolves or rejects and cancels remaining promises\n */\nexport async function raceCancellablePromises(cancellablePromises: CancelablePromise[]): Promise {\n\tlet resolvedPromiseIndex = -1;\n\tconst promises = cancellablePromises.map((promise, index) => promise.then(result => { resolvedPromiseIndex = index; return result; }));\n\ttry {\n\t\tconst result = await Promise.race(promises);\n\t\treturn result;\n\t} finally {\n\t\tcancellablePromises.forEach((cancellablePromise, index) => {\n\t\t\tif (index !== resolvedPromiseIndex) {\n\t\t\t\tcancellablePromise.cancel();\n\t\t\t}\n\t\t});\n\t}\n}\n\nexport function raceTimeout(promise: Promise, timeout: number, onTimeout?: () => void): Promise {\n\tlet promiseResolve: ((value: T | undefined) => void) | undefined = undefined;\n\n\tconst timer = setTimeout(() => {\n\t\tpromiseResolve?.(undefined);\n\t\tonTimeout?.();\n\t}, timeout);\n\n\treturn Promise.race([\n\t\tpromise.finally(() => clearTimeout(timer)),\n\t\tnew Promise(resolve => promiseResolve = resolve)\n\t]);\n}\n\nexport function asPromise(callback: () => T | Thenable): Promise {\n\treturn new Promise((resolve, reject) => {\n\t\tconst item = callback();\n\t\tif (isThenable(item)) {\n\t\t\titem.then(resolve, reject);\n\t\t} else {\n\t\t\tresolve(item);\n\t\t}\n\t});\n}\n\n/**\n * Creates and returns a new promise, plus its `resolve` and `reject` callbacks.\n *\n * Replace with standardized [`Promise.withResolvers`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers) once it is supported\n */\nexport function promiseWithResolvers(): { promise: Promise; resolve: (value: T | PromiseLike) => void; reject: (err?: any) => void } {\n\tlet resolve: (value: T | PromiseLike) => void;\n\tlet reject: (reason?: any) => void;\n\tconst promise = new Promise((res, rej) => {\n\t\tresolve = res;\n\t\treject = rej;\n\t});\n\treturn { promise, resolve: resolve!, reject: reject! };\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\nexport class Sequencer {\n\n\tprivate current: Promise = Promise.resolve(null);\n\n\tqueue(promiseTask: ITask>): Promise {\n\t\treturn this.current = this.current.then(() => promiseTask(), () => promiseTask());\n\t}\n}\n\nexport class SequencerByKey {\n\n\tprivate promiseMap = new Map>();\n\n\tqueue(key: TKey, promiseTask: ITask>): Promise {\n\t\tconst runningPromise = this.promiseMap.get(key) ?? Promise.resolve();\n\t\tconst newPromise = runningPromise\n\t\t\t.catch(() => { })\n\t\t\t.then(promiseTask)\n\t\t\t.finally(() => {\n\t\t\t\tif (this.promiseMap.get(key) === newPromise) {\n\t\t\t\t\tthis.promiseMap.delete(key);\n\t\t\t\t}\n\t\t\t});\n\t\tthis.promiseMap.set(key, newPromise);\n\t\treturn newPromise;\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\tisTriggered(): boolean {\n\t\treturn this.delayer.isTriggered();\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\n/**\n * A barrier that is initially closed and then becomes opened permanently.\n */\nexport class Barrier {\n\tprivate _isOpen: boolean;\n\tprivate _promise: Promise;\n\tprivate _completePromise!: (v: boolean) => void;\n\n\tconstructor() {\n\t\tthis._isOpen = false;\n\t\tthis._promise = new Promise((c, e) => {\n\t\t\tthis._completePromise = c;\n\t\t});\n\t}\n\n\tisOpen(): boolean {\n\t\treturn this._isOpen;\n\t}\n\n\topen(): void {\n\t\tthis._isOpen = true;\n\t\tthis._completePromise(true);\n\t}\n\n\twait(): Promise {\n\t\treturn this._promise;\n\t}\n}\n\n/**\n * A barrier that is initially closed and then becomes opened permanently after a certain period of\n * time or when open is called explicitly\n */\nexport class AutoOpenBarrier extends Barrier {\n\n\tprivate readonly _timeout: any;\n\n\tconstructor(autoOpenTimeMs: number) {\n\t\tsuper();\n\t\tthis._timeout = setTimeout(() => this.open(), autoOpenTimeMs);\n\t}\n\n\toverride open(): void {\n\t\tclearTimeout(this._timeout);\n\t\tsuper.open();\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\n/**\n * Runs the provided list of promise factories in sequential order. The returned\n * promise will complete to an array of results from each promise.\n */\n\nexport function sequence(promiseFactories: ITask>[]): Promise {\n\tconst results: T[] = [];\n\tlet index = 0;\n\tconst len = promiseFactories.length;\n\n\tfunction next(): Promise | null {\n\t\treturn index < len ? promiseFactories[index++]() : null;\n\t}\n\n\tfunction thenHandler(result: any): Promise {\n\t\tif (result !== undefined && result !== null) {\n\t\t\tresults.push(result);\n\t\t}\n\n\t\tconst n = next();\n\t\tif (n) {\n\t\t\treturn n.then(thenHandler);\n\t\t}\n\n\t\treturn Promise.resolve(results);\n\t}\n\n\treturn Promise.resolve(null).then(thenHandler);\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\n/**\n * Returns the result of the first promise that matches the \"shouldStop\",\n * running all promises in parallel. Supports cancelable promises.\n */\nexport function firstParallel(promiseList: Promise[], shouldStop?: (t: T) => boolean, defaultValue?: T | null): Promise;\nexport function firstParallel(promiseList: Promise[], shouldStop: (t: T) => t is R, defaultValue?: R | null): Promise;\nexport function firstParallel(promiseList: Promise[], shouldStop: (t: T) => boolean = t => !!t, defaultValue: T | null = null) {\n\tif (promiseList.length === 0) {\n\t\treturn Promise.resolve(defaultValue);\n\t}\n\n\tlet todo = promiseList.length;\n\tconst finish = () => {\n\t\ttodo = -1;\n\t\tfor (const promise of promiseList) {\n\t\t\t(promise as Partial>).cancel?.();\n\t\t}\n\t};\n\n\treturn new Promise((resolve, reject) => {\n\t\tfor (const promise of promiseList) {\n\t\t\tpromise.then(result => {\n\t\t\t\tif (--todo >= 0 && shouldStop(result)) {\n\t\t\t\t\tfinish();\n\t\t\t\t\tresolve(result);\n\t\t\t\t} else if (todo === 0) {\n\t\t\t\t\tresolve(defaultValue);\n\t\t\t\t}\n\t\t\t})\n\t\t\t\t.catch(err => {\n\t\t\t\t\tif (--todo >= 0) {\n\t\t\t\t\t\tfinish();\n\t\t\t\t\t\treject(err);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t}\n\t});\n}\n\ninterface ILimitedTaskFactory {\n\tfactory: ITask>;\n\tc: (value: T | Promise) => void;\n\te: (error?: unknown) => void;\n}\n\nexport interface ILimiter {\n\n\treadonly size: number;\n\n\tqueue(factory: ITask>): Promise;\n\n\tclear(): void;\n}\n\n/**\n * A helper to queue N promises and run them all with a max degree of parallelism. The helper\n * ensures that at any time no more than M promises are running at the same time.\n */\nexport class Limiter implements ILimiter {\n\n\tprivate _size = 0;\n\tprivate _isDisposed = false;\n\tprivate runningPromises: number;\n\tprivate readonly maxDegreeOfParalellism: number;\n\tprivate readonly outstandingPromises: ILimitedTaskFactory[];\n\tprivate readonly _onDrained: Emitter;\n\n\tconstructor(maxDegreeOfParalellism: number) {\n\t\tthis.maxDegreeOfParalellism = maxDegreeOfParalellism;\n\t\tthis.outstandingPromises = [];\n\t\tthis.runningPromises = 0;\n\t\tthis._onDrained = new Emitter();\n\t}\n\n\t/**\n\t *\n\t * @returns A promise that resolved when all work is done (onDrained) or when\n\t * there is nothing to do\n\t */\n\twhenIdle(): Promise {\n\t\treturn this.size > 0\n\t\t\t? Event.toPromise(this.onDrained)\n\t\t\t: Promise.resolve();\n\t}\n\n\tget onDrained(): Event {\n\t\treturn this._onDrained.event;\n\t}\n\n\tget size(): number {\n\t\treturn this._size;\n\t}\n\n\tqueue(factory: ITask>): Promise {\n\t\tif (this._isDisposed) {\n\t\t\tthrow new Error('Object has been disposed');\n\t\t}\n\t\tthis._size++;\n\n\t\treturn new Promise((c, e) => {\n\t\t\tthis.outstandingPromises.push({ factory, c, e });\n\t\t\tthis.consume();\n\t\t});\n\t}\n\n\tprivate consume(): void {\n\t\twhile (this.outstandingPromises.length && this.runningPromises < this.maxDegreeOfParalellism) {\n\t\t\tconst iLimitedTask = this.outstandingPromises.shift()!;\n\t\t\tthis.runningPromises++;\n\n\t\t\tconst promise = iLimitedTask.factory();\n\t\t\tpromise.then(iLimitedTask.c, iLimitedTask.e);\n\t\t\tpromise.then(() => this.consumed(), () => this.consumed());\n\t\t}\n\t}\n\n\tprivate consumed(): void {\n\t\tif (this._isDisposed) {\n\t\t\treturn;\n\t\t}\n\t\tthis.runningPromises--;\n\t\tif (--this._size === 0) {\n\t\t\tthis._onDrained.fire();\n\t\t}\n\n\t\tif (this.outstandingPromises.length > 0) {\n\t\t\tthis.consume();\n\t\t}\n\t}\n\n\tclear(): void {\n\t\tif (this._isDisposed) {\n\t\t\tthrow new Error('Object has been disposed');\n\t\t}\n\t\tthis.outstandingPromises.length = 0;\n\t\tthis._size = this.runningPromises;\n\t}\n\n\tdispose(): void {\n\t\tthis._isDisposed = true;\n\t\tthis.outstandingPromises.length = 0; // stop further processing\n\t\tthis._size = 0;\n\t\tthis._onDrained.dispose();\n\t}\n}\n\n/**\n * A queue is handles one promise at a time and guarantees that at any time only one promise is executing.\n */\nexport class Queue extends Limiter {\n\n\tconstructor() {\n\t\tsuper(1);\n\t}\n}\n\n/**\n * Same as `Queue`, ensures that only 1 task is executed at the same time. The difference to `Queue` is that\n * there is only 1 task about to be scheduled next. As such, calling `queue` while a task is executing will\n * replace the currently queued task until it executes.\n *\n * As such, the returned promise may not be from the factory that is passed in but from the next factory that\n * is running after having called `queue`.\n */\nexport class LimitedQueue {\n\n\tprivate readonly sequentializer = new TaskSequentializer();\n\n\tprivate tasks = 0;\n\n\tqueue(factory: ITask>): Promise {\n\t\tif (!this.sequentializer.isRunning()) {\n\t\t\treturn this.sequentializer.run(this.tasks++, factory());\n\t\t}\n\n\t\treturn this.sequentializer.queue(() => {\n\t\t\treturn this.sequentializer.run(this.tasks++, factory());\n\t\t});\n\t}\n}\n\n/**\n * A helper to organize queues per resource. The ResourceQueue makes sure to manage queues per resource\n * by disposing them once the queue is empty.\n */\nexport class ResourceQueue implements IDisposable {\n\n\tprivate readonly queues = new Map>();\n\n\tprivate readonly drainers = new Set>();\n\n\tprivate drainListeners: DisposableMap | undefined = undefined;\n\tprivate drainListenerCount = 0;\n\n\tasync whenDrained(): Promise {\n\t\tif (this.isDrained()) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst promise = new DeferredPromise();\n\t\tthis.drainers.add(promise);\n\n\t\treturn promise.p;\n\t}\n\n\tprivate isDrained(): boolean {\n\t\tfor (const [, queue] of this.queues) {\n\t\t\tif (queue.size > 0) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tqueueSize(resource: URI, extUri: IExtUri = defaultExtUri): number {\n\t\tconst key = extUri.getComparisonKey(resource);\n\n\t\treturn this.queues.get(key)?.size ?? 0;\n\t}\n\n\tqueueFor(resource: URI, factory: ITask>, extUri: IExtUri = defaultExtUri): Promise {\n\t\tconst key = extUri.getComparisonKey(resource);\n\n\t\tlet queue = this.queues.get(key);\n\t\tif (!queue) {\n\t\t\tqueue = new Queue();\n\t\t\tconst drainListenerId = this.drainListenerCount++;\n\t\t\tconst drainListener = Event.once(queue.onDrained)(() => {\n\t\t\t\tqueue?.dispose();\n\t\t\t\tthis.queues.delete(key);\n\t\t\t\tthis.onDidQueueDrain();\n\n\t\t\t\tthis.drainListeners?.deleteAndDispose(drainListenerId);\n\n\t\t\t\tif (this.drainListeners?.size === 0) {\n\t\t\t\t\tthis.drainListeners.dispose();\n\t\t\t\t\tthis.drainListeners = undefined;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tif (!this.drainListeners) {\n\t\t\t\tthis.drainListeners = new DisposableMap();\n\t\t\t}\n\t\t\tthis.drainListeners.set(drainListenerId, drainListener);\n\n\t\t\tthis.queues.set(key, queue);\n\t\t}\n\n\t\treturn queue.queue(factory);\n\t}\n\n\tprivate onDidQueueDrain(): void {\n\t\tif (!this.isDrained()) {\n\t\t\treturn; // not done yet\n\t\t}\n\n\t\tthis.releaseDrainers();\n\t}\n\n\tprivate releaseDrainers(): void {\n\t\tfor (const drainer of this.drainers) {\n\t\t\tdrainer.complete();\n\t\t}\n\n\t\tthis.drainers.clear();\n\t}\n\n\tdispose(): void {\n\t\tfor (const [, queue] of this.queues) {\n\t\t\tqueue.dispose();\n\t\t}\n\n\t\tthis.queues.clear();\n\n\t\t// Even though we might still have pending\n\t\t// tasks queued, after the queues have been\n\t\t// disposed, we can no longer track them, so\n\t\t// we release drainers to prevent hanging\n\t\t// promises when the resource queue is being\n\t\t// disposed.\n\t\tthis.releaseDrainers();\n\n\t\tthis.drainListeners?.dispose();\n\t}\n}\n\nexport class TimeoutTimer implements IDisposable {\n\tprivate _token: any;\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}\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\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._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\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\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}\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\tflush(): void {\n\t\tif (this.isScheduled()) {\n\t\t\tthis.cancel();\n\t\t\tthis.doRun();\n\t\t}\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/**\n * Same as `RunOnceScheduler`, but doesn't count the time spent in sleep mode.\n * > **NOTE**: Only offers 1s resolution.\n *\n * When calling `setTimeout` with 3hrs, and putting the computer immediately to sleep\n * for 8hrs, `setTimeout` will fire **as soon as the computer wakes from sleep**. But\n * this scheduler will execute 3hrs **after waking the computer from sleep**.\n */\nexport class ProcessTimeRunOnceScheduler {\n\n\tprivate runner: (() => void) | null;\n\tprivate timeout: number;\n\n\tprivate counter: number;\n\tprivate intervalToken: any;\n\tprivate intervalHandler: () => void;\n\n\tconstructor(runner: () => void, delay: number) {\n\t\tif (delay % 1000 !== 0) {\n\t\t\tconsole.warn(`ProcessTimeRunOnceScheduler resolution is 1s, ${delay}ms is not a multiple of 1000ms.`);\n\t\t}\n\t\tthis.runner = runner;\n\t\tthis.timeout = delay;\n\t\tthis.counter = 0;\n\t\tthis.intervalToken = -1;\n\t\tthis.intervalHandler = this.onInterval.bind(this);\n\t}\n\n\tdispose(): void {\n\t\tthis.cancel();\n\t\tthis.runner = null;\n\t}\n\n\tcancel(): void {\n\t\tif (this.isScheduled()) {\n\t\t\tclearInterval(this.intervalToken);\n\t\t\tthis.intervalToken = -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\tif (delay % 1000 !== 0) {\n\t\t\tconsole.warn(`ProcessTimeRunOnceScheduler resolution is 1s, ${delay}ms is not a multiple of 1000ms.`);\n\t\t}\n\t\tthis.cancel();\n\t\tthis.counter = Math.ceil(delay / 1000);\n\t\tthis.intervalToken = setInterval(this.intervalHandler, 1000);\n\t}\n\n\t/**\n\t * Returns true if scheduled.\n\t */\n\tisScheduled(): boolean {\n\t\treturn this.intervalToken !== -1;\n\t}\n\n\tprivate onInterval() {\n\t\tthis.counter--;\n\t\tif (this.counter > 0) {\n\t\t\t// still need to wait\n\t\t\treturn;\n\t\t}\n\n\t\t// time elapsed\n\t\tclearInterval(this.intervalToken);\n\t\tthis.intervalToken = -1;\n\t\tthis.runner?.();\n\t}\n}\n\nexport class RunOnceWorker extends RunOnceScheduler {\n\n\tprivate units: T[] = [];\n\n\tconstructor(runner: (units: T[]) => void, timeout: number) {\n\t\tsuper(runner, timeout);\n\t}\n\n\twork(unit: T): void {\n\t\tthis.units.push(unit);\n\n\t\tif (!this.isScheduled()) {\n\t\t\tthis.schedule();\n\t\t}\n\t}\n\n\tprotected override doRun(): void {\n\t\tconst units = this.units;\n\t\tthis.units = [];\n\n\t\tthis.runner?.(units);\n\t}\n\n\toverride dispose(): void {\n\t\tthis.units = [];\n\n\t\tsuper.dispose();\n\t}\n}\n\nexport interface IThrottledWorkerOptions {\n\n\t/**\n\t * maximum of units the worker will pass onto handler at once\n\t */\n\tmaxWorkChunkSize: number;\n\n\t/**\n\t * maximum of units the worker will keep in memory for processing\n\t */\n\tmaxBufferedWork: number | undefined;\n\n\t/**\n\t * delay before processing the next round of chunks when chunk size exceeds limits\n\t */\n\tthrottleDelay: number;\n}\n\n/**\n * The `ThrottledWorker` will accept units of work `T`\n * to handle. The contract is:\n * * there is a maximum of units the worker can handle at once (via `maxWorkChunkSize`)\n * * there is a maximum of units the worker will keep in memory for processing (via `maxBufferedWork`)\n * * after having handled `maxWorkChunkSize` units, the worker needs to rest (via `throttleDelay`)\n */\nexport class ThrottledWorker extends Disposable {\n\n\tprivate readonly pendingWork: T[] = [];\n\n\tprivate readonly throttler = this._register(new MutableDisposable());\n\tprivate disposed = false;\n\n\tconstructor(\n\t\tprivate options: IThrottledWorkerOptions,\n\t\tprivate readonly handler: (units: T[]) => void\n\t) {\n\t\tsuper();\n\t}\n\n\t/**\n\t * The number of work units that are pending to be processed.\n\t */\n\tget pending(): number { return this.pendingWork.length; }\n\n\t/**\n\t * Add units to be worked on. Use `pending` to figure out\n\t * how many units are not yet processed after this method\n\t * was called.\n\t *\n\t * @returns whether the work was accepted or not. If the\n\t * worker is disposed, it will not accept any more work.\n\t * If the number of pending units would become larger\n\t * than `maxPendingWork`, more work will also not be accepted.\n\t */\n\twork(units: readonly T[]): boolean {\n\t\tif (this.disposed) {\n\t\t\treturn false; // work not accepted: disposed\n\t\t}\n\n\t\t// Check for reaching maximum of pending work\n\t\tif (typeof this.options.maxBufferedWork === 'number') {\n\n\t\t\t// Throttled: simple check if pending + units exceeds max pending\n\t\t\tif (this.throttler.value) {\n\t\t\t\tif (this.pending + units.length > this.options.maxBufferedWork) {\n\t\t\t\t\treturn false; // work not accepted: too much pending work\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Unthrottled: same as throttled, but account for max chunk getting\n\t\t\t// worked on directly without being pending\n\t\t\telse {\n\t\t\t\tif (this.pending + units.length - this.options.maxWorkChunkSize > this.options.maxBufferedWork) {\n\t\t\t\t\treturn false; // work not accepted: too much pending work\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Add to pending units first\n\t\tfor (const unit of units) {\n\t\t\tthis.pendingWork.push(unit);\n\t\t}\n\n\t\t// If not throttled, start working directly\n\t\t// Otherwise, when the throttle delay has\n\t\t// past, pending work will be worked again.\n\t\tif (!this.throttler.value) {\n\t\t\tthis.doWork();\n\t\t}\n\n\t\treturn true; // work accepted\n\t}\n\n\tprivate doWork(): void {\n\n\t\t// Extract chunk to handle and handle it\n\t\tthis.handler(this.pendingWork.splice(0, this.options.maxWorkChunkSize));\n\n\t\t// If we have remaining work, schedule it after a delay\n\t\tif (this.pendingWork.length > 0) {\n\t\t\tthis.throttler.value = new RunOnceScheduler(() => {\n\t\t\t\tthis.throttler.clear();\n\n\t\t\t\tthis.doWork();\n\t\t\t}, this.options.throttleDelay);\n\t\t\tthis.throttler.value.schedule();\n\t\t}\n\t}\n\n\toverride dispose(): void {\n\t\tsuper.dispose();\n\n\t\tthis.disposed = true;\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\nexport async function retry(task: ITask>, delay: number, retries: number): Promise {\n\tlet lastError: Error | undefined;\n\n\tfor (let i = 0; i < retries; i++) {\n\t\ttry {\n\t\t\treturn await task();\n\t\t} catch (error) {\n\t\t\tlastError = error;\n\n\t\t\tawait timeout(delay);\n\t\t}\n\t}\n\n\tthrow lastError;\n}\n\n//#region Task Sequentializer\n\ninterface IRunningTask {\n\treadonly taskId: number;\n\treadonly cancel: () => void;\n\treadonly promise: Promise;\n}\n\ninterface IQueuedTask {\n\treadonly promise: Promise;\n\treadonly promiseResolve: () => void;\n\treadonly promiseReject: (error: Error) => void;\n\trun: ITask>;\n}\n\nexport interface ITaskSequentializerWithRunningTask {\n\treadonly running: Promise;\n}\n\nexport interface ITaskSequentializerWithQueuedTask {\n\treadonly queued: IQueuedTask;\n}\n\n/**\n * @deprecated use `LimitedQueue` instead for an easier to use API\n */\nexport class TaskSequentializer {\n\n\tprivate _running?: IRunningTask;\n\tprivate _queued?: IQueuedTask;\n\n\tisRunning(taskId?: number): this is ITaskSequentializerWithRunningTask {\n\t\tif (typeof taskId === 'number') {\n\t\t\treturn this._running?.taskId === taskId;\n\t\t}\n\n\t\treturn !!this._running;\n\t}\n\n\tget running(): Promise | undefined {\n\t\treturn this._running?.promise;\n\t}\n\n\tcancelRunning(): void {\n\t\tthis._running?.cancel();\n\t}\n\n\trun(taskId: number, promise: Promise, onCancel?: () => void,): Promise {\n\t\tthis._running = { taskId, cancel: () => onCancel?.(), promise };\n\n\t\tpromise.then(() => this.doneRunning(taskId), () => this.doneRunning(taskId));\n\n\t\treturn promise;\n\t}\n\n\tprivate doneRunning(taskId: number): void {\n\t\tif (this._running && taskId === this._running.taskId) {\n\n\t\t\t// only set running to done if the promise finished that is associated with that taskId\n\t\t\tthis._running = undefined;\n\n\t\t\t// schedule the queued task now that we are free if we have any\n\t\t\tthis.runQueued();\n\t\t}\n\t}\n\n\tprivate runQueued(): void {\n\t\tif (this._queued) {\n\t\t\tconst queued = this._queued;\n\t\t\tthis._queued = undefined;\n\n\t\t\t// Run queued task and complete on the associated promise\n\t\t\tqueued.run().then(queued.promiseResolve, queued.promiseReject);\n\t\t}\n\t}\n\n\t/**\n\t * Note: the promise to schedule as next run MUST itself call `run`.\n\t * Otherwise, this sequentializer will report `false` for `isRunning`\n\t * even when this task is running. Missing this detail means that\n\t * suddenly multiple tasks will run in parallel.\n\t */\n\tqueue(run: ITask>): Promise {\n\n\t\t// this is our first queued task, so we create associated promise with it\n\t\t// so that we can return a promise that completes when the task has\n\t\t// completed.\n\t\tif (!this._queued) {\n\t\t\tconst { promise, resolve: promiseResolve, reject: promiseReject } = promiseWithResolvers();\n\t\t\tthis._queued = {\n\t\t\t\trun,\n\t\t\t\tpromise,\n\t\t\t\tpromiseResolve: promiseResolve!,\n\t\t\t\tpromiseReject: promiseReject!\n\t\t\t};\n\t\t}\n\n\t\t// we have a previous queued task, just overwrite it\n\t\telse {\n\t\t\tthis._queued.run = run;\n\t\t}\n\n\t\treturn this._queued.promise;\n\t}\n\n\thasQueued(): this is ITaskSequentializerWithQueuedTask {\n\t\treturn !!this._queued;\n\t}\n\n\tasync join(): Promise {\n\t\treturn this._queued?.promise ?? this._running?.promise;\n\t}\n}\n\n//#endregion\n\n//#region\n\n/**\n * The `IntervalCounter` allows to count the number\n * of calls to `increment()` over a duration of\n * `interval`. This utility can be used to conditionally\n * throttle a frequent task when a certain threshold\n * is reached.\n */\nexport class IntervalCounter {\n\n\tprivate lastIncrementTime = 0;\n\n\tprivate value = 0;\n\n\tconstructor(private readonly interval: number, private readonly nowFn = () => Date.now()) { }\n\n\tincrement(): number {\n\t\tconst now = this.nowFn();\n\n\t\t// We are outside of the range of `interval` and as such\n\t\t// start counting from 0 and remember the time\n\t\tif (now - this.lastIncrementTime > this.interval) {\n\t\t\tthis.lastIncrementTime = now;\n\t\t\tthis.value = 0;\n\t\t}\n\n\t\tthis.value++;\n\n\t\treturn this.value;\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 isResolved() {\n\t\treturn this.outcome?.outcome === DeferredOutcome.Resolved;\n\t}\n\n\tpublic get isSettled() {\n\t\treturn !!this.outcome;\n\t}\n\n\tpublic get value() {\n\t\treturn this.outcome?.outcome === DeferredOutcome.Resolved ? this.outcome?.value : undefined;\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\nexport class StatefulPromise {\n\tprivate _value: T | undefined = undefined;\n\tget value(): T | undefined { return this._value; }\n\n\tprivate _error: unknown = undefined;\n\tget error(): unknown { return this._error; }\n\n\tprivate _isResolved = false;\n\tget isResolved() { return this._isResolved; }\n\n\tpublic readonly promise: Promise;\n\n\tconstructor(promise: Promise) {\n\t\tthis.promise = promise.then(\n\t\t\tvalue => {\n\t\t\t\tthis._value = value;\n\t\t\t\tthis._isResolved = true;\n\t\t\t\treturn value;\n\t\t\t},\n\t\t\terror => {\n\t\t\t\tthis._error = error;\n\t\t\t\tthis._isResolved = true;\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t);\n\t}\n\n\t/**\n\t * Returns the resolved value.\n\t * Throws if the promise is not resolved yet.\n\t */\n\tpublic requireValue(): T {\n\t\tif (!this._isResolved) {\n\t\t\tthrow new BugIndicatingError('Promise is not resolved yet');\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\nexport class LazyStatefulPromise {\n\tprivate readonly _promise = new Lazy(() => new StatefulPromise(this._compute()));\n\n\tconstructor(\n\t\tprivate readonly _compute: () => Promise,\n\t) { }\n\n\t/**\n\t * Returns the resolved value.\n\t * Throws if the promise is not resolved yet.\n\t */\n\tpublic requireValue(): T {\n\t\treturn this._promise.value.requireValue();\n\t}\n\n\t/**\n\t * Returns the promise (and triggers a computation of the promise if not yet done so).\n\t */\n\tpublic getPromise(): Promise {\n\t\treturn this._promise.value.promise;\n\t}\n\n\t/**\n\t * Reads the current value without triggering a computation of the promise.\n\t */\n\tpublic get currentValue(): T | undefined {\n\t\treturn this._promise.rawValue?.value;\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 _onStateChanged: Emitter;\n\n\tconstructor(executor: AsyncIterableExecutor) {\n\t\tthis._state = AsyncIterableSourceState.Initial;\n\t\tthis._results = [];\n\t\tthis._error = null;\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};\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\nexport class AsyncIterableSource {\n\n\tprivate readonly _deferred = new DeferredPromise();\n\tprivate readonly _asyncIterable: AsyncIterableObject;\n\n\tprivate _errorFn: (error: Error) => void;\n\tprivate _emitFn: (item: T) => void;\n\n\tconstructor() {\n\t\tthis._asyncIterable = new AsyncIterableObject(emitter => {\n\n\t\t\tif (earlyError) {\n\t\t\t\temitter.reject(earlyError);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (earlyItems) {\n\t\t\t\temitter.emitMany(earlyItems);\n\t\t\t}\n\t\t\tthis._errorFn = (error: Error) => emitter.reject(error);\n\t\t\tthis._emitFn = (item: T) => emitter.emitOne(item);\n\t\t\treturn this._deferred.p;\n\t\t});\n\n\t\tlet earlyError: Error | undefined;\n\t\tlet earlyItems: T[] | undefined;\n\n\t\tthis._emitFn = (item: T) => {\n\t\t\tif (!earlyItems) {\n\t\t\t\tearlyItems = [];\n\t\t\t}\n\t\t\tearlyItems.push(item);\n\t\t};\n\t\tthis._errorFn = (error: Error) => {\n\t\t\tif (!earlyError) {\n\t\t\t\tearlyError = error;\n\t\t\t}\n\t\t};\n\t}\n\n\tget asyncIterable(): AsyncIterableObject {\n\t\treturn this._asyncIterable;\n\t}\n\n\tresolve(): void {\n\t\tthis._deferred.complete();\n\t}\n\n\treject(error: Error): void {\n\t\tthis._errorFn(error);\n\t\tthis._deferred.complete();\n\t}\n\n\temitOne(item: T): void {\n\t\tthis._emitFn(item);\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 * 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, TimeoutTimer, _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, Schemas } 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') {\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 addDisposableGenericMouseMoveListener(node: EventTarget, handler: (event: any) => void, useCapture?: boolean): IDisposable {\n\treturn addDisposableListener(node, platform.isIOS && BrowserFeatures.pointerEvents ? EventType.POINTER_MOVE : EventType.MOUSE_MOVE, 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 function disposableWindowInterval(targetWindow: Window, handler: () => void | boolean /* stop interval */ | Promise, interval: number, iterations?: number): IDisposable {\n\tlet iteration = 0;\n\tconst timer = targetWindow.setInterval(() => {\n\t\titeration++;\n\t\tif ((typeof iterations === 'number' && iteration >= iterations) || handler() === true) {\n\t\t\tdisposable.dispose();\n\t\t}\n\t}, interval);\n\tconst disposable = toDisposable(() => {\n\t\ttargetWindow.clearInterval(timer);\n\t});\n\treturn disposable;\n}\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 measure(targetWindow: Window, callback: () => void): IDisposable {\n\treturn scheduleAtNextAnimationFrame(targetWindow, callback, 10000 /* must be early */);\n}\n\nexport function modify(targetWindow: Window, callback: () => void): IDisposable {\n\treturn scheduleAtNextAnimationFrame(targetWindow, callback, -10000 /* must be late */);\n}\n\n/**\n * Add a throttled listener. `handler` is fired at most every 8.33333ms or with the next animation frame (if browser supports it).\n */\nexport interface IEventMerger {\n\t(lastEvent: R | null, currentEvent: E): R;\n}\n\nconst MINIMUM_TIME_MS = 8;\nconst DEFAULT_EVENT_MERGER: IEventMerger = function (lastEvent: Event | null, currentEvent: Event) {\n\treturn currentEvent;\n};\n\nclass TimeoutThrottledDomListener extends Disposable {\n\n\tconstructor(node: any, type: string, handler: (event: R) => void, eventMerger: IEventMerger = DEFAULT_EVENT_MERGER, minimumTimeMs: number = MINIMUM_TIME_MS) {\n\t\tsuper();\n\n\t\tlet lastEvent: R | null = null;\n\t\tlet lastHandlerTime = 0;\n\t\tconst timeout = this._register(new TimeoutTimer());\n\n\t\tconst invokeHandler = () => {\n\t\t\tlastHandlerTime = (new Date()).getTime();\n\t\t\thandler(lastEvent);\n\t\t\tlastEvent = null;\n\t\t};\n\n\t\tthis._register(addDisposableListener(node, type, (e) => {\n\n\t\t\tlastEvent = eventMerger(lastEvent, e);\n\t\t\tconst elapsedTime = (new Date()).getTime() - lastHandlerTime;\n\n\t\t\tif (elapsedTime >= minimumTimeMs) {\n\t\t\t\ttimeout.cancel();\n\t\t\t\tinvokeHandler();\n\t\t\t} else {\n\t\t\t\ttimeout.setIfNotSet(invokeHandler, minimumTimeMs - elapsedTime);\n\t\t\t}\n\t\t}));\n\t}\n}\n\nexport function addDisposableThrottledListener(node: any, type: string, handler: (event: R) => void, eventMerger?: IEventMerger, minimumTimeMs?: number): IDisposable {\n\treturn new TimeoutThrottledDomListener(node, type, handler, eventMerger, minimumTimeMs);\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\nexport function position(element: HTMLElement, top: number, right?: number, bottom?: number, left?: number, position: string = 'absolute'): void {\n\tif (typeof top === 'number') {\n\t\telement.style.top = `${top}px`;\n\t}\n\n\tif (typeof right === 'number') {\n\t\telement.style.right = `${right}px`;\n\t}\n\n\tif (typeof bottom === 'number') {\n\t\telement.style.bottom = `${bottom}px`;\n\t}\n\n\tif (typeof left === 'number') {\n\t\telement.style.left = `${left}px`;\n\t}\n\n\telement.style.position = position;\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\nexport function getTotalScrollWidth(element: HTMLElement): number {\n\tconst margin = SizeUtils.getMarginLeft(element) + SizeUtils.getMarginRight(element);\n\treturn element.scrollWidth + margin;\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// Gets the left coordinate of the specified element relative to the specified parent.\nfunction getRelativeLeft(element: HTMLElement, parent: HTMLElement): number {\n\tif (element === null) {\n\t\treturn 0;\n\t}\n\n\tconst elementPosition = getTopLeftOffset(element);\n\tconst parentPosition = getTopLeftOffset(parent);\n\treturn elementPosition.left - parentPosition.left;\n}\n\nexport function getLargestChildWidth(parent: HTMLElement, children: HTMLElement[]): number {\n\tconst childWidths = children.map((child) => {\n\t\treturn Math.max(getTotalScrollWidth(child), getTotalWidth(child)) + getRelativeLeft(child, parent) || 0;\n\t});\n\tconst maxWidth = Math.max(...childWidths);\n\treturn maxWidth;\n}\n\n// ----------------------------------------------------------------------------------------\n\nexport function isAncestor(testChild: Node | null, testAncestor: Node | null): boolean {\n\treturn Boolean(testAncestor?.contains(testChild));\n}\n\nconst parentFlowToDataKey = 'parentFlowToElementId';\n\n/**\n * Set an explicit parent to use for nodes that are not part of the\n * regular dom structure.\n */\nexport function setParentFlowTo(fromChildElement: HTMLElement, toParentElement: Element): void {\n\tfromChildElement.dataset[parentFlowToDataKey] = toParentElement.id;\n}\n\nfunction getParentFlowToElement(node: HTMLElement): HTMLElement | null {\n\tconst flowToParentId = node.dataset[parentFlowToDataKey];\n\tif (typeof flowToParentId === 'string') {\n\t\treturn node.ownerDocument.getElementById(flowToParentId);\n\t}\n\treturn null;\n}\n\n/**\n * Check if `testAncestor` is an ancestor of `testChild`, observing the explicit\n * parents set by `setParentFlowTo`.\n */\nexport function isAncestorUsingFlowTo(testChild: Node, testAncestor: Node): boolean {\n\tlet node: Node | null = testChild;\n\twhile (node) {\n\t\tif (node === testAncestor) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (node instanceof HTMLElement) {\n\t\t\tconst flowToParentElement = getParentFlowToElement(node);\n\t\t\tif (flowToParentElement) {\n\t\t\t\tnode = flowToParentElement;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\tnode = node.parentNode;\n\t}\n\n\treturn false;\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 whether the element is in the active `document`. The active\n * document has focus or will be the main windows document.\n */\nexport function isActiveDocument(element: Element): boolean {\n\treturn element.ownerDocument === getActiveDocument();\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\nexport function focusWindow(element: Node): void {\n\tconst window = getWindow(element);\n\tif (!window.document.hasFocus()) {\n\t\twindow.focus();\n\t}\n}\n\nconst globalStylesheets = new Map>();\n\nexport function isGlobalStylesheet(node: Node): boolean {\n\treturn globalStylesheets.has(node as HTMLStyleElement);\n}\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\nexport function cloneGlobalStylesheets(targetWindow: Window): IDisposable {\n\tconst disposables = new DisposableStore();\n\n\tfor (const [globalStylesheet, clonedGlobalStylesheets] of globalStylesheets) {\n\t\tdisposables.add(cloneGlobalStyleSheet(globalStylesheet, clonedGlobalStylesheets, targetWindow));\n\t}\n\n\treturn disposables;\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\nexport function createMetaElement(container: HTMLElement = mainWindow.document.head): HTMLMetaElement {\n\treturn createHeadElement('meta', container) as HTMLMetaElement;\n}\n\nexport function createLinkElement(container: HTMLElement = mainWindow.document.head): HTMLLinkElement {\n\treturn createHeadElement('link', container) as HTMLLinkElement;\n}\n\nfunction createHeadElement(tagName: string, container: HTMLElement = mainWindow.document.head): HTMLElement {\n\tconst element = document.createElement(tagName);\n\tcontainer.appendChild(element);\n\treturn element;\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 function isPointerEvent(e: unknown): e is PointerEvent {\n\t// eslint-disable-next-line no-restricted-syntax\n\treturn e instanceof PointerEvent || e instanceof getWindow(e as UIEvent).PointerEvent;\n}\n\nexport function isDragEvent(e: unknown): e is DragEvent {\n\t// eslint-disable-next-line no-restricted-syntax\n\treturn e instanceof DragEvent || e instanceof getWindow(e as UIEvent).DragEvent;\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\trefreshState(): void;\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\trefreshState() {\n\t\tthis._refreshStateHandler();\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 join(nodes: Node[], separator: Node | string): Node[] {\n\tconst result: Node[] = [];\n\n\tnodes.forEach((node, index) => {\n\t\tif (index > 0) {\n\t\t\tif (separator instanceof Node) {\n\t\t\t\tresult.push(separator.cloneNode());\n\t\t\t} else {\n\t\t\t\tresult.push(document.createTextNode(separator));\n\t\t\t}\n\t\t}\n\n\t\tresult.push(node);\n\t});\n\n\treturn result;\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\nfunction findParentWithAttribute(node: Node | null, attribute: string): HTMLElement | null {\n\twhile (node && node.nodeType === node.ELEMENT_NODE) {\n\t\tif (node instanceof HTMLElement && node.hasAttribute(attribute)) {\n\t\t\treturn node;\n\t\t}\n\n\t\tnode = node.parentNode;\n\t}\n\n\treturn null;\n}\n\nexport function removeTabIndexAndUpdateFocus(node: HTMLElement): void {\n\tif (!node || !node.hasAttribute('tabIndex')) {\n\t\treturn;\n\t}\n\n\t// If we are the currently focused element and tabIndex is removed,\n\t// standard DOM behavior is to move focus to the element. We\n\t// typically never want that, rather put focus to the closest element\n\t// in the hierarchy of the parent DOM nodes.\n\tif (node.ownerDocument.activeElement === node) {\n\t\tconst parentFocusable = findParentWithAttribute(node.parentElement, 'tabIndex');\n\t\tparentFocusable?.focus();\n\t}\n\n\tnode.removeAttribute('tabindex');\n}\n\nexport function finalHandler(fn: (event: T) => any): (event: T) => any {\n\treturn e => {\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t\tfn(e);\n\t};\n}\n\nexport function domContentLoaded(targetWindow: Window): Promise {\n\treturn new Promise(resolve => {\n\t\tconst readyState = targetWindow.document.readyState;\n\t\tif (readyState === 'complete' || (targetWindow.document && targetWindow.document.body !== null)) {\n\t\t\tresolve(undefined);\n\t\t} else {\n\t\t\tconst listener = () => {\n\t\t\t\ttargetWindow.window.removeEventListener('DOMContentLoaded', listener, false);\n\t\t\t\tresolve();\n\t\t\t};\n\n\t\t\ttargetWindow.window.addEventListener('DOMContentLoaded', listener, false);\n\t\t}\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\n/**\n * Open a new window in a popup. 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 * Note: this does not set {@link window.opener} to null. This is to allow the opened popup to\n * be able to use {@link window.close} to close itself. Because of this, you should only use\n * this function on urls that you trust.\n *\n * In otherwords, you should almost always use {@link windowOpenNoOpener} instead of this function.\n */\nconst popupWidth = 780, popupHeight = 640;\nexport function windowOpenPopup(url: string): void {\n\tconst left = Math.floor(mainWindow.screenLeft + mainWindow.innerWidth / 2 - popupWidth / 2);\n\tconst top = Math.floor(mainWindow.screenTop + mainWindow.innerHeight / 2 - popupHeight / 2);\n\tmainWindow.open(\n\t\turl,\n\t\t'_blank',\n\t\t`width=${popupWidth},height=${popupHeight},top=${top},left=${left}`\n\t);\n}\n\n/**\n * Attempts to open a window and returns whether it succeeded. This technique is\n * not appropriate in certain contexts, like for example when the JS context is\n * executing inside a sandboxed iframe. If it is not necessary to know if the\n * browser blocked the new window, use {@link windowOpenNoOpener}.\n *\n * See https://github.com/microsoft/monaco-editor/issues/601\n * See https://github.com/microsoft/monaco-editor/issues/2474\n * See https://mathiasbynens.github.io/rel-noopener/\n *\n * @param url the url to open\n * @param noOpener whether or not to set the {@link window.opener} to null. You should leave the default\n * (true) unless you trust the url that is being opened.\n * @returns boolean indicating if the {@link window.open} call succeeded\n */\nexport function windowOpenWithSuccess(url: string, noOpener = true): boolean {\n\tconst newTab = mainWindow.open();\n\tif (newTab) {\n\t\tif (noOpener) {\n\t\t\t// see `windowOpenNoOpener` for details on why this is important\n\t\t\t(newTab as any).opener = null;\n\t\t}\n\t\tnewTab.location.href = url;\n\t\treturn true;\n\t}\n\treturn false;\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\nexport function triggerDownload(dataOrUri: Uint8Array | URI, name: string): void {\n\n\t// If the data is provided as Buffer, we create a\n\t// blob URL out of it to produce a valid link\n\tlet url: string;\n\tif (URI.isUri(dataOrUri)) {\n\t\turl = dataOrUri.toString(true);\n\t} else {\n\t\tconst blob = new Blob([dataOrUri]);\n\t\turl = URL.createObjectURL(blob);\n\n\t\t// Ensure to free the data from DOM eventually\n\t\tsetTimeout(() => URL.revokeObjectURL(url));\n\t}\n\n\t// In order to download from the browser, the only way seems\n\t// to be creating a
    element with download attribute that\n\t// points to the file to download.\n\t// See also https://developers.google.com/web/updates/2011/08/Downloading-resources-in-HTML5-a-download\n\tconst activeWindow = getActiveWindow();\n\tconst anchor = document.createElement('a');\n\tactiveWindow.document.body.appendChild(anchor);\n\tanchor.download = name;\n\tanchor.href = url;\n\tanchor.click();\n\n\t// Ensure to remove the element from DOM eventually\n\tsetTimeout(() => activeWindow.document.body.removeChild(anchor));\n}\n\nexport function triggerUpload(): Promise {\n\treturn new Promise(resolve => {\n\n\t\t// In order to upload to the browser, create a\n\t\t// input element of type `file` and click it\n\t\t// to gather the selected files\n\t\tconst activeWindow = getActiveWindow();\n\t\tconst input = document.createElement('input');\n\t\tactiveWindow.document.body.appendChild(input);\n\t\tinput.type = 'file';\n\t\tinput.multiple = true;\n\n\t\t// Resolve once the input event has fired once\n\t\tevent.Event.once(event.Event.fromDOMEventEmitter(input, 'input'))(() => {\n\t\t\tresolve(input.files ?? undefined);\n\t\t});\n\n\t\tinput.click();\n\n\t\t// Ensure to remove the element from DOM eventually\n\t\tsetTimeout(() => activeWindow.document.body.removeChild(input));\n\t});\n}\n\nexport enum DetectedFullscreenMode {\n\n\t/**\n\t * The document is fullscreen, e.g. because an element\n\t * in the document requested to be fullscreen.\n\t */\n\tDOCUMENT = 1,\n\n\t/**\n\t * The browser is fullscreen, e.g. because the user enabled\n\t * native window fullscreen for it.\n\t */\n\tBROWSER\n}\n\nexport interface IDetectedFullscreen {\n\n\t/**\n\t * Figure out if the document is fullscreen or the browser.\n\t */\n\tmode: DetectedFullscreenMode;\n\n\t/**\n\t * Whether we know for sure that we are in fullscreen mode or\n\t * it is a guess.\n\t */\n\tguess: boolean;\n}\n\nexport function detectFullscreen(targetWindow: Window): IDetectedFullscreen | null {\n\n\t// Browser fullscreen: use DOM APIs to detect\n\tif (targetWindow.document.fullscreenElement || (targetWindow.document).webkitFullscreenElement || (targetWindow.document).webkitIsFullScreen) {\n\t\treturn { mode: DetectedFullscreenMode.DOCUMENT, guess: false };\n\t}\n\n\t// There is no standard way to figure out if the browser\n\t// is using native fullscreen. Via checking on screen\n\t// height and comparing that to window height, we can guess\n\t// it though.\n\n\tif (targetWindow.innerHeight === targetWindow.screen.height) {\n\t\t// if the height of the window matches the screen height, we can\n\t\t// safely assume that the browser is fullscreen because no browser\n\t\t// chrome is taking height away (e.g. like toolbars).\n\t\treturn { mode: DetectedFullscreenMode.BROWSER, guess: false };\n\t}\n\n\tif (platform.isMacintosh || platform.isLinux) {\n\t\t// macOS and Linux do not properly report `innerHeight`, only Windows does\n\t\tif (targetWindow.outerHeight === targetWindow.screen.height && targetWindow.outerWidth === targetWindow.screen.width) {\n\t\t\t// if the height of the browser matches the screen height, we can\n\t\t\t// only guess that we are in fullscreen. It is also possible that\n\t\t\t// the user has turned off taskbars in the OS and the browser is\n\t\t\t// simply able to span the entire size of the screen.\n\t\t\treturn { mode: DetectedFullscreenMode.BROWSER, guess: true };\n\t\t}\n\t}\n\n\t// Not in fullscreen\n\treturn null;\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\nconst defaultSafeProtocols = [\n\tSchemas.http,\n\tSchemas.https,\n\tSchemas.command,\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\n/**\n * Sanitizes the given `value` and reset the given `node` with it.\n */\nexport function safeInnerHtml(node: HTMLElement, value: string): void {\n\tconst hook = hookDomPurifyHrefAndSrcSanitizer(defaultSafeProtocols);\n\ttry {\n\t\tconst html = dompurify.sanitize(value, defaultDomPurifyConfig);\n\t\tnode.innerHTML = html as unknown as string;\n\t} finally {\n\t\thook.dispose();\n\t}\n}\n\n/**\n * Convert a Unicode string to a string in which each 16-bit unit occupies only one byte\n *\n * From https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/btoa\n */\nfunction toBinary(str: string): string {\n\tconst codeUnits = new Uint16Array(str.length);\n\tfor (let i = 0; i < codeUnits.length; i++) {\n\t\tcodeUnits[i] = str.charCodeAt(i);\n\t}\n\tlet binary = '';\n\tconst uint8array = new Uint8Array(codeUnits.buffer);\n\tfor (let i = 0; i < uint8array.length; i++) {\n\t\tbinary += String.fromCharCode(uint8array[i]);\n\t}\n\treturn binary;\n}\n\n/**\n * Version of the global `btoa` function that handles multi-byte characters instead\n * of throwing an exception.\n */\nexport function multibyteAwareBtoa(str: string): string {\n\treturn btoa(toBinary(str));\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\tget isModifierPressed(): boolean {\n\t\treturn this._keyStatus.altKey || this._keyStatus.ctrlKey || this._keyStatus.metaKey || this._keyStatus.shiftKey;\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 function getCookieValue(name: string): string | undefined {\n\tconst match = document.cookie.match('(^|[^;]+)\\\\s*' + name + '\\\\s*=\\\\s*([^;]+)'); // See https://stackoverflow.com/a/25490531\n\n\treturn match ? match.pop() : undefined;\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\nexport function copyAttributes(from: Element, to: Element, filter?: string[]): void {\n\tfor (const { name, value } of from.attributes) {\n\t\tif (!filter || filter.includes(name)) {\n\t\t\tto.setAttribute(name, value);\n\t\t}\n\t}\n}\n\nfunction copyAttribute(from: Element, to: Element, name: string): void {\n\tconst value = from.getAttribute(name);\n\tif (value) {\n\t\tto.setAttribute(name, value);\n\t} else {\n\t\tto.removeAttribute(name);\n\t}\n}\n\nexport function trackAttributes(from: Element, to: Element, filter?: string[]): IDisposable {\n\tcopyAttributes(from, to, filter);\n\n\tconst disposables = new DisposableStore();\n\n\tdisposables.add(sharedMutationObserver.observe(from, disposables, { attributes: true, attributeFilter: filter })(mutations => {\n\t\tfor (const mutation of mutations) {\n\t\t\tif (mutation.type === 'attributes' && mutation.attributeName) {\n\t\t\t\tcopyAttribute(from, to, mutation.attributeName);\n\t\t\t}\n\t\t}\n\t}));\n\n\treturn disposables;\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 } from 'vs/base/browser/dom';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { Mimes } from 'vs/base/common/mime';\n\n/**\n * A helper that will execute a provided function when the provided HTMLElement receives\n * dragover event for 800ms. If the drag is aborted before, the callback will not be triggered.\n */\nexport class DelayedDragHandler extends Disposable {\n\tprivate timeout: any;\n\n\tconstructor(container: HTMLElement, callback: () => void) {\n\t\tsuper();\n\n\t\tthis._register(addDisposableListener(container, 'dragover', e => {\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\tif (!this.timeout) {\n\t\t\t\tthis.timeout = setTimeout(() => {\n\t\t\t\t\tcallback();\n\n\t\t\t\t\tthis.timeout = null;\n\t\t\t\t}, 800);\n\t\t\t}\n\t\t}));\n\n\t\t['dragleave', 'drop', 'dragend'].forEach(type => {\n\t\t\tthis._register(addDisposableListener(container, type, () => {\n\t\t\t\tthis.clearDragTimeout();\n\t\t\t}));\n\t\t});\n\t}\n\n\tprivate clearDragTimeout(): void {\n\t\tif (this.timeout) {\n\t\t\tclearTimeout(this.timeout);\n\t\t\tthis.timeout = null;\n\t\t}\n\t}\n\n\toverride dispose(): void {\n\t\tsuper.dispose();\n\n\t\tthis.clearDragTimeout();\n\t}\n}\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 function applyDragImage(event: DragEvent, label: string | null, clazz: string, backgroundColor?: string | null, foregroundColor?: string | null): void {\n\tconst dragImage = document.createElement('div');\n\tdragImage.className = clazz;\n\tdragImage.textContent = label;\n\n\tif (foregroundColor) {\n\t\tdragImage.style.color = foregroundColor;\n\t}\n\n\tif (backgroundColor) {\n\t\tdragImage.style.background = backgroundColor;\n\t}\n\n\tif (event.dataTransfer) {\n\t\tconst ownerDocument = getWindow(event).document;\n\t\townerDocument.body.appendChild(dragImage);\n\t\tevent.dataTransfer.setDragImage(dragImage, -10, -10);\n\n\t\t// Removes the element when the DND operation is done\n\t\tsetTimeout(() => ownerDocument.body.removeChild(dragImage), 0);\n\t}\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\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\tscreenX: number;\n\tscreenY: number;\n\tclientX: number;\n\tclientY: number;\n\tpageX: number;\n\tpageY: number;\n\tradiusX: number;\n\tradiusY: number;\n\trotationAngle: number;\n\tforce: number;\n\ttarget: Element;\n}\n\ninterface TouchList {\n\t[i: number]: Touch;\n\tlength: number;\n\titem(index: number): Touch;\n\tidentifiedTouch(id: 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\tfor (const target of this.targets) {\n\t\t\t\tif (target.contains(event.initialTarget)) {\n\t\t\t\t\ttarget.dispatchEvent(event);\n\t\t\t\t\tthis.dispatched = true;\n\t\t\t\t}\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\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';\n\t\tthis.view.style.top = '0px';\n\t\tthis.view.style.left = '0px';\n\t\tthis.view.style.zIndex = '2575';\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 const unthemedCountStyles: ICountBadgeStyles = {\n\tbadgeBackground: '#4D4D4D',\n\tbadgeForeground: '#FFFFFF',\n\tbadgeBorder: 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\tsetCountFormat(countFormat: string) {\n\t\tthis.countFormat = countFormat;\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 * 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 { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels';\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\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 {\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\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, options?: IHighlightedLabelOptions) {\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.title) {\n\t\t\tthis.domNode.title = this.title;\n\t\t} else {\n\t\t\tthis.domNode.removeAttribute('title');\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 { reset } from 'vs/base/browser/dom';\nimport { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels';\n\nexport class SimpleIconLabel {\n\n\tconstructor(\n\t\tprivate readonly _container: HTMLElement\n\t) { }\n\n\tset text(text: string) {\n\t\treset(this._container, ...renderLabelWithIcons(text ?? ''));\n\t}\n\n\tset title(title: string) {\n\t\tthis._container.title = title;\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { UILabelProvider } from 'vs/base/common/keybindingLabels';\nimport { ResolvedKeybinding, ResolvedChord } from 'vs/base/common/keybindings';\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 {\n\n\tprivate domNode: HTMLElement;\n\tprivate options: KeybindingLabelOptions;\n\n\tprivate readonly keyElements = new Set();\n\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\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.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\tif (title !== undefined) {\n\t\t\t\tthis.domNode.title = title;\n\t\t\t} else {\n\t\t\t\tthis.domNode.removeAttribute('title');\n\t\t\t}\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 { hide, show } from 'vs/base/browser/dom';\nimport { RunOnceScheduler } from 'vs/base/common/async';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { isNumber } from 'vs/base/common/types';\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\nexport const unthemedProgressBarOptions: IProgressBarOptions = {\n\tprogressBarBackground: 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\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}\n\n\t/**\n\t * Indicates to the progress bar that all work is done.\n\t */\n\tdone(): ProgressBar {\n\t\treturn this.doDone(true);\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\t/**\n\t * Tells the progress bar the total number of work. Use in combination with workedVal() to let\n\t * the progress bar show the actual progress based on the work that is done.\n\t */\n\ttotal(value: number): ProgressBar {\n\t\tthis.workedVal = 0;\n\t\tthis.totalWork = value;\n\t\tthis.element.setAttribute('aria-valuemax', value.toString());\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Finds out if this progress bar is configured with total work\n\t */\n\thasTotal(): boolean {\n\t\treturn isNumber(this.totalWork);\n\t}\n\n\t/**\n\t * Tells the progress bar that an increment of work has been completed.\n\t */\n\tworked(value: number): ProgressBar {\n\t\tvalue = Math.max(1, Number(value));\n\n\t\treturn this.doSetWorked(this.workedVal + value);\n\t}\n\n\t/**\n\t * Tells the progress bar the total amount of work that has been completed.\n\t */\n\tsetWorked(value: number): ProgressBar {\n\t\tvalue = Math.max(1, Number(value));\n\n\t\treturn this.doSetWorked(value);\n\t}\n\n\tprivate doSetWorked(value: number): ProgressBar {\n\t\tconst totalWork = this.totalWork || 100;\n\n\t\tthis.workedVal = value;\n\t\tthis.workedVal = Math.min(totalWork, this.workedVal);\n\n\t\tthis.element.classList.remove(CSS_INFINITE, CSS_INFINITE_LONG_RUNNING, CSS_DONE);\n\t\tthis.element.classList.add(CSS_ACTIVE, CSS_DISCRETE);\n\t\tthis.element.setAttribute('aria-valuenow', value.toString());\n\n\t\tthis.bit.style.width = 100 * (this.workedVal / (totalWork)) + '%';\n\n\t\treturn this;\n\t}\n\n\tgetContainer(): HTMLElement {\n\t\treturn this.element;\n\t}\n\n\tshow(delay?: number): void {\n\t\tthis.showDelayedScheduler.cancel();\n\n\t\tif (typeof delay === 'number') {\n\t\t\tthis.showDelayedScheduler.schedule(delay);\n\t\t} else {\n\t\t\tshow(this.element);\n\t\t}\n\t}\n\n\thide(): void {\n\t\thide(this.element);\n\t\tthis.showDelayedScheduler.cancel();\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 top?: Sash;\n\treadonly right?: Sash;\n\treadonly bottom?: Sash;\n\treadonly left?: 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();\nexport function setGlobalSashSize(size: number): void {\n\tglobalSize = size;\n\tonDidChangeGlobalSize.fire(size);\n}\n\nlet globalHoverDelay = 300;\nconst onDidChangeHoverDelay = new Emitter();\nexport function setGlobalHoverDelay(size: number): void {\n\tglobalHoverDelay = size;\n\tonDidChangeHoverDelay.fire(size);\n}\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 { 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 * 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 setAriaLabel(label: string): void {\n\t\tthis.selectBoxOptions.ariaLabel = label;\n\t\tthis.selectElement.setAttribute('aria-label', label);\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 style(styles: ISelectBoxStyles): void {\n\t\tthis.styles = styles;\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 { 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 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 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.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\tupdateElementHeight(location: number[], height: number | undefined): 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 { listIndex } = this.getTreeNodeWithListIndex(location);\n\t\tthis.list.updateElementHeight(listIndex, height);\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\tnode.collapsible = node.collapsible || node.children.length > 0;\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\tgetLastElementAncestor(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 this._getLastElementAncestor(node);\n\t}\n\n\tprivate _getLastElementAncestor(node: ITreeNode): T {\n\t\tif (node.children.length === 0) {\n\t\t\treturn node.element;\n\t\t}\n\n\t\treturn this._getLastElementAncestor(node.children[node.children.length - 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 { 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 type ITreeNodeCallback = (node: ITreeNode) => void;\n\nexport interface IObjectTreeModel, TFilterData extends NonNullable = void> extends ITreeModel {\n\tsetChildren(element: T | null, children: Iterable> | undefined, options?: IObjectTreeModelSetChildrenOptions): void;\n\tresort(element?: T | null, recursive?: boolean): void;\n\tupdateElementHeight(element: T, height: number | undefined): 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\tget size(): number { return this.nodes.size; }\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\tupdateElementHeight(element: T, height: number | undefined): void {\n\t\tconst location = this.getElementLocation(element);\n\t\tthis.model.updateElementHeight(location, height);\n\t}\n\n\tresort(element: T | null = null, recursive = true): void {\n\t\tif (!this.sorter) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst location = this.getElementLocation(element);\n\t\tconst node = this.model.getNode(location);\n\n\t\tthis._setChildren(location, this.resortChildren(node, recursive), {});\n\t}\n\n\tprivate resortChildren(node: ITreeNode, recursive: boolean, first = true): Iterable> {\n\t\tlet childrenNodes = [...node.children] as ITreeNode[];\n\n\t\tif (recursive || first) {\n\t\t\tchildrenNodes = childrenNodes.sort(this.sorter!.compare.bind(this.sorter));\n\t\t}\n\n\t\treturn Iterable.map, ITreeElement>(childrenNodes, node => ({\n\t\t\telement: node.element as T,\n\t\t\tcollapsible: node.collapsible,\n\t\t\tcollapsed: node.collapsed,\n\t\t\tchildren: this.resortChildren(node, recursive, false)\n\t\t}));\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\tgetLastElementAncestor(ref: T | null = null): T | null | undefined {\n\t\tconst location = this.getElementLocation(ref);\n\t\treturn this.model.getLastElementAncestor(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\tget size(): number { return this.nodes.size; }\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\tgetLastElementAncestor(location?: T | null | undefined): ICompressedTreeNode | null | undefined {\n\t\tconst compressedNode = typeof location === 'undefined' ? undefined : this.getCompressedNode(location);\n\t\treturn this.model.getLastElementAncestor(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\tupdateElementHeight(element: T, height: number): void {\n\t\tconst compressedNode = this.getCompressedNode(element);\n\n\t\tif (!compressedNode) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.model.updateElementHeight(compressedNode, height);\n\t}\n\n\trefilter(): void {\n\t\tthis.model.refilter();\n\t}\n\n\tresort(location: T | null = null, recursive = true): void {\n\t\tconst compressedNode = this.getCompressedNode(location);\n\t\tthis.model.resort(compressedNode, recursive);\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 compressionEnabled?: boolean;\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\tgetLastElementAncestor(location?: T | null | undefined): T | null | undefined {\n\t\tconst result = this.model.getLastElementAncestor(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\tupdateElementHeight(element: T, height: number): void {\n\t\tthis.model.updateElementHeight(element, height);\n\t}\n\n\trefilter(): void {\n\t\treturn this.model.refilter();\n\t}\n\n\tresort(element: T | null = null, recursive = true): void {\n\t\treturn this.model.resort(element, recursive);\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 * 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 onchange(domNode: HTMLElement, listener: (e: Event) => void): void {\n\t\tthis._register(dom.addDisposableListener(domNode, dom.EventType.CHANGE, 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\tbuttons: number;\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 { createFastDomNode, FastDomNode } 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 { dispose, IDisposable } from 'vs/base/common/lifecycle';\nimport * as platform from 'vs/base/common/platform';\nimport { INewScrollDimensions, INewScrollPosition, IScrollDimensions, IScrollPosition, Scrollable, ScrollbarVisibility, ScrollEvent } 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\tconst item = new MouseWheelClassifierItem(timestamp, deltaX, deltaY);\n\t\titem.score = this._computeScore(item);\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\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\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): 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\t\tconst prev = (this._front === -1 && this._rear === -1 ? null : this._memory[this._rear]);\n\t\tif (prev) {\n\t\t\t// const deltaT = item.timestamp - prev.timestamp;\n\t\t\t// if (deltaT < 1000 / 30) {\n\t\t\t// \t// sooner than X times per second => indicator that this is not a physical mouse wheel\n\t\t\t// \tscore += 0.25;\n\t\t\t// }\n\n\t\t\t// if (item.deltaX === prev.deltaX && item.deltaY === prev.deltaY) {\n\t\t\t// \t// equal amplitude => indicator that this is a physical mouse wheel\n\t\t\t// \tscore -= 0.25;\n\t\t\t// }\n\t\t}\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\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\tpublic readonly onWillScroll: Event = this._onWillScroll.event;\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 setRevealOnScroll(value: boolean) {\n\t\tthis._revealOnScroll = value;\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// 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\tpublic getScrollPosition(): IScrollPosition {\n\t\treturn this._scrollable.getCurrentScrollPosition();\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 { IMouseEvent } from 'vs/base/browser/mouseEvent';\nimport { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';\nimport { commonPrefixLength } from 'vs/base/common/arrays';\nimport { ThemeIcon } from 'vs/base/common/themables';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle';\nimport { ScrollbarVisibility } from 'vs/base/common/scrollable';\nimport 'vs/css!./breadcrumbsWidget';\n\nexport abstract class BreadcrumbsItem {\n\tabstract dispose(): void;\n\tabstract equals(other: BreadcrumbsItem): boolean;\n\tabstract render(container: HTMLElement): void;\n}\n\nexport interface IBreadcrumbsWidgetStyles {\n\treadonly breadcrumbsBackground: string | undefined;\n\treadonly breadcrumbsForeground: string | undefined;\n\treadonly breadcrumbsHoverForeground: string | undefined;\n\treadonly breadcrumbsFocusForeground: string | undefined;\n\treadonly breadcrumbsFocusAndSelectionForeground: string | undefined;\n}\n\nexport interface IBreadcrumbsItemEvent {\n\ttype: 'select' | 'focus';\n\titem: BreadcrumbsItem;\n\tnode: HTMLElement;\n\tpayload: any;\n}\n\nexport class BreadcrumbsWidget {\n\n\tprivate readonly _disposables = new DisposableStore();\n\tprivate readonly _domNode: HTMLDivElement;\n\tprivate readonly _scrollable: DomScrollableElement;\n\n\tprivate readonly _onDidSelectItem = new Emitter();\n\tprivate readonly _onDidFocusItem = new Emitter();\n\tprivate readonly _onDidChangeFocus = new Emitter();\n\n\treadonly onDidSelectItem: Event = this._onDidSelectItem.event;\n\treadonly onDidFocusItem: Event = this._onDidFocusItem.event;\n\treadonly onDidChangeFocus: Event = this._onDidChangeFocus.event;\n\n\tprivate readonly _items = new Array();\n\tprivate readonly _nodes = new Array();\n\tprivate readonly _freeNodes = new Array();\n\tprivate readonly _separatorIcon: ThemeIcon;\n\n\tprivate _enabled: boolean = true;\n\tprivate _focusedItemIdx: number = -1;\n\tprivate _selectedItemIdx: number = -1;\n\n\tprivate _pendingLayout: IDisposable | undefined;\n\tprivate _dimension: dom.Dimension | undefined;\n\n\tconstructor(\n\t\tcontainer: HTMLElement,\n\t\thorizontalScrollbarSize: number,\n\t\tseparatorIcon: ThemeIcon,\n\t\tstyles: IBreadcrumbsWidgetStyles\n\t) {\n\t\tthis._domNode = document.createElement('div');\n\t\tthis._domNode.className = 'monaco-breadcrumbs';\n\t\tthis._domNode.tabIndex = 0;\n\t\tthis._domNode.setAttribute('role', 'list');\n\t\tthis._scrollable = new DomScrollableElement(this._domNode, {\n\t\t\tvertical: ScrollbarVisibility.Hidden,\n\t\t\thorizontal: ScrollbarVisibility.Auto,\n\t\t\thorizontalScrollbarSize,\n\t\t\tuseShadows: false,\n\t\t\tscrollYToX: true\n\t\t});\n\t\tthis._separatorIcon = separatorIcon;\n\t\tthis._disposables.add(this._scrollable);\n\t\tthis._disposables.add(dom.addStandardDisposableListener(this._domNode, 'click', e => this._onClick(e)));\n\t\tcontainer.appendChild(this._scrollable.getDomNode());\n\n\t\tconst styleElement = dom.createStyleSheet(this._domNode);\n\t\tthis._style(styleElement, styles);\n\n\t\tconst focusTracker = dom.trackFocus(this._domNode);\n\t\tthis._disposables.add(focusTracker);\n\t\tthis._disposables.add(focusTracker.onDidBlur(_ => this._onDidChangeFocus.fire(false)));\n\t\tthis._disposables.add(focusTracker.onDidFocus(_ => this._onDidChangeFocus.fire(true)));\n\t}\n\n\tsetHorizontalScrollbarSize(size: number) {\n\t\tthis._scrollable.updateOptions({\n\t\t\thorizontalScrollbarSize: size\n\t\t});\n\t}\n\n\tdispose(): void {\n\t\tthis._disposables.dispose();\n\t\tthis._pendingLayout?.dispose();\n\t\tthis._onDidSelectItem.dispose();\n\t\tthis._onDidFocusItem.dispose();\n\t\tthis._onDidChangeFocus.dispose();\n\t\tthis._domNode.remove();\n\t\tthis._nodes.length = 0;\n\t\tthis._freeNodes.length = 0;\n\t}\n\n\tlayout(dim: dom.Dimension | undefined): void {\n\t\tif (dim && dom.Dimension.equals(dim, this._dimension)) {\n\t\t\treturn;\n\t\t}\n\t\tthis._pendingLayout?.dispose();\n\t\tif (dim) {\n\t\t\t// only measure\n\t\t\tthis._pendingLayout = this._updateDimensions(dim);\n\t\t} else {\n\t\t\tthis._pendingLayout = this._updateScrollbar();\n\t\t}\n\t}\n\n\tprivate _updateDimensions(dim: dom.Dimension): IDisposable {\n\t\tconst disposables = new DisposableStore();\n\t\tdisposables.add(dom.modify(dom.getWindow(this._domNode), () => {\n\t\t\tthis._dimension = dim;\n\t\t\tthis._domNode.style.width = `${dim.width}px`;\n\t\t\tthis._domNode.style.height = `${dim.height}px`;\n\t\t\tdisposables.add(this._updateScrollbar());\n\t\t}));\n\t\treturn disposables;\n\t}\n\n\tprivate _updateScrollbar(): IDisposable {\n\t\treturn dom.measure(dom.getWindow(this._domNode), () => {\n\t\t\tdom.measure(dom.getWindow(this._domNode), () => { // double RAF\n\t\t\t\tthis._scrollable.setRevealOnScroll(false);\n\t\t\t\tthis._scrollable.scanDomNode();\n\t\t\t\tthis._scrollable.setRevealOnScroll(true);\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate _style(styleElement: HTMLStyleElement, style: IBreadcrumbsWidgetStyles): void {\n\t\tlet content = '';\n\t\tif (style.breadcrumbsBackground) {\n\t\t\tcontent += `.monaco-breadcrumbs { background-color: ${style.breadcrumbsBackground}}`;\n\t\t}\n\t\tif (style.breadcrumbsForeground) {\n\t\t\tcontent += `.monaco-breadcrumbs .monaco-breadcrumb-item { color: ${style.breadcrumbsForeground}}\\n`;\n\t\t}\n\t\tif (style.breadcrumbsFocusForeground) {\n\t\t\tcontent += `.monaco-breadcrumbs .monaco-breadcrumb-item.focused { color: ${style.breadcrumbsFocusForeground}}\\n`;\n\t\t}\n\t\tif (style.breadcrumbsFocusAndSelectionForeground) {\n\t\t\tcontent += `.monaco-breadcrumbs .monaco-breadcrumb-item.focused.selected { color: ${style.breadcrumbsFocusAndSelectionForeground}}\\n`;\n\t\t}\n\t\tif (style.breadcrumbsHoverForeground) {\n\t\t\tcontent += `.monaco-breadcrumbs:not(.disabled\t) .monaco-breadcrumb-item:hover:not(.focused):not(.selected) { color: ${style.breadcrumbsHoverForeground}}\\n`;\n\t\t}\n\t\tstyleElement.innerText = content;\n\t}\n\n\tsetEnabled(value: boolean) {\n\t\tthis._enabled = value;\n\t\tthis._domNode.classList.toggle('disabled', !this._enabled);\n\t}\n\n\tdomFocus(): void {\n\t\tconst idx = this._focusedItemIdx >= 0 ? this._focusedItemIdx : this._items.length - 1;\n\t\tif (idx >= 0 && idx < this._items.length) {\n\t\t\tthis._focus(idx, undefined);\n\t\t} else {\n\t\t\tthis._domNode.focus();\n\t\t}\n\t}\n\n\tisDOMFocused(): boolean {\n\t\treturn dom.isAncestorOfActiveElement(this._domNode);\n\t}\n\n\tgetFocused(): BreadcrumbsItem {\n\t\treturn this._items[this._focusedItemIdx];\n\t}\n\n\tsetFocused(item: BreadcrumbsItem | undefined, payload?: any): void {\n\t\tthis._focus(this._items.indexOf(item!), payload);\n\t}\n\n\tfocusPrev(payload?: any): any {\n\t\tif (this._focusedItemIdx > 0) {\n\t\t\tthis._focus(this._focusedItemIdx - 1, payload);\n\t\t}\n\t}\n\n\tfocusNext(payload?: any): any {\n\t\tif (this._focusedItemIdx + 1 < this._nodes.length) {\n\t\t\tthis._focus(this._focusedItemIdx + 1, payload);\n\t\t}\n\t}\n\n\tprivate _focus(nth: number, payload: any): void {\n\t\tthis._focusedItemIdx = -1;\n\t\tfor (let i = 0; i < this._nodes.length; i++) {\n\t\t\tconst node = this._nodes[i];\n\t\t\tif (i !== nth) {\n\t\t\t\tnode.classList.remove('focused');\n\t\t\t} else {\n\t\t\t\tthis._focusedItemIdx = i;\n\t\t\t\tnode.classList.add('focused');\n\t\t\t\tnode.focus();\n\t\t\t}\n\t\t}\n\t\tthis._reveal(this._focusedItemIdx, true);\n\t\tthis._onDidFocusItem.fire({ type: 'focus', item: this._items[this._focusedItemIdx], node: this._nodes[this._focusedItemIdx], payload });\n\t}\n\n\treveal(item: BreadcrumbsItem): void {\n\t\tconst idx = this._items.indexOf(item);\n\t\tif (idx >= 0) {\n\t\t\tthis._reveal(idx, false);\n\t\t}\n\t}\n\n\trevealLast(): void {\n\t\tthis._reveal(this._items.length - 1, false);\n\t}\n\n\tprivate _reveal(nth: number, minimal: boolean): void {\n\t\tif (nth < 0 || nth >= this._nodes.length) {\n\t\t\treturn;\n\t\t}\n\t\tconst node = this._nodes[nth];\n\t\tif (!node) {\n\t\t\treturn;\n\t\t}\n\t\tconst { width } = this._scrollable.getScrollDimensions();\n\t\tconst { scrollLeft } = this._scrollable.getScrollPosition();\n\t\tif (!minimal || node.offsetLeft > scrollLeft + width || node.offsetLeft < scrollLeft) {\n\t\t\tthis._scrollable.setRevealOnScroll(false);\n\t\t\tthis._scrollable.setScrollPosition({ scrollLeft: node.offsetLeft });\n\t\t\tthis._scrollable.setRevealOnScroll(true);\n\t\t}\n\t}\n\n\tgetSelection(): BreadcrumbsItem {\n\t\treturn this._items[this._selectedItemIdx];\n\t}\n\n\tsetSelection(item: BreadcrumbsItem | undefined, payload?: any): void {\n\t\tthis._select(this._items.indexOf(item!), payload);\n\t}\n\n\tprivate _select(nth: number, payload: any): void {\n\t\tthis._selectedItemIdx = -1;\n\t\tfor (let i = 0; i < this._nodes.length; i++) {\n\t\t\tconst node = this._nodes[i];\n\t\t\tif (i !== nth) {\n\t\t\t\tnode.classList.remove('selected');\n\t\t\t} else {\n\t\t\t\tthis._selectedItemIdx = i;\n\t\t\t\tnode.classList.add('selected');\n\t\t\t}\n\t\t}\n\t\tthis._onDidSelectItem.fire({ type: 'select', item: this._items[this._selectedItemIdx], node: this._nodes[this._selectedItemIdx], payload });\n\t}\n\n\tgetItems(): readonly BreadcrumbsItem[] {\n\t\treturn this._items;\n\t}\n\n\tsetItems(items: BreadcrumbsItem[]): void {\n\t\tlet prefix: number | undefined;\n\t\tlet removed: BreadcrumbsItem[] = [];\n\t\ttry {\n\t\t\tprefix = commonPrefixLength(this._items, items, (a, b) => a.equals(b));\n\t\t\tremoved = this._items.splice(prefix, this._items.length - prefix, ...items.slice(prefix));\n\t\t\tthis._render(prefix);\n\t\t\tdispose(removed);\n\t\t\tthis._focus(-1, undefined);\n\t\t} catch (e) {\n\t\t\tconst newError = new Error(`BreadcrumbsItem#setItems: newItems: ${items.length}, prefix: ${prefix}, removed: ${removed.length}`);\n\t\t\tnewError.name = e.name;\n\t\t\tnewError.stack = e.stack;\n\t\t\tthrow newError;\n\t\t}\n\t}\n\n\tprivate _render(start: number): void {\n\t\tlet didChange = false;\n\t\tfor (; start < this._items.length && start < this._nodes.length; start++) {\n\t\t\tconst item = this._items[start];\n\t\t\tconst node = this._nodes[start];\n\t\t\tthis._renderItem(item, node);\n\t\t\tdidChange = true;\n\t\t}\n\t\t// case a: more nodes -> remove them\n\t\twhile (start < this._nodes.length) {\n\t\t\tconst free = this._nodes.pop();\n\t\t\tif (free) {\n\t\t\t\tthis._freeNodes.push(free);\n\t\t\t\tfree.remove();\n\t\t\t\tdidChange = true;\n\t\t\t}\n\t\t}\n\n\t\t// case b: more items -> render them\n\t\tfor (; start < this._items.length; start++) {\n\t\t\tconst item = this._items[start];\n\t\t\tconst node = this._freeNodes.length > 0 ? this._freeNodes.pop() : document.createElement('div');\n\t\t\tif (node) {\n\t\t\t\tthis._renderItem(item, node);\n\t\t\t\tthis._domNode.appendChild(node);\n\t\t\t\tthis._nodes.push(node);\n\t\t\t\tdidChange = true;\n\t\t\t}\n\t\t}\n\t\tif (didChange) {\n\t\t\tthis.layout(undefined);\n\t\t}\n\t}\n\n\tprivate _renderItem(item: BreadcrumbsItem, container: HTMLDivElement): void {\n\t\tdom.clearNode(container);\n\t\tcontainer.className = '';\n\t\ttry {\n\t\t\titem.render(container);\n\t\t} catch (err) {\n\t\t\tcontainer.innerText = '<>';\n\t\t\tconsole.error(err);\n\t\t}\n\t\tcontainer.tabIndex = -1;\n\t\tcontainer.setAttribute('role', 'listitem');\n\t\tcontainer.classList.add('monaco-breadcrumb-item');\n\t\tconst iconContainer = dom.$(ThemeIcon.asCSSSelector(this._separatorIcon));\n\t\tcontainer.appendChild(iconContainer);\n\t}\n\n\tprivate _onClick(event: IMouseEvent): void {\n\t\tif (!this._enabled) {\n\t\t\treturn;\n\t\t}\n\t\tfor (let el: HTMLElement | null = event.target; el; el = el.parentElement) {\n\t\t\tconst idx = this._nodes.indexOf(el as HTMLDivElement);\n\t\t\tif (idx >= 0) {\n\t\t\t\tthis._focus(idx, event);\n\t\t\t\tthis._select(idx, event);\n\t\t\t\tbreak;\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 { 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!./hover';\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._register(dom.addDisposableListener(this.actionContainer, dom.EventType.CLICK, e => {\n\t\t\te.stopPropagation();\n\t\t\te.preventDefault();\n\t\t\tactionOptions.run(this.actionContainer);\n\t\t}));\n\n\t\tthis._register(dom.addDisposableListener(this.actionContainer, dom.EventType.KEY_DOWN, 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\te.stopPropagation();\n\t\t\t\te.preventDefault();\n\t\t\t\tactionOptions.run(this.actionContainer);\n\t\t\t}\n\t\t}));\n\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","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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, scheduleAtNextAnimationFrame } from 'vs/base/browser/dom';\nimport { DomEmitter } from 'vs/base/browser/event';\nimport { IMouseWheelEvent } from 'vs/base/browser/mouseEvent';\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 } 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 { IObservableValue } from 'vs/base/common/observableValue';\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 | IObservableValue | 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\tprivate _context: TContext | undefined;\n\tpublic get context(): TContext | undefined {\n\t\treturn this._context;\n\t}\n\tpublic set context(value: TContext | undefined) {\n\t\tthis._context = value;\n\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 | IObservableValue | 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 containerDomNode: HTMLElement;\n\treadonly scrollableElementDomNode: HTMLElement;\n\treadonly length: number;\n\treadonly contentHeight: number;\n\treadonly contentWidth: number;\n\treadonly onDidChangeContentHeight: Event;\n\treadonly onDidChangeContentWidth: Event;\n\treadonly renderHeight: number;\n\treadonly scrollHeight: number;\n\treadonly firstVisibleIndex: number;\n\treadonly firstMostlyVisibleIndex: number;\n\treadonly lastVisibleIndex: number;\n\tonDidScroll: Event;\n\tonWillScroll: Event;\n\tonMouseClick: Event>;\n\tonMouseDblClick: Event>;\n\tonMouseMiddleClick: Event>;\n\tonMouseUp: Event>;\n\tonMouseDown: Event>;\n\tonMouseOver: Event>;\n\tonMouseMove: 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\tgetScrollLeft(): number;\n\tsetScrollLeft(scrollLeft: number): void;\n\tdelegateScrollFromMouseWheelEvent(browserEvent: IMouseWheelEvent): void;\n\tdelegateVerticalScrollbarPointerDown(browserEvent: PointerEvent): void;\n\tupdateWidth(index: number): void;\n\tupdateElementHeight(index: number, size: number | undefined, anchorIndex: number | null): 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\treadonly onDidChangeContentWidth: Event = Event.latch(this._onDidChangeContentWidth.event, undefined, this.disposables);\n\tget contentHeight(): number { return this.rangeMap.size; }\n\tget contentWidth(): number { return this.scrollWidth ?? 0; }\n\n\tget onDidScroll(): Event { return this.scrollableElement.onScroll; }\n\tget onWillScroll(): Event { return this.scrollableElement.onWillScroll; }\n\tget containerDomNode(): HTMLElement { return this.rowsContainer; }\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\tdelegateScrollFromMouseWheelEvent(browserEvent: IMouseWheelEvent) {\n\t\tthis.scrollableElement.delegateScrollFromMouseWheelEvent(browserEvent);\n\t}\n\n\tdelegateVerticalScrollbarPointerDown(browserEvent: PointerEvent) {\n\t\tthis.scrollableElement.delegateVerticalScrollbarPointerDown(browserEvent);\n\t}\n\n\tupdateElementHeight(index: number, size: number | undefined, anchorIndex: number | null): void {\n\t\tif (index < 0 || index >= this.items.length) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst originalSize = this.items[index].size;\n\n\t\tif (typeof size === 'undefined') {\n\t\t\tif (!this.supportDynamicHeights) {\n\t\t\t\tconsole.warn('Dynamic heights not supported');\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.items[index].lastDynamicHeightWidth = undefined;\n\t\t\tsize = originalSize + this.probeDynamicHeight(index);\n\t\t}\n\n\t\tif (originalSize === size) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst lastRenderRange = this.getRenderRange(this.lastRenderTop, this.lastRenderHeight);\n\n\t\tlet heightDiff = 0;\n\n\t\tif (index < lastRenderRange.start) {\n\t\t\t// do not scroll the viewport if resized element is out of viewport\n\t\t\theightDiff = size - originalSize;\n\t\t} else {\n\t\t\tif (anchorIndex !== null && anchorIndex > index && anchorIndex < lastRenderRange.end) {\n\t\t\t\t// anchor in viewport\n\t\t\t\t// resized element in viewport and above the anchor\n\t\t\t\theightDiff = size - originalSize;\n\t\t\t} else {\n\t\t\t\theightDiff = 0;\n\t\t\t}\n\t\t}\n\n\t\tthis.rangeMap.splice(index, 1, [{ size: size }]);\n\t\tthis.items[index].size = size;\n\n\t\tthis.render(lastRenderRange, Math.max(0, this.lastRenderTop + heightDiff), this.lastRenderHeight, undefined, undefined, true);\n\t\tthis.setScrollTop(this.lastRenderTop);\n\n\t\tthis.eventuallyUpdateScrollDimensions();\n\n\t\tif (this.supportDynamicHeights) {\n\t\t\tthis._rerender(this.lastRenderTop, this.lastRenderHeight);\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.push(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\tupdateWidth(index: number): void {\n\t\tif (!this.horizontalScrolling || typeof this.scrollWidth === 'undefined') {\n\t\t\treturn;\n\t\t}\n\n\t\tconst item = this.items[index];\n\t\tthis.measureItemWidth(item);\n\n\t\tif (typeof item.width !== 'undefined' && item.width > this.scrollWidth) {\n\t\t\tthis.scrollWidth = item.width;\n\t\t\tthis.scrollableElement.setScrollDimensions({ scrollWidth: this.scrollWidth + 10 });\n\t\t\tthis._onDidChangeContentWidth.fire(this.scrollWidth);\n\t\t}\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\tget firstMostlyVisibleIndex(): number {\n\t\tconst firstVisibleIndex = this.firstVisibleIndex;\n\t\tconst firstElTop = this.rangeMap.positionAt(firstVisibleIndex);\n\t\tconst nextElTop = this.rangeMap.positionAt(firstVisibleIndex + 1);\n\t\tif (nextElTop !== -1) {\n\t\t\tconst firstElMidpoint = (nextElTop - firstElTop) / 2 + firstElTop;\n\t\t\tif (firstElMidpoint < this.scrollTop) {\n\t\t\t\treturn firstVisibleIndex + 1;\n\t\t\t}\n\t\t}\n\n\t\treturn firstVisibleIndex;\n\t}\n\n\tget lastVisibleIndex(): number {\n\t\tconst range = this.getRenderRange(this.lastRenderTop, this.lastRenderHeight);\n\t\treturn range.end - 1;\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);\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\tthis.rowsContainer.insertBefore(item.row.domNode, referenceNode);\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\tgetScrollLeft(): number {\n\t\tconst scrollPosition = this.scrollableElement.getScrollPosition();\n\t\treturn scrollPosition.scrollLeft;\n\t}\n\n\tsetScrollLeft(scrollLeft: number): void {\n\t\tif (this.scrollableElementUpdateDisposable) {\n\t\t\tthis.scrollableElementUpdateDisposable.dispose();\n\t\t\tthis.scrollableElementUpdateDisposable = null;\n\t\t\tthis.scrollableElement.setScrollDimensions({ scrollWidth: this.scrollWidth });\n\t\t}\n\n\t\tthis.scrollableElement.setScrollPosition({ scrollLeft });\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 onMouseUp(): Event> { return Event.map(this.disposables.add(new DomEmitter(this.domNode, 'mouseup')).event, e => this.toMouseEvent(e), 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 onMouseMove(): Event> { return Event.map(this.disposables.add(new DomEmitter(this.domNode, 'mousemove')).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\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, Dimension, EventHelper, getActiveElement, getWindow, isActiveElement, 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 { ScrollableElementChangeOptions } from 'vs/base/browser/ui/scrollbar/scrollableElementOptions';\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';\n\ninterface ITraitChangeEvent {\n\tindexes: number[];\n\tbrowserEvent?: UIEvent;\n}\n\ntype ITraitTemplateData = HTMLElement;\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 isMonacoTwistie(e: HTMLElement): boolean {\n\treturn isListElementDescendantOfClass(e, 'monaco-tl-twistie');\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\ttrigger(): void {\n\t\tthis.triggered = !this.triggered;\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\t\t\tif (ariaLabel) {\n\t\t\t\talert(ariaLabel);\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 | 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 supportDynamicHeights?: boolean;\n\treadonly mouseSupport?: boolean;\n\treadonly horizontalScrolling?: boolean;\n\treadonly scrollByPage?: boolean;\n\treadonly transformOptimization?: boolean;\n\treadonly smoothScrolling?: boolean;\n\treadonly scrollableElementChangeOptions?: ScrollableElementChangeOptions;\n\treadonly alwaysConsumeMouseWheel?: boolean;\n\treadonly initialSize?: Dimension;\n\treadonly paddingTop?: number;\n\treadonly paddingBottom?: number;\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\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};\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): HTMLElement {\n\t\treturn container;\n\t}\n\n\trenderElement(element: T, index: number, container: HTMLElement): void {\n\t\tconst ariaLabel = this.accessibilityProvider.getAriaLabel(element);\n\n\t\tif (ariaLabel) {\n\t\t\tcontainer.setAttribute('aria-label', ariaLabel);\n\t\t} else {\n\t\t\tcontainer.removeAttribute('aria-label');\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\tcontainer.setAttribute('aria-level', `${ariaLevel}`);\n\t\t} else {\n\t\t\tcontainer.removeAttribute('aria-level');\n\t\t}\n\t}\n\n\tdisposeTemplate(templateData: any): void {\n\t\t// noop\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 onMouseUp(): Event> { return this.view.onMouseUp; }\n\tget onMouseDown(): Event> { return this.view.onMouseDown; }\n\tget onMouseOver(): Event> { return this.view.onMouseOver; }\n\tget onMouseMove(): Event> { return this.view.onMouseMove; }\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\t@memoize get onKeyUp(): Event { return this.disposables.add(new DomEmitter(this.view.domNode, 'keyup')).event; }\n\t@memoize get onKeyPress(): Event { return this.disposables.add(new DomEmitter(this.view.domNode, 'keypress')).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\tupdateWidth(index: number): void {\n\t\tthis.view.updateWidth(index);\n\t}\n\n\tupdateElementHeight(index: number, size: number): void {\n\t\tthis.view.updateElementHeight(index, size, null);\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 contentWidth(): number {\n\t\treturn this.view.contentWidth;\n\t}\n\n\tget onDidChangeContentHeight(): Event {\n\t\treturn this.view.onDidChangeContentHeight;\n\t}\n\n\tget onDidChangeContentWidth(): Event {\n\t\treturn this.view.onDidChangeContentWidth;\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 scrollLeft(): number {\n\t\treturn this.view.getScrollLeft();\n\t}\n\n\tset scrollLeft(scrollLeft: number) {\n\t\tthis.view.setScrollLeft(scrollLeft);\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 firstMostlyVisibleIndex(): number {\n\t\treturn this.view.firstMostlyVisibleIndex;\n\t}\n\n\tget lastVisibleIndex(): number {\n\t\treturn this.view.lastVisibleIndex;\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\ttriggerTypeNavigation(): void {\n\t\tthis.typeNavigationController?.trigger();\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\tisDOMFocused(): boolean {\n\t\treturn isActiveElement(this.view.domNode);\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 { ScrollbarVisibility } from 'vs/base/common/scrollable';\nimport 'vs/css!./list';\nimport { IListContextMenuEvent, IListEvent, IListMouseEvent, IListRenderer, IListVirtualDelegate } from './list';\nimport { IListAccessibilityProvider, IListOptions, IListOptionsUpdate, IListStyles, List, TypeNavigationMode } from './listWidget';\nimport { isActiveElement } from 'vs/base/browser/dom';\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): string | null {\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 typeNavigationEnabled?: boolean;\n\treadonly typeNavigationMode?: TypeNavigationMode;\n\treadonly ariaLabel?: string;\n\treadonly keyboardSupport?: boolean;\n\treadonly multipleSelectionSupport?: boolean;\n\treadonly accessibilityProvider?: IListAccessibilityProvider;\n\n\t// list view options\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 horizontalScrolling?: boolean;\n\treadonly scrollByPage?: boolean;\n\treadonly paddingBottom?: number;\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\tisDOMFocused(): boolean {\n\t\treturn isActiveElement(this.getHTMLElement());\n\t}\n\n\tdomFocus(): void {\n\t\tthis.list.domFocus();\n\t}\n\n\tget onDidFocus(): Event {\n\t\treturn this.list.onDidFocus;\n\t}\n\n\tget onDidBlur(): Event {\n\t\treturn this.list.onDidBlur;\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 onMouseClick(): Event> {\n\t\treturn Event.map(this.list.onMouseClick, ({ element, index, browserEvent }) => ({ element: element === undefined ? undefined : this._model.get(element), index, browserEvent }));\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 onTap(): Event> {\n\t\treturn Event.map(this.list.onTap, ({ 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 onDidChangeFocus(): Event> {\n\t\treturn Event.map(this.list.onDidChangeFocus, ({ elements, indexes, browserEvent }) => ({ elements: elements.map(e => this._model.get(e)), indexes, 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 onContextMenu(): Event> {\n\t\treturn Event.map(this.list.onContextMenu, ({ element, index, anchor, browserEvent }) => (typeof element === 'undefined' ? { element, index, anchor, browserEvent } : { element: this._model.get(element), index, anchor, 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\tget length(): number {\n\t\treturn this.list.length;\n\t}\n\n\tget scrollTop(): number {\n\t\treturn this.list.scrollTop;\n\t}\n\n\tset scrollTop(scrollTop: number) {\n\t\tthis.list.scrollTop = scrollTop;\n\t}\n\n\tget scrollLeft(): number {\n\t\treturn this.list.scrollLeft;\n\t}\n\n\tset scrollLeft(scrollLeft: number) {\n\t\tthis.list.scrollLeft = scrollLeft;\n\t}\n\n\tsetAnchor(index: number | undefined): void {\n\t\tthis.list.setAnchor(index);\n\t}\n\n\tgetAnchor(): number | undefined {\n\t\treturn this.list.getAnchor();\n\t}\n\n\tsetFocus(indexes: number[]): void {\n\t\tthis.list.setFocus(indexes);\n\t}\n\n\tfocusNext(n?: number, loop?: boolean): void {\n\t\tthis.list.focusNext(n, loop);\n\t}\n\n\tfocusPrevious(n?: number, loop?: boolean): void {\n\t\tthis.list.focusPrevious(n, loop);\n\t}\n\n\tfocusNextPage(): Promise {\n\t\treturn this.list.focusNextPage();\n\t}\n\n\tfocusPreviousPage(): Promise {\n\t\treturn this.list.focusPreviousPage();\n\t}\n\n\tfocusLast(): void {\n\t\tthis.list.focusLast();\n\t}\n\n\tfocusFirst(): void {\n\t\tthis.list.focusFirst();\n\t}\n\n\tgetFocus(): number[] {\n\t\treturn this.list.getFocus();\n\t}\n\n\tsetSelection(indexes: number[], browserEvent?: UIEvent): void {\n\t\tthis.list.setSelection(indexes, browserEvent);\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\tlayout(height?: number, width?: number): void {\n\t\tthis.list.layout(height, width);\n\t}\n\n\ttriggerTypeNavigation(): void {\n\t\tthis.list.triggerTypeNavigation();\n\t}\n\n\treveal(index: number, relativeTop?: number): void {\n\t\tthis.list.reveal(index, relativeTop);\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\tget cachedVisibleSize(): number | undefined { return this._cachedVisibleSize; }\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 * The sum of all views' sizes.\n\t */\n\tget contentSize(): number { return this._contentSize; }\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\t/**\n\t * The amount of views in this {@link SplitView}.\n\t */\n\tget length(): number {\n\t\treturn this.viewItems.length;\n\t}\n\n\t/**\n\t * The minimum size of this {@link SplitView}.\n\t */\n\tget minimumSize(): number {\n\t\treturn this.viewItems.reduce((r, item) => r + item.minimumSize, 0);\n\t}\n\n\t/**\n\t * The maximum size of this {@link SplitView}.\n\t */\n\tget maximumSize(): number {\n\t\treturn this.length === 0 ? Number.POSITIVE_INFINITY : this.viewItems.reduce((r, item) => r + item.maximumSize, 0);\n\t}\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 * The internal sashes within this {@link SplitView}.\n\t */\n\tget sashes(): readonly Sash[] {\n\t\treturn this.sashItems.map(s => s.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 } as 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 * Remove a {@link IView view} from this {@link SplitView}.\n\t *\n\t * @param index The index where the {@link IView view} is located.\n\t * @param sizing Whether to distribute other {@link IView view}'s sizes.\n\t */\n\tremoveView(index: number, sizing?: Sizing): TView {\n\t\tif (index < 0 || index >= this.viewItems.length) {\n\t\t\tthrow new Error('Index out of bounds');\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\tif (sizing?.type === 'auto') {\n\t\t\t\tif (this.areViewsDistributed()) {\n\t\t\t\t\tsizing = { type: 'distribute' };\n\t\t\t\t} else {\n\t\t\t\t\tsizing = { type: 'split', index: sizing.index };\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Save referene view, in case of `split` sizing\n\t\t\tconst referenceViewItem = sizing?.type === 'split' ? this.viewItems[sizing.index] : undefined;\n\n\t\t\t// Remove view\n\t\t\tconst viewItemToRemove = this.viewItems.splice(index, 1)[0];\n\n\t\t\t// Resize reference view, in case of `split` sizing\n\t\t\tif (referenceViewItem) {\n\t\t\t\treferenceViewItem.size += viewItemToRemove.size;\n\t\t\t}\n\n\t\t\t// Remove sash\n\t\t\tif (this.viewItems.length >= 1) {\n\t\t\t\tconst sashIndex = Math.max(index - 1, 0);\n\t\t\t\tconst sashItem = this.sashItems.splice(sashIndex, 1)[0];\n\t\t\t\tsashItem.disposable.dispose();\n\t\t\t}\n\n\t\t\tthis.relayout();\n\n\t\t\tif (sizing?.type === 'distribute') {\n\t\t\t\tthis.distributeViewSizes();\n\t\t\t}\n\n\t\t\tconst result = viewItemToRemove.view;\n\t\t\tviewItemToRemove.dispose();\n\t\t\treturn result;\n\n\t\t} finally {\n\t\t\tthis.state = State.Idle;\n\t\t}\n\t}\n\n\tremoveAllViews(): TView[] {\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 viewItems = this.viewItems.splice(0, this.viewItems.length);\n\n\t\t\tfor (const viewItem of viewItems) {\n\t\t\t\tviewItem.dispose();\n\t\t\t}\n\n\t\t\tconst sashItems = this.sashItems.splice(0, this.sashItems.length);\n\n\t\t\tfor (const sashItem of sashItems) {\n\t\t\t\tsashItem.disposable.dispose();\n\t\t\t}\n\n\t\t\tthis.relayout();\n\t\t\treturn viewItems.map(i => i.view);\n\n\t\t} finally {\n\t\t\tthis.state = State.Idle;\n\t\t}\n\t}\n\n\t/**\n\t * Move a {@link IView view} to a different index.\n\t *\n\t * @param from The source index.\n\t * @param to The target index.\n\t */\n\tmoveView(from: number, to: number): void {\n\t\tif (this.state !== State.Idle) {\n\t\t\tthrow new Error('Cant modify splitview');\n\t\t}\n\n\t\tconst cachedVisibleSize = this.getViewCachedVisibleSize(from);\n\t\tconst sizing = typeof cachedVisibleSize === 'undefined' ? this.getViewSize(from) : Sizing.Invisible(cachedVisibleSize);\n\t\tconst view = this.removeView(from);\n\t\tthis.addView(view, sizing, to);\n\t}\n\n\n\t/**\n\t * Swap two {@link IView views}.\n\t *\n\t * @param from The source index.\n\t * @param to The target index.\n\t */\n\tswapViews(from: number, to: number): void {\n\t\tif (this.state !== State.Idle) {\n\t\t\tthrow new Error('Cant modify splitview');\n\t\t}\n\n\t\tif (from > to) {\n\t\t\treturn this.swapViews(to, from);\n\t\t}\n\n\t\tconst fromSize = this.getViewSize(from);\n\t\tconst toSize = this.getViewSize(to);\n\t\tconst toView = this.removeView(to);\n\t\tconst fromView = this.removeView(from);\n\n\t\tthis.addView(toView, fromSize, from);\n\t\tthis.addView(fromView, toSize, to);\n\t}\n\n\t/**\n\t * Returns whether the {@link IView view} is visible.\n\t *\n\t * @param index The {@link IView view} index.\n\t */\n\tisViewVisible(index: number): boolean {\n\t\tif (index < 0 || index >= this.viewItems.length) {\n\t\t\tthrow new Error('Index out of bounds');\n\t\t}\n\n\t\tconst viewItem = this.viewItems[index];\n\t\treturn viewItem.visible;\n\t}\n\n\t/**\n\t * Set a {@link IView view}'s visibility.\n\t *\n\t * @param index The {@link IView view} index.\n\t * @param visible Whether the {@link IView view} should be visible.\n\t */\n\tsetViewVisible(index: number, visible: boolean): void {\n\t\tif (index < 0 || index >= this.viewItems.length) {\n\t\t\tthrow new Error('Index out of bounds');\n\t\t}\n\n\t\tconst viewItem = this.viewItems[index];\n\t\tviewItem.setVisible(visible);\n\n\t\tthis.distributeEmptySpace(index);\n\t\tthis.layoutViews();\n\t\tthis.saveProportions();\n\t}\n\n\t/**\n\t * Returns the {@link IView view}'s size previously to being hidden.\n\t *\n\t * @param index The {@link IView view} index.\n\t */\n\tgetViewCachedVisibleSize(index: number): number | undefined {\n\t\tif (index < 0 || index >= this.viewItems.length) {\n\t\t\tthrow new Error('Index out of bounds');\n\t\t}\n\n\t\tconst viewItem = this.viewItems[index];\n\t\treturn viewItem.cachedVisibleSize;\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 * Returns whether all other {@link IView views} are at their minimum size.\n\t */\n\tisViewExpanded(index: number): boolean {\n\t\tif (index < 0 || index >= this.viewItems.length) {\n\t\t\treturn false;\n\t\t}\n\n\t\tfor (const item of this.viewItems) {\n\t\t\tif (item !== this.viewItems[index] && item.size > item.minimumSize) {\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 * 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 { $, IDomNodePagePosition } from 'vs/base/browser/dom';\nimport { IView, IViewSize } from 'vs/base/browser/ui/grid/grid';\nimport { IBoundarySashes } from 'vs/base/browser/ui/sash/sash';\nimport { DistributeSizing, ISplitViewStyles, IView as ISplitViewView, Orientation, SplitView } from 'vs/base/browser/ui/splitview/splitview';\nimport { Color } from 'vs/base/common/color';\nimport { Event } from 'vs/base/common/event';\nimport { DisposableStore, IDisposable } from 'vs/base/common/lifecycle';\n\nexport interface CenteredViewState {\n\t// width of the fixed centered layout\n\ttargetWidth: number;\n\t// proportional size of left margin\n\tleftMarginRatio: number;\n\t// proportional size of right margin\n\trightMarginRatio: number;\n}\n\nconst defaultState: CenteredViewState = {\n\ttargetWidth: 900,\n\tleftMarginRatio: 0.1909,\n\trightMarginRatio: 0.1909,\n};\n\nconst distributeSizing: DistributeSizing = { type: 'distribute' };\n\nfunction createEmptyView(background: Color | undefined): ISplitViewView<{ top: number; left: number }> {\n\tconst element = $('.centered-layout-margin');\n\telement.style.height = '100%';\n\tif (background) {\n\t\telement.style.backgroundColor = background.toString();\n\t}\n\n\treturn {\n\t\telement,\n\t\tlayout: () => undefined,\n\t\tminimumSize: 60,\n\t\tmaximumSize: Number.POSITIVE_INFINITY,\n\t\tonDidChange: Event.None\n\t};\n}\n\nfunction toSplitViewView(view: IView, getHeight: () => number): ISplitViewView<{ top: number; left: number }> {\n\treturn {\n\t\telement: view.element,\n\t\tget maximumSize() { return view.maximumWidth; },\n\t\tget minimumSize() { return view.minimumWidth; },\n\t\tonDidChange: Event.map(view.onDidChange, e => e && e.width),\n\t\tlayout: (size, offset, ctx) => view.layout(size, getHeight(), ctx?.top ?? 0, (ctx?.left ?? 0) + offset)\n\t};\n}\n\nexport interface ICenteredViewStyles extends ISplitViewStyles {\n\tbackground: Color;\n}\n\nexport class CenteredViewLayout implements IDisposable {\n\n\tprivate splitView?: SplitView<{ top: number; left: number }>;\n\tprivate lastLayoutPosition: IDomNodePagePosition = { width: 0, height: 0, left: 0, top: 0 };\n\tprivate style!: ICenteredViewStyles;\n\tprivate didLayout = false;\n\tprivate emptyViews: ISplitViewView<{ top: number; left: number }>[] | undefined;\n\tprivate readonly splitViewDisposables = new DisposableStore();\n\n\tconstructor(\n\t\tprivate container: HTMLElement,\n\t\tprivate view: IView,\n\t\tpublic state: CenteredViewState = { ...defaultState },\n\t\tprivate centeredLayoutFixedWidth: boolean = false\n\t) {\n\t\tthis.container.appendChild(this.view.element);\n\t\t// Make sure to hide the split view overflow like sashes #52892\n\t\tthis.container.style.overflow = 'hidden';\n\t}\n\n\tget minimumWidth(): number { return this.splitView ? this.splitView.minimumSize : this.view.minimumWidth; }\n\tget maximumWidth(): number { return this.splitView ? this.splitView.maximumSize : this.view.maximumWidth; }\n\tget minimumHeight(): number { return this.view.minimumHeight; }\n\tget maximumHeight(): number { return this.view.maximumHeight; }\n\tget onDidChange(): Event { return this.view.onDidChange; }\n\n\tprivate _boundarySashes: IBoundarySashes = {};\n\tget boundarySashes(): IBoundarySashes { return this._boundarySashes; }\n\tset boundarySashes(boundarySashes: IBoundarySashes) {\n\t\tthis._boundarySashes = boundarySashes;\n\n\t\tif (!this.splitView) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.splitView.orthogonalStartSash = boundarySashes.top;\n\t\tthis.splitView.orthogonalEndSash = boundarySashes.bottom;\n\t}\n\n\tlayout(width: number, height: number, top: number, left: number): void {\n\t\tthis.lastLayoutPosition = { width, height, top, left };\n\t\tif (this.splitView) {\n\t\t\tthis.splitView.layout(width, this.lastLayoutPosition);\n\t\t\tif (!this.didLayout || this.centeredLayoutFixedWidth) {\n\t\t\t\tthis.resizeSplitViews();\n\t\t\t}\n\t\t} else {\n\t\t\tthis.view.layout(width, height, top, left);\n\t\t}\n\n\t\tthis.didLayout = true;\n\t}\n\n\tprivate resizeSplitViews(): void {\n\t\tif (!this.splitView) {\n\t\t\treturn;\n\t\t}\n\t\tif (this.centeredLayoutFixedWidth) {\n\t\t\tconst centerViewWidth = Math.min(this.lastLayoutPosition.width, this.state.targetWidth);\n\t\t\tconst marginWidthFloat = (this.lastLayoutPosition.width - centerViewWidth) / 2;\n\t\t\tthis.splitView.resizeView(0, Math.floor(marginWidthFloat));\n\t\t\tthis.splitView.resizeView(1, centerViewWidth);\n\t\t\tthis.splitView.resizeView(2, Math.ceil(marginWidthFloat));\n\t\t} else {\n\t\t\tconst leftMargin = this.state.leftMarginRatio * this.lastLayoutPosition.width;\n\t\t\tconst rightMargin = this.state.rightMarginRatio * this.lastLayoutPosition.width;\n\t\t\tconst center = this.lastLayoutPosition.width - leftMargin - rightMargin;\n\t\t\tthis.splitView.resizeView(0, leftMargin);\n\t\t\tthis.splitView.resizeView(1, center);\n\t\t\tthis.splitView.resizeView(2, rightMargin);\n\t\t}\n\t}\n\n\tsetFixedWidth(option: boolean) {\n\t\tthis.centeredLayoutFixedWidth = option;\n\t\tif (!!this.splitView) {\n\t\t\tthis.updateState();\n\t\t\tthis.resizeSplitViews();\n\t\t}\n\t}\n\n\tprivate updateState() {\n\t\tif (!!this.splitView) {\n\t\t\tthis.state.targetWidth = this.splitView.getViewSize(1);\n\t\t\tthis.state.leftMarginRatio = this.splitView.getViewSize(0) / this.lastLayoutPosition.width;\n\t\t\tthis.state.rightMarginRatio = this.splitView.getViewSize(2) / this.lastLayoutPosition.width;\n\t\t}\n\t}\n\n\tisActive(): boolean {\n\t\treturn !!this.splitView;\n\t}\n\n\tstyles(style: ICenteredViewStyles): void {\n\t\tthis.style = style;\n\t\tif (this.splitView && this.emptyViews) {\n\t\t\tthis.splitView.style(this.style);\n\t\t\tthis.emptyViews[0].element.style.backgroundColor = this.style.background.toString();\n\t\t\tthis.emptyViews[1].element.style.backgroundColor = this.style.background.toString();\n\t\t}\n\t}\n\n\tactivate(active: boolean): void {\n\t\tif (active === this.isActive()) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (active) {\n\t\t\tthis.container.removeChild(this.view.element);\n\t\t\tthis.splitView = new SplitView(this.container, {\n\t\t\t\tinverseAltBehavior: true,\n\t\t\t\torientation: Orientation.HORIZONTAL,\n\t\t\t\tstyles: this.style\n\t\t\t});\n\t\t\tthis.splitView.orthogonalStartSash = this.boundarySashes.top;\n\t\t\tthis.splitView.orthogonalEndSash = this.boundarySashes.bottom;\n\n\t\t\tthis.splitViewDisposables.add(this.splitView.onDidSashChange(() => {\n\t\t\t\tif (!!this.splitView) {\n\t\t\t\t\tthis.updateState();\n\t\t\t\t}\n\t\t\t}));\n\t\t\tthis.splitViewDisposables.add(this.splitView.onDidSashReset(() => {\n\t\t\t\tthis.state = { ...defaultState };\n\t\t\t\tthis.resizeSplitViews();\n\t\t\t}));\n\n\t\t\tthis.splitView.layout(this.lastLayoutPosition.width, this.lastLayoutPosition);\n\t\t\tconst backgroundColor = this.style ? this.style.background : undefined;\n\t\t\tthis.emptyViews = [createEmptyView(backgroundColor), createEmptyView(backgroundColor)];\n\n\t\t\tthis.splitView.addView(this.emptyViews[0], distributeSizing, 0);\n\t\t\tthis.splitView.addView(toSplitViewView(this.view, () => this.lastLayoutPosition.height), distributeSizing, 1);\n\t\t\tthis.splitView.addView(this.emptyViews[1], distributeSizing, 2);\n\n\t\t\tthis.resizeSplitViews();\n\t\t} else {\n\t\t\tif (this.splitView) {\n\t\t\t\tthis.container.removeChild(this.splitView.el);\n\t\t\t}\n\t\t\tthis.splitViewDisposables.clear();\n\t\t\tthis.splitView?.dispose();\n\t\t\tthis.splitView = undefined;\n\t\t\tthis.emptyViews = undefined;\n\t\t\tthis.container.appendChild(this.view.element);\n\t\t\tthis.view.layout(this.lastLayoutPosition.width, this.lastLayoutPosition.height, this.lastLayoutPosition.top, this.lastLayoutPosition.left);\n\t\t}\n\t}\n\n\tisDefault(state: CenteredViewState): boolean {\n\t\tif (this.centeredLayoutFixedWidth) {\n\t\t\treturn state.targetWidth === defaultState.targetWidth;\n\t\t} else {\n\t\t\treturn state.leftMarginRatio === defaultState.leftMarginRatio\n\t\t\t\t&& state.rightMarginRatio === defaultState.rightMarginRatio;\n\t\t}\n\t}\n\n\tdispose(): void {\n\t\tthis.splitViewDisposables.dispose();\n\n\t\tif (this.splitView) {\n\t\t\tthis.splitView.dispose();\n\t\t\tthis.splitView = 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 { $ } from 'vs/base/browser/dom';\nimport { IBoundarySashes, Orientation, Sash } from 'vs/base/browser/ui/sash/sash';\nimport { DistributeSizing, ISplitViewStyles, IView as ISplitView, LayoutPriority, Sizing, AutoSizing, SplitView } from 'vs/base/browser/ui/splitview/splitview';\nimport { equals as arrayEquals, tail2 as tail } from 'vs/base/common/arrays';\nimport { Color } from 'vs/base/common/color';\nimport { Emitter, Event, Relay } from 'vs/base/common/event';\nimport { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';\nimport { rot } from 'vs/base/common/numbers';\nimport { isUndefined } from 'vs/base/common/types';\nimport 'vs/css!./gridview';\n\nexport { Orientation } from 'vs/base/browser/ui/sash/sash';\nexport { LayoutPriority, Sizing } from 'vs/base/browser/ui/splitview/splitview';\n\nexport interface IGridViewStyles extends ISplitViewStyles { }\n\nconst defaultStyles: IGridViewStyles = {\n\tseparatorBorder: Color.transparent\n};\n\nexport interface IViewSize {\n\treadonly width: number;\n\treadonly height: number;\n}\n\ninterface IRelativeBoundarySashes {\n\treadonly start?: Sash;\n\treadonly end?: Sash;\n\treadonly orthogonalStart?: Sash;\n\treadonly orthogonalEnd?: Sash;\n}\n\n/**\n * The interface to implement for views within a {@link GridView}.\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 width for this view.\n\t *\n\t * @remarks If none, set it to `0`.\n\t */\n\treadonly minimumWidth: number;\n\n\t/**\n\t * A minimum width for this view.\n\t *\n\t * @remarks If none, set it to `Number.POSITIVE_INFINITY`.\n\t */\n\treadonly maximumWidth: number;\n\n\t/**\n\t * A minimum height for this view.\n\t *\n\t * @remarks If none, set it to `0`.\n\t */\n\treadonly minimumHeight: number;\n\n\t/**\n\t * A minimum height for this view.\n\t *\n\t * @remarks If none, set it to `Number.POSITIVE_INFINITY`.\n\t */\n\treadonly maximumHeight: number;\n\n\t/**\n\t * The priority of the view when the {@link GridView} 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 GridView} supports 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 this event whenever any of the constraint\n\t * properties have changed:\n\t *\n\t * - {@link IView.minimumWidth}\n\t * - {@link IView.maximumWidth}\n\t * - {@link IView.minimumHeight}\n\t * - {@link IView.maximumHeight}\n\t * - {@link IView.priority}\n\t * - {@link IView.snap}\n\t *\n\t * The {@link GridView} will relayout whenever that happens. The event can\n\t * optionally emit 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 GridView} during layout. A view meant to\n\t * pass along the layout information down to its descendants.\n\t */\n\tlayout(width: number, height: number, top: number, left: number): void;\n\n\t/**\n\t * This will be called by the {@link GridView} 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\t/**\n\t * This will be called by the {@link GridView} whenever this view is on\n\t * an edge of the grid and the grid's\n\t * {@link GridView.boundarySashes boundary sashes} change.\n\t */\n\tsetBoundarySashes?(sashes: IBoundarySashes): void;\n}\n\nexport interface ISerializableView extends IView {\n\ttoJSON(): object;\n}\n\nexport interface IViewDeserializer {\n\tfromJSON(json: any): T;\n}\n\nexport interface ISerializedLeafNode {\n\ttype: 'leaf';\n\tdata: any;\n\tsize: number;\n\tvisible?: boolean;\n\tmaximized?: boolean;\n}\n\nexport interface ISerializedBranchNode {\n\ttype: 'branch';\n\tdata: ISerializedNode[];\n\tsize: number;\n\tvisible?: boolean;\n}\n\nexport type ISerializedNode = ISerializedLeafNode | ISerializedBranchNode;\n\nexport interface ISerializedGridView {\n\troot: ISerializedNode;\n\torientation: Orientation;\n\twidth: number;\n\theight: number;\n}\n\nexport function orthogonal(orientation: Orientation): Orientation {\n\treturn orientation === Orientation.VERTICAL ? Orientation.HORIZONTAL : Orientation.VERTICAL;\n}\n\nexport interface Box {\n\treadonly top: number;\n\treadonly left: number;\n\treadonly width: number;\n\treadonly height: number;\n}\n\nexport interface GridLeafNode {\n\treadonly view: IView;\n\treadonly box: Box;\n\treadonly cachedVisibleSize: number | undefined;\n\treadonly maximized: boolean;\n}\n\nexport interface GridBranchNode {\n\treadonly children: GridNode[];\n\treadonly box: Box;\n}\n\nexport type GridNode = GridLeafNode | GridBranchNode;\n\nexport function isGridBranchNode(node: GridNode): node is GridBranchNode {\n\treturn !!(node as any).children;\n}\n\nclass LayoutController {\n\tconstructor(public isLayoutEnabled: boolean) { }\n}\n\nexport interface IGridViewOptions {\n\n\t/**\n\t * Styles overriding the {@link defaultStyles default ones}.\n\t */\n\treadonly styles?: IGridViewStyles;\n\n\t/**\n\t * Resize each view proportionally when resizing the {@link GridView}.\n\t *\n\t * @defaultValue `true`\n\t */\n\treadonly proportionalLayout?: boolean; // default true\n}\n\ninterface ILayoutContext {\n\treadonly orthogonalSize: number;\n\treadonly absoluteOffset: number;\n\treadonly absoluteOrthogonalOffset: number;\n\treadonly absoluteSize: number;\n\treadonly absoluteOrthogonalSize: number;\n}\n\nfunction toAbsoluteBoundarySashes(sashes: IRelativeBoundarySashes, orientation: Orientation): IBoundarySashes {\n\tif (orientation === Orientation.HORIZONTAL) {\n\t\treturn { left: sashes.start, right: sashes.end, top: sashes.orthogonalStart, bottom: sashes.orthogonalEnd };\n\t} else {\n\t\treturn { top: sashes.start, bottom: sashes.end, left: sashes.orthogonalStart, right: sashes.orthogonalEnd };\n\t}\n}\n\nfunction fromAbsoluteBoundarySashes(sashes: IBoundarySashes, orientation: Orientation): IRelativeBoundarySashes {\n\tif (orientation === Orientation.HORIZONTAL) {\n\t\treturn { start: sashes.left, end: sashes.right, orthogonalStart: sashes.top, orthogonalEnd: sashes.bottom };\n\t} else {\n\t\treturn { start: sashes.top, end: sashes.bottom, orthogonalStart: sashes.left, orthogonalEnd: sashes.right };\n\t}\n}\n\nfunction validateIndex(index: number, numChildren: number): number {\n\tif (Math.abs(index) > numChildren) {\n\t\tthrow new Error('Invalid index');\n\t}\n\n\treturn rot(index, numChildren + 1);\n}\n\nclass BranchNode implements ISplitView, IDisposable {\n\n\treadonly element: HTMLElement;\n\treadonly children: Node[] = [];\n\tprivate splitview: SplitView;\n\n\tprivate _size: number;\n\tget size(): number { return this._size; }\n\n\tprivate _orthogonalSize: number;\n\tget orthogonalSize(): number { return this._orthogonalSize; }\n\n\tprivate _absoluteOffset: number = 0;\n\tget absoluteOffset(): number { return this._absoluteOffset; }\n\n\tprivate _absoluteOrthogonalOffset: number = 0;\n\tget absoluteOrthogonalOffset(): number { return this._absoluteOrthogonalOffset; }\n\n\tprivate absoluteOrthogonalSize: number = 0;\n\n\tprivate _styles: IGridViewStyles;\n\tget styles(): IGridViewStyles { return this._styles; }\n\n\tget width(): number {\n\t\treturn this.orientation === Orientation.HORIZONTAL ? this.size : this.orthogonalSize;\n\t}\n\n\tget height(): number {\n\t\treturn this.orientation === Orientation.HORIZONTAL ? this.orthogonalSize : this.size;\n\t}\n\n\tget top(): number {\n\t\treturn this.orientation === Orientation.HORIZONTAL ? this._absoluteOffset : this._absoluteOrthogonalOffset;\n\t}\n\n\tget left(): number {\n\t\treturn this.orientation === Orientation.HORIZONTAL ? this._absoluteOrthogonalOffset : this._absoluteOffset;\n\t}\n\n\tget minimumSize(): number {\n\t\treturn this.children.length === 0 ? 0 : Math.max(...this.children.map((c, index) => this.splitview.isViewVisible(index) ? c.minimumOrthogonalSize : 0));\n\t}\n\n\tget maximumSize(): number {\n\t\treturn Math.min(...this.children.map((c, index) => this.splitview.isViewVisible(index) ? c.maximumOrthogonalSize : Number.POSITIVE_INFINITY));\n\t}\n\n\tget priority(): LayoutPriority {\n\t\tif (this.children.length === 0) {\n\t\t\treturn LayoutPriority.Normal;\n\t\t}\n\n\t\tconst priorities = this.children.map(c => typeof c.priority === 'undefined' ? LayoutPriority.Normal : c.priority);\n\n\t\tif (priorities.some(p => p === LayoutPriority.High)) {\n\t\t\treturn LayoutPriority.High;\n\t\t} else if (priorities.some(p => p === LayoutPriority.Low)) {\n\t\t\treturn LayoutPriority.Low;\n\t\t}\n\n\t\treturn LayoutPriority.Normal;\n\t}\n\n\tget proportionalLayout(): boolean {\n\t\tif (this.children.length === 0) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn this.children.every(c => c.proportionalLayout);\n\t}\n\n\tget minimumOrthogonalSize(): number {\n\t\treturn this.splitview.minimumSize;\n\t}\n\n\tget maximumOrthogonalSize(): number {\n\t\treturn this.splitview.maximumSize;\n\t}\n\n\tget minimumWidth(): number {\n\t\treturn this.orientation === Orientation.HORIZONTAL ? this.minimumOrthogonalSize : this.minimumSize;\n\t}\n\n\tget minimumHeight(): number {\n\t\treturn this.orientation === Orientation.HORIZONTAL ? this.minimumSize : this.minimumOrthogonalSize;\n\t}\n\n\tget maximumWidth(): number {\n\t\treturn this.orientation === Orientation.HORIZONTAL ? this.maximumOrthogonalSize : this.maximumSize;\n\t}\n\n\tget maximumHeight(): number {\n\t\treturn this.orientation === Orientation.HORIZONTAL ? this.maximumSize : this.maximumOrthogonalSize;\n\t}\n\n\tprivate readonly _onDidChange = new Emitter();\n\treadonly onDidChange: Event = this._onDidChange.event;\n\n\tprivate readonly _onDidVisibilityChange = new Emitter();\n\treadonly onDidVisibilityChange: Event = this._onDidVisibilityChange.event;\n\tprivate readonly childrenVisibilityChangeDisposable: DisposableStore = new DisposableStore();\n\n\tprivate _onDidScroll = new Emitter();\n\tprivate onDidScrollDisposable: IDisposable = Disposable.None;\n\treadonly onDidScroll: Event = this._onDidScroll.event;\n\n\tprivate childrenChangeDisposable: IDisposable = Disposable.None;\n\n\tprivate readonly _onDidSashReset = new Emitter();\n\treadonly onDidSashReset: Event = this._onDidSashReset.event;\n\tprivate splitviewSashResetDisposable: IDisposable = Disposable.None;\n\tprivate childrenSashResetDisposable: IDisposable = Disposable.None;\n\n\tprivate _boundarySashes: IRelativeBoundarySashes = {};\n\tget boundarySashes(): IRelativeBoundarySashes { return this._boundarySashes; }\n\tset boundarySashes(boundarySashes: IRelativeBoundarySashes) {\n\t\tif (this._boundarySashes.start === boundarySashes.start\n\t\t\t&& this._boundarySashes.end === boundarySashes.end\n\t\t\t&& this._boundarySashes.orthogonalStart === boundarySashes.orthogonalStart\n\t\t\t&& this._boundarySashes.orthogonalEnd === boundarySashes.orthogonalEnd) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._boundarySashes = boundarySashes;\n\n\t\tthis.splitview.orthogonalStartSash = boundarySashes.orthogonalStart;\n\t\tthis.splitview.orthogonalEndSash = boundarySashes.orthogonalEnd;\n\n\t\tfor (let index = 0; index < this.children.length; index++) {\n\t\t\tconst child = this.children[index];\n\t\t\tconst first = index === 0;\n\t\t\tconst last = index === this.children.length - 1;\n\n\t\t\tchild.boundarySashes = {\n\t\t\t\tstart: boundarySashes.orthogonalStart,\n\t\t\t\tend: boundarySashes.orthogonalEnd,\n\t\t\t\torthogonalStart: first ? boundarySashes.start : child.boundarySashes.orthogonalStart,\n\t\t\t\torthogonalEnd: last ? boundarySashes.end : child.boundarySashes.orthogonalEnd,\n\t\t\t};\n\t\t}\n\t}\n\n\tprivate _edgeSnapping = false;\n\tget edgeSnapping(): boolean { return this._edgeSnapping; }\n\tset edgeSnapping(edgeSnapping: boolean) {\n\t\tif (this._edgeSnapping === edgeSnapping) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._edgeSnapping = edgeSnapping;\n\n\t\tfor (const child of this.children) {\n\t\t\tif (child instanceof BranchNode) {\n\t\t\t\tchild.edgeSnapping = edgeSnapping;\n\t\t\t}\n\t\t}\n\n\t\tthis.updateSplitviewEdgeSnappingEnablement();\n\t}\n\n\tconstructor(\n\t\treadonly orientation: Orientation,\n\t\treadonly layoutController: LayoutController,\n\t\tstyles: IGridViewStyles,\n\t\treadonly splitviewProportionalLayout: boolean,\n\t\tsize: number = 0,\n\t\torthogonalSize: number = 0,\n\t\tedgeSnapping: boolean = false,\n\t\tchildDescriptors?: INodeDescriptor[]\n\t) {\n\t\tthis._styles = styles;\n\t\tthis._size = size;\n\t\tthis._orthogonalSize = orthogonalSize;\n\n\t\tthis.element = $('.monaco-grid-branch-node');\n\n\t\tif (!childDescriptors) {\n\t\t\t// Normal behavior, we have no children yet, just set up the splitview\n\t\t\tthis.splitview = new SplitView(this.element, { orientation, styles, proportionalLayout: splitviewProportionalLayout });\n\t\t\tthis.splitview.layout(size, { orthogonalSize, absoluteOffset: 0, absoluteOrthogonalOffset: 0, absoluteSize: size, absoluteOrthogonalSize: orthogonalSize });\n\t\t} else {\n\t\t\t// Reconstruction behavior, we want to reconstruct a splitview\n\t\t\tconst descriptor = {\n\t\t\t\tviews: childDescriptors.map(childDescriptor => {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tview: childDescriptor.node,\n\t\t\t\t\t\tsize: childDescriptor.node.size,\n\t\t\t\t\t\tvisible: childDescriptor.visible !== false\n\t\t\t\t\t};\n\t\t\t\t}),\n\t\t\t\tsize: this.orthogonalSize\n\t\t\t};\n\n\t\t\tconst options = { proportionalLayout: splitviewProportionalLayout, orientation, styles };\n\n\t\t\tthis.children = childDescriptors.map(c => c.node);\n\t\t\tthis.splitview = new SplitView(this.element, { ...options, descriptor });\n\n\t\t\tthis.children.forEach((node, index) => {\n\t\t\t\tconst first = index === 0;\n\t\t\t\tconst last = index === this.children.length;\n\n\t\t\t\tnode.boundarySashes = {\n\t\t\t\t\tstart: this.boundarySashes.orthogonalStart,\n\t\t\t\t\tend: this.boundarySashes.orthogonalEnd,\n\t\t\t\t\torthogonalStart: first ? this.boundarySashes.start : this.splitview.sashes[index - 1],\n\t\t\t\t\torthogonalEnd: last ? this.boundarySashes.end : this.splitview.sashes[index],\n\t\t\t\t};\n\t\t\t});\n\t\t}\n\n\t\tconst onDidSashReset = Event.map(this.splitview.onDidSashReset, i => [i]);\n\t\tthis.splitviewSashResetDisposable = onDidSashReset(this._onDidSashReset.fire, this._onDidSashReset);\n\n\t\tthis.updateChildrenEvents();\n\t}\n\n\tstyle(styles: IGridViewStyles): void {\n\t\tthis._styles = styles;\n\t\tthis.splitview.style(styles);\n\n\t\tfor (const child of this.children) {\n\t\t\tif (child instanceof BranchNode) {\n\t\t\t\tchild.style(styles);\n\t\t\t}\n\t\t}\n\t}\n\n\tlayout(size: number, offset: number, ctx: ILayoutContext | undefined): void {\n\t\tif (!this.layoutController.isLayoutEnabled) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (typeof ctx === 'undefined') {\n\t\t\tthrow new Error('Invalid state');\n\t\t}\n\n\t\t// branch nodes should flip the normal/orthogonal directions\n\t\tthis._size = ctx.orthogonalSize;\n\t\tthis._orthogonalSize = size;\n\t\tthis._absoluteOffset = ctx.absoluteOffset + offset;\n\t\tthis._absoluteOrthogonalOffset = ctx.absoluteOrthogonalOffset;\n\t\tthis.absoluteOrthogonalSize = ctx.absoluteOrthogonalSize;\n\n\t\tthis.splitview.layout(ctx.orthogonalSize, {\n\t\t\torthogonalSize: size,\n\t\t\tabsoluteOffset: this._absoluteOrthogonalOffset,\n\t\t\tabsoluteOrthogonalOffset: this._absoluteOffset,\n\t\t\tabsoluteSize: ctx.absoluteOrthogonalSize,\n\t\t\tabsoluteOrthogonalSize: ctx.absoluteSize\n\t\t});\n\n\t\tthis.updateSplitviewEdgeSnappingEnablement();\n\t}\n\n\tsetVisible(visible: boolean): void {\n\t\tfor (const child of this.children) {\n\t\t\tchild.setVisible(visible);\n\t\t}\n\t}\n\n\taddChild(node: Node, size: number | Sizing, index: number, skipLayout?: boolean): void {\n\t\tindex = validateIndex(index, this.children.length);\n\n\t\tthis.splitview.addView(node, size, index, skipLayout);\n\t\tthis.children.splice(index, 0, node);\n\n\t\tthis.updateBoundarySashes();\n\t\tthis.onDidChildrenChange();\n\t}\n\n\tremoveChild(index: number, sizing?: Sizing): Node {\n\t\tindex = validateIndex(index, this.children.length);\n\n\t\tconst result = this.splitview.removeView(index, sizing);\n\t\tthis.children.splice(index, 1);\n\n\t\tthis.updateBoundarySashes();\n\t\tthis.onDidChildrenChange();\n\n\t\treturn result;\n\t}\n\n\tremoveAllChildren(): Node[] {\n\t\tconst result = this.splitview.removeAllViews();\n\n\t\tthis.children.splice(0, this.children.length);\n\n\t\tthis.updateBoundarySashes();\n\t\tthis.onDidChildrenChange();\n\n\t\treturn result;\n\t}\n\n\tmoveChild(from: number, to: number): void {\n\t\tfrom = validateIndex(from, this.children.length);\n\t\tto = validateIndex(to, this.children.length);\n\n\t\tif (from === to) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (from < to) {\n\t\t\tto -= 1;\n\t\t}\n\n\t\tthis.splitview.moveView(from, to);\n\t\tthis.children.splice(to, 0, this.children.splice(from, 1)[0]);\n\n\t\tthis.updateBoundarySashes();\n\t\tthis.onDidChildrenChange();\n\t}\n\n\tswapChildren(from: number, to: number): void {\n\t\tfrom = validateIndex(from, this.children.length);\n\t\tto = validateIndex(to, this.children.length);\n\n\t\tif (from === to) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.splitview.swapViews(from, to);\n\n\t\t// swap boundary sashes\n\t\t[this.children[from].boundarySashes, this.children[to].boundarySashes]\n\t\t\t= [this.children[from].boundarySashes, this.children[to].boundarySashes];\n\n\t\t// swap children\n\t\t[this.children[from], this.children[to]] = [this.children[to], this.children[from]];\n\n\t\tthis.onDidChildrenChange();\n\t}\n\n\tresizeChild(index: number, size: number): void {\n\t\tindex = validateIndex(index, this.children.length);\n\n\t\tthis.splitview.resizeView(index, size);\n\t}\n\n\tisChildExpanded(index: number): boolean {\n\t\treturn this.splitview.isViewExpanded(index);\n\t}\n\n\tdistributeViewSizes(recursive = false): void {\n\t\tthis.splitview.distributeViewSizes();\n\n\t\tif (recursive) {\n\t\t\tfor (const child of this.children) {\n\t\t\t\tif (child instanceof BranchNode) {\n\t\t\t\t\tchild.distributeViewSizes(true);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tgetChildSize(index: number): number {\n\t\tindex = validateIndex(index, this.children.length);\n\n\t\treturn this.splitview.getViewSize(index);\n\t}\n\n\tisChildVisible(index: number): boolean {\n\t\tindex = validateIndex(index, this.children.length);\n\n\t\treturn this.splitview.isViewVisible(index);\n\t}\n\n\tsetChildVisible(index: number, visible: boolean): void {\n\t\tindex = validateIndex(index, this.children.length);\n\n\t\tif (this.splitview.isViewVisible(index) === visible) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst wereAllChildrenHidden = this.splitview.contentSize === 0;\n\t\tthis.splitview.setViewVisible(index, visible);\n\t\tconst areAllChildrenHidden = this.splitview.contentSize === 0;\n\n\t\t// If all children are hidden then the parent should hide the entire splitview\n\t\t// If the entire splitview is hidden then the parent should show the splitview when a child is shown\n\t\tif ((visible && wereAllChildrenHidden) || (!visible && areAllChildrenHidden)) {\n\t\t\tthis._onDidVisibilityChange.fire(visible);\n\t\t}\n\t}\n\n\tgetChildCachedVisibleSize(index: number): number | undefined {\n\t\tindex = validateIndex(index, this.children.length);\n\n\t\treturn this.splitview.getViewCachedVisibleSize(index);\n\t}\n\n\tprivate updateBoundarySashes(): void {\n\t\tfor (let i = 0; i < this.children.length; i++) {\n\t\t\tthis.children[i].boundarySashes = {\n\t\t\t\tstart: this.boundarySashes.orthogonalStart,\n\t\t\t\tend: this.boundarySashes.orthogonalEnd,\n\t\t\t\torthogonalStart: i === 0 ? this.boundarySashes.start : this.splitview.sashes[i - 1],\n\t\t\t\torthogonalEnd: i === this.children.length - 1 ? this.boundarySashes.end : this.splitview.sashes[i],\n\t\t\t};\n\t\t}\n\t}\n\n\tprivate onDidChildrenChange(): void {\n\t\tthis.updateChildrenEvents();\n\t\tthis._onDidChange.fire(undefined);\n\t}\n\n\tprivate updateChildrenEvents(): void {\n\t\tconst onDidChildrenChange = Event.map(Event.any(...this.children.map(c => c.onDidChange)), () => undefined);\n\t\tthis.childrenChangeDisposable.dispose();\n\t\tthis.childrenChangeDisposable = onDidChildrenChange(this._onDidChange.fire, this._onDidChange);\n\n\t\tconst onDidChildrenSashReset = Event.any(...this.children.map((c, i) => Event.map(c.onDidSashReset, location => [i, ...location])));\n\t\tthis.childrenSashResetDisposable.dispose();\n\t\tthis.childrenSashResetDisposable = onDidChildrenSashReset(this._onDidSashReset.fire, this._onDidSashReset);\n\n\t\tconst onDidScroll = Event.any(Event.signal(this.splitview.onDidScroll), ...this.children.map(c => c.onDidScroll));\n\t\tthis.onDidScrollDisposable.dispose();\n\t\tthis.onDidScrollDisposable = onDidScroll(this._onDidScroll.fire, this._onDidScroll);\n\n\t\tthis.childrenVisibilityChangeDisposable.clear();\n\t\tthis.children.forEach((child, index) => {\n\t\t\tif (child instanceof BranchNode) {\n\t\t\t\tthis.childrenVisibilityChangeDisposable.add(child.onDidVisibilityChange((visible) => {\n\t\t\t\t\tthis.setChildVisible(index, visible);\n\t\t\t\t}));\n\t\t\t}\n\t\t});\n\t}\n\n\ttrySet2x2(other: BranchNode): IDisposable {\n\t\tif (this.children.length !== 2 || other.children.length !== 2) {\n\t\t\treturn Disposable.None;\n\t\t}\n\n\t\tif (this.getChildSize(0) !== other.getChildSize(0)) {\n\t\t\treturn Disposable.None;\n\t\t}\n\n\t\tconst [firstChild, secondChild] = this.children;\n\t\tconst [otherFirstChild, otherSecondChild] = other.children;\n\n\t\tif (!(firstChild instanceof LeafNode) || !(secondChild instanceof LeafNode)) {\n\t\t\treturn Disposable.None;\n\t\t}\n\n\t\tif (!(otherFirstChild instanceof LeafNode) || !(otherSecondChild instanceof LeafNode)) {\n\t\t\treturn Disposable.None;\n\t\t}\n\n\t\tif (this.orientation === Orientation.VERTICAL) {\n\t\t\tsecondChild.linkedWidthNode = otherFirstChild.linkedHeightNode = firstChild;\n\t\t\tfirstChild.linkedWidthNode = otherSecondChild.linkedHeightNode = secondChild;\n\t\t\totherSecondChild.linkedWidthNode = firstChild.linkedHeightNode = otherFirstChild;\n\t\t\totherFirstChild.linkedWidthNode = secondChild.linkedHeightNode = otherSecondChild;\n\t\t} else {\n\t\t\totherFirstChild.linkedWidthNode = secondChild.linkedHeightNode = firstChild;\n\t\t\totherSecondChild.linkedWidthNode = firstChild.linkedHeightNode = secondChild;\n\t\t\tfirstChild.linkedWidthNode = otherSecondChild.linkedHeightNode = otherFirstChild;\n\t\t\tsecondChild.linkedWidthNode = otherFirstChild.linkedHeightNode = otherSecondChild;\n\t\t}\n\n\t\tconst mySash = this.splitview.sashes[0];\n\t\tconst otherSash = other.splitview.sashes[0];\n\t\tmySash.linkedSash = otherSash;\n\t\totherSash.linkedSash = mySash;\n\n\t\tthis._onDidChange.fire(undefined);\n\t\tother._onDidChange.fire(undefined);\n\n\t\treturn toDisposable(() => {\n\t\t\tmySash.linkedSash = otherSash.linkedSash = undefined;\n\t\t\tfirstChild.linkedHeightNode = firstChild.linkedWidthNode = undefined;\n\t\t\tsecondChild.linkedHeightNode = secondChild.linkedWidthNode = undefined;\n\t\t\totherFirstChild.linkedHeightNode = otherFirstChild.linkedWidthNode = undefined;\n\t\t\totherSecondChild.linkedHeightNode = otherSecondChild.linkedWidthNode = undefined;\n\t\t});\n\t}\n\n\tprivate updateSplitviewEdgeSnappingEnablement(): void {\n\t\tthis.splitview.startSnappingEnabled = this._edgeSnapping || this._absoluteOrthogonalOffset > 0;\n\t\tthis.splitview.endSnappingEnabled = this._edgeSnapping || this._absoluteOrthogonalOffset + this._size < this.absoluteOrthogonalSize;\n\t}\n\n\tdispose(): void {\n\t\tfor (const child of this.children) {\n\t\t\tchild.dispose();\n\t\t}\n\n\t\tthis._onDidChange.dispose();\n\t\tthis._onDidSashReset.dispose();\n\t\tthis._onDidVisibilityChange.dispose();\n\n\t\tthis.childrenVisibilityChangeDisposable.dispose();\n\t\tthis.splitviewSashResetDisposable.dispose();\n\t\tthis.childrenSashResetDisposable.dispose();\n\t\tthis.childrenChangeDisposable.dispose();\n\t\tthis.onDidScrollDisposable.dispose();\n\t\tthis.splitview.dispose();\n\t}\n}\n\n/**\n * Creates a latched event that avoids being fired when the view\n * constraints do not change at all.\n */\nfunction createLatchedOnDidChangeViewEvent(view: IView): Event {\n\tconst [onDidChangeViewConstraints, onDidSetViewSize] = Event.split(view.onDidChange, isUndefined);\n\n\treturn Event.any(\n\t\tonDidSetViewSize,\n\t\tEvent.map(\n\t\t\tEvent.latch(\n\t\t\t\tEvent.map(onDidChangeViewConstraints, _ => ([view.minimumWidth, view.maximumWidth, view.minimumHeight, view.maximumHeight])),\n\t\t\t\tarrayEquals\n\t\t\t),\n\t\t\t_ => undefined\n\t\t)\n\t);\n}\n\nclass LeafNode implements ISplitView, IDisposable {\n\n\tprivate _size: number = 0;\n\tget size(): number { return this._size; }\n\n\tprivate _orthogonalSize: number;\n\tget orthogonalSize(): number { return this._orthogonalSize; }\n\n\tprivate absoluteOffset: number = 0;\n\tprivate absoluteOrthogonalOffset: number = 0;\n\n\treadonly onDidScroll: Event = Event.None;\n\treadonly onDidSashReset: Event = Event.None;\n\n\tprivate _onDidLinkedWidthNodeChange = new Relay();\n\tprivate _linkedWidthNode: LeafNode | undefined = undefined;\n\tget linkedWidthNode(): LeafNode | undefined { return this._linkedWidthNode; }\n\tset linkedWidthNode(node: LeafNode | undefined) {\n\t\tthis._onDidLinkedWidthNodeChange.input = node ? node._onDidViewChange : Event.None;\n\t\tthis._linkedWidthNode = node;\n\t\tthis._onDidSetLinkedNode.fire(undefined);\n\t}\n\n\tprivate _onDidLinkedHeightNodeChange = new Relay();\n\tprivate _linkedHeightNode: LeafNode | undefined = undefined;\n\tget linkedHeightNode(): LeafNode | undefined { return this._linkedHeightNode; }\n\tset linkedHeightNode(node: LeafNode | undefined) {\n\t\tthis._onDidLinkedHeightNodeChange.input = node ? node._onDidViewChange : Event.None;\n\t\tthis._linkedHeightNode = node;\n\t\tthis._onDidSetLinkedNode.fire(undefined);\n\t}\n\n\tprivate readonly _onDidSetLinkedNode = new Emitter();\n\tprivate _onDidViewChange: Event;\n\treadonly onDidChange: Event;\n\n\tprivate readonly disposables = new DisposableStore();\n\n\tconstructor(\n\t\treadonly view: IView,\n\t\treadonly orientation: Orientation,\n\t\treadonly layoutController: LayoutController,\n\t\torthogonalSize: number,\n\t\tsize: number = 0\n\t) {\n\t\tthis._orthogonalSize = orthogonalSize;\n\t\tthis._size = size;\n\n\t\tconst onDidChange = createLatchedOnDidChangeViewEvent(view);\n\t\tthis._onDidViewChange = Event.map(onDidChange, e => e && (this.orientation === Orientation.VERTICAL ? e.width : e.height), this.disposables);\n\t\tthis.onDidChange = Event.any(this._onDidViewChange, this._onDidSetLinkedNode.event, this._onDidLinkedWidthNodeChange.event, this._onDidLinkedHeightNodeChange.event);\n\t}\n\n\tget width(): number {\n\t\treturn this.orientation === Orientation.HORIZONTAL ? this.orthogonalSize : this.size;\n\t}\n\n\tget height(): number {\n\t\treturn this.orientation === Orientation.HORIZONTAL ? this.size : this.orthogonalSize;\n\t}\n\n\tget top(): number {\n\t\treturn this.orientation === Orientation.HORIZONTAL ? this.absoluteOffset : this.absoluteOrthogonalOffset;\n\t}\n\n\tget left(): number {\n\t\treturn this.orientation === Orientation.HORIZONTAL ? this.absoluteOrthogonalOffset : this.absoluteOffset;\n\t}\n\n\tget element(): HTMLElement {\n\t\treturn this.view.element;\n\t}\n\n\tprivate get minimumWidth(): number {\n\t\treturn this.linkedWidthNode ? Math.max(this.linkedWidthNode.view.minimumWidth, this.view.minimumWidth) : this.view.minimumWidth;\n\t}\n\n\tprivate get maximumWidth(): number {\n\t\treturn this.linkedWidthNode ? Math.min(this.linkedWidthNode.view.maximumWidth, this.view.maximumWidth) : this.view.maximumWidth;\n\t}\n\n\tprivate get minimumHeight(): number {\n\t\treturn this.linkedHeightNode ? Math.max(this.linkedHeightNode.view.minimumHeight, this.view.minimumHeight) : this.view.minimumHeight;\n\t}\n\n\tprivate get maximumHeight(): number {\n\t\treturn this.linkedHeightNode ? Math.min(this.linkedHeightNode.view.maximumHeight, this.view.maximumHeight) : this.view.maximumHeight;\n\t}\n\n\tget minimumSize(): number {\n\t\treturn this.orientation === Orientation.HORIZONTAL ? this.minimumHeight : this.minimumWidth;\n\t}\n\n\tget maximumSize(): number {\n\t\treturn this.orientation === Orientation.HORIZONTAL ? this.maximumHeight : this.maximumWidth;\n\t}\n\n\tget priority(): LayoutPriority | undefined {\n\t\treturn this.view.priority;\n\t}\n\n\tget proportionalLayout(): boolean {\n\t\treturn this.view.proportionalLayout ?? true;\n\t}\n\n\tget snap(): boolean | undefined {\n\t\treturn this.view.snap;\n\t}\n\n\tget minimumOrthogonalSize(): number {\n\t\treturn this.orientation === Orientation.HORIZONTAL ? this.minimumWidth : this.minimumHeight;\n\t}\n\n\tget maximumOrthogonalSize(): number {\n\t\treturn this.orientation === Orientation.HORIZONTAL ? this.maximumWidth : this.maximumHeight;\n\t}\n\n\tprivate _boundarySashes: IRelativeBoundarySashes = {};\n\tget boundarySashes(): IRelativeBoundarySashes { return this._boundarySashes; }\n\tset boundarySashes(boundarySashes: IRelativeBoundarySashes) {\n\t\tthis._boundarySashes = boundarySashes;\n\n\t\tthis.view.setBoundarySashes?.(toAbsoluteBoundarySashes(boundarySashes, this.orientation));\n\t}\n\n\tlayout(size: number, offset: number, ctx: ILayoutContext | undefined): void {\n\t\tif (!this.layoutController.isLayoutEnabled) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (typeof ctx === 'undefined') {\n\t\t\tthrow new Error('Invalid state');\n\t\t}\n\n\t\tthis._size = size;\n\t\tthis._orthogonalSize = ctx.orthogonalSize;\n\t\tthis.absoluteOffset = ctx.absoluteOffset + offset;\n\t\tthis.absoluteOrthogonalOffset = ctx.absoluteOrthogonalOffset;\n\n\t\tthis._layout(this.width, this.height, this.top, this.left);\n\t}\n\n\tprivate cachedWidth: number = 0;\n\tprivate cachedHeight: number = 0;\n\tprivate cachedTop: number = 0;\n\tprivate cachedLeft: number = 0;\n\n\tprivate _layout(width: number, height: number, top: number, left: number): void {\n\t\tif (this.cachedWidth === width && this.cachedHeight === height && this.cachedTop === top && this.cachedLeft === left) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.cachedWidth = width;\n\t\tthis.cachedHeight = height;\n\t\tthis.cachedTop = top;\n\t\tthis.cachedLeft = left;\n\t\tthis.view.layout(width, height, top, left);\n\t}\n\n\tsetVisible(visible: boolean): void {\n\t\tthis.view.setVisible?.(visible);\n\t}\n\n\tdispose(): void {\n\t\tthis.disposables.dispose();\n\t}\n}\n\ntype Node = BranchNode | LeafNode;\n\nexport interface INodeDescriptor {\n\tnode: Node;\n\tvisible?: boolean;\n}\n\nfunction flipNode(node: BranchNode, size: number, orthogonalSize: number): BranchNode;\nfunction flipNode(node: LeafNode, size: number, orthogonalSize: number): LeafNode;\nfunction flipNode(node: Node, size: number, orthogonalSize: number): Node;\nfunction flipNode(node: Node, size: number, orthogonalSize: number): Node {\n\tif (node instanceof BranchNode) {\n\t\tconst result = new BranchNode(orthogonal(node.orientation), node.layoutController, node.styles, node.splitviewProportionalLayout, size, orthogonalSize, node.edgeSnapping);\n\n\t\tlet totalSize = 0;\n\n\t\tfor (let i = node.children.length - 1; i >= 0; i--) {\n\t\t\tconst child = node.children[i];\n\t\t\tconst childSize = child instanceof BranchNode ? child.orthogonalSize : child.size;\n\n\t\t\tlet newSize = node.size === 0 ? 0 : Math.round((size * childSize) / node.size);\n\t\t\ttotalSize += newSize;\n\n\t\t\t// The last view to add should adjust to rounding errors\n\t\t\tif (i === 0) {\n\t\t\t\tnewSize += size - totalSize;\n\t\t\t}\n\n\t\t\tresult.addChild(flipNode(child, orthogonalSize, newSize), newSize, 0, true);\n\t\t}\n\n\t\tnode.dispose();\n\t\treturn result;\n\t} else {\n\t\tconst result = new LeafNode(node.view, orthogonal(node.orientation), node.layoutController, orthogonalSize);\n\t\tnode.dispose();\n\t\treturn result;\n\t}\n}\n\n/**\n * The location of a {@link IView view} within a {@link GridView}.\n *\n * A GridView is a tree composition of multiple {@link SplitView} instances, orthogonal\n * between one another. Here's an example:\n *\n * ```\n * +-----+---------------+\n * | A | B |\n * +-----+---------+-----+\n * | C | |\n * +---------------+ D |\n * | E | |\n * +---------------+-----+\n * ```\n *\n * The above grid's tree structure is:\n *\n * ```\n * Vertical SplitView\n * +-Horizontal SplitView\n * | +-A\n * | +-B\n * +- Horizontal SplitView\n * +-Vertical SplitView\n * | +-C\n * | +-E\n * +-D\n * ```\n *\n * So, {@link IView views} within a {@link GridView} can be referenced by\n * a sequence of indexes, each index referencing each SplitView. Here are\n * each view's locations, from the example above:\n *\n * - `A`: `[0,0]`\n * - `B`: `[0,1]`\n * - `C`: `[1,0,0]`\n * - `D`: `[1,1]`\n * - `E`: `[1,0,1]`\n */\nexport type GridLocation = number[];\n\n/**\n * The {@link GridView} is the UI component which implements a two dimensional\n * flex-like layout algorithm for a collection of {@link IView} instances, which\n * are mostly HTMLElement instances with size constraints. A {@link GridView} is a\n * tree composition of multiple {@link SplitView} instances, orthogonal between\n * one another. It will respect view's size contraints, just like the SplitView.\n *\n * It has a low-level index based API, allowing for fine grain performant operations.\n * Look into the {@link Grid} widget for a higher-level API.\n *\n * Features:\n * - flex-like layout algorithm\n * - snap support\n * - corner sash support\n * - Alt key modifier behavior, macOS style\n * - layout (de)serialization\n */\nexport class GridView implements IDisposable {\n\n\t/**\n\t * The DOM element for this view.\n\t */\n\treadonly element: HTMLElement;\n\n\tprivate styles: IGridViewStyles;\n\tprivate proportionalLayout: boolean;\n\tprivate _root!: BranchNode;\n\tprivate onDidSashResetRelay = new Relay();\n\tprivate _onDidScroll = new Relay();\n\tprivate _onDidChange = new Relay();\n\tprivate _boundarySashes: IBoundarySashes = {};\n\n\t/**\n\t * The layout controller makes sure layout only propagates\n\t * to the views after the very first call to {@link GridView.layout}.\n\t */\n\tprivate layoutController: LayoutController;\n\tprivate disposable2x2: IDisposable = Disposable.None;\n\n\tprivate get root(): BranchNode { return this._root; }\n\n\tprivate set root(root: BranchNode) {\n\t\tconst oldRoot = this._root;\n\n\t\tif (oldRoot) {\n\t\t\tthis.element.removeChild(oldRoot.element);\n\t\t\toldRoot.dispose();\n\t\t}\n\n\t\tthis._root = root;\n\t\tthis.element.appendChild(root.element);\n\t\tthis.onDidSashResetRelay.input = root.onDidSashReset;\n\t\tthis._onDidChange.input = Event.map(root.onDidChange, () => undefined); // TODO\n\t\tthis._onDidScroll.input = root.onDidScroll;\n\t}\n\n\t/**\n\t * Fires whenever the user double clicks a {@link Sash sash}.\n\t */\n\treadonly onDidSashReset = this.onDidSashResetRelay.event;\n\n\t/**\n\t * Fires whenever the user scrolls a {@link SplitView} within\n\t * the grid.\n\t */\n\treadonly onDidScroll = this._onDidScroll.event;\n\n\t/**\n\t * Fires whenever a view within the grid changes its size constraints.\n\t */\n\treadonly onDidChange = this._onDidChange.event;\n\n\t/**\n\t * The width of the grid.\n\t */\n\tget width(): number { return this.root.width; }\n\n\t/**\n\t * The height of the grid.\n\t */\n\tget height(): number { return this.root.height; }\n\n\t/**\n\t * The minimum width of the grid.\n\t */\n\tget minimumWidth(): number { return this.root.minimumWidth; }\n\n\t/**\n\t * The minimum height of the grid.\n\t */\n\tget minimumHeight(): number { return this.root.minimumHeight; }\n\n\t/**\n\t * The maximum width of the grid.\n\t */\n\tget maximumWidth(): number { return this.root.maximumHeight; }\n\n\t/**\n\t * The maximum height of the grid.\n\t */\n\tget maximumHeight(): number { return this.root.maximumHeight; }\n\n\tget orientation(): Orientation { return this._root.orientation; }\n\tget boundarySashes(): IBoundarySashes { return this._boundarySashes; }\n\n\t/**\n\t * The orientation of the grid. Matches the orientation of the root\n\t * {@link SplitView} in the grid's tree model.\n\t */\n\tset orientation(orientation: Orientation) {\n\t\tif (this._root.orientation === orientation) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst { size, orthogonalSize, absoluteOffset, absoluteOrthogonalOffset } = this._root;\n\t\tthis.root = flipNode(this._root, orthogonalSize, size);\n\t\tthis.root.layout(size, 0, { orthogonalSize, absoluteOffset: absoluteOrthogonalOffset, absoluteOrthogonalOffset: absoluteOffset, absoluteSize: size, absoluteOrthogonalSize: orthogonalSize });\n\t\tthis.boundarySashes = this.boundarySashes;\n\t}\n\n\t/**\n\t * A collection of sashes perpendicular to each edge of the grid.\n\t * Corner sashes will be created for each intersection.\n\t */\n\tset boundarySashes(boundarySashes: IBoundarySashes) {\n\t\tthis._boundarySashes = boundarySashes;\n\t\tthis.root.boundarySashes = fromAbsoluteBoundarySashes(boundarySashes, this.orientation);\n\t}\n\n\t/**\n\t * Enable/disable edge snapping across all grid views.\n\t */\n\tset edgeSnapping(edgeSnapping: boolean) {\n\t\tthis.root.edgeSnapping = edgeSnapping;\n\t}\n\n\tprivate maximizedNode: LeafNode | undefined = undefined;\n\n\tprivate readonly _onDidChangeViewMaximized = new Emitter();\n\treadonly onDidChangeViewMaximized = this._onDidChangeViewMaximized.event;\n\n\t/**\n\t * Create a new {@link GridView} instance.\n\t *\n\t * @remarks It's the caller's responsibility to append the\n\t * {@link GridView.element} to the page's DOM.\n\t */\n\tconstructor(options: IGridViewOptions = {}) {\n\t\tthis.element = $('.monaco-grid-view');\n\t\tthis.styles = options.styles || defaultStyles;\n\t\tthis.proportionalLayout = typeof options.proportionalLayout !== 'undefined' ? !!options.proportionalLayout : true;\n\t\tthis.layoutController = new LayoutController(false);\n\t\tthis.root = new BranchNode(Orientation.VERTICAL, this.layoutController, this.styles, this.proportionalLayout);\n\t}\n\n\tstyle(styles: IGridViewStyles): void {\n\t\tthis.styles = styles;\n\t\tthis.root.style(styles);\n\t}\n\n\t/**\n\t * Layout the {@link GridView}.\n\t *\n\t * Optionally provide a `top` and `left` positions, those will propagate\n\t * as an origin for positions passed to {@link IView.layout}.\n\t *\n\t * @param width The width of the {@link GridView}.\n\t * @param height The height of the {@link GridView}.\n\t * @param top Optional, the top location of the {@link GridView}.\n\t * @param left Optional, the left location of the {@link GridView}.\n\t */\n\tlayout(width: number, height: number, top: number = 0, left: number = 0): void {\n\t\tthis.layoutController.isLayoutEnabled = true;\n\n\t\tconst [size, orthogonalSize, offset, orthogonalOffset] = this.root.orientation === Orientation.HORIZONTAL ? [height, width, top, left] : [width, height, left, top];\n\t\tthis.root.layout(size, 0, { orthogonalSize, absoluteOffset: offset, absoluteOrthogonalOffset: orthogonalOffset, absoluteSize: size, absoluteOrthogonalSize: orthogonalSize });\n\t}\n\n\t/**\n\t * Add a {@link IView view} to this {@link GridView}.\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 location The {@link GridLocation location} to insert the view on.\n\t */\n\taddView(view: IView, size: number | Sizing, location: GridLocation): void {\n\t\tif (this.hasMaximizedView()) {\n\t\t\tthis.exitMaximizedView();\n\t\t}\n\n\t\tthis.disposable2x2.dispose();\n\t\tthis.disposable2x2 = Disposable.None;\n\n\t\tconst [rest, index] = tail(location);\n\t\tconst [pathToParent, parent] = this.getNode(rest);\n\n\t\tif (parent instanceof BranchNode) {\n\t\t\tconst node = new LeafNode(view, orthogonal(parent.orientation), this.layoutController, parent.orthogonalSize);\n\n\t\t\ttry {\n\t\t\t\tparent.addChild(node, size, index);\n\t\t\t} catch (err) {\n\t\t\t\tnode.dispose();\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t} else {\n\t\t\tconst [, grandParent] = tail(pathToParent);\n\t\t\tconst [, parentIndex] = tail(rest);\n\n\t\t\tlet newSiblingSize: number | Sizing = 0;\n\n\t\t\tconst newSiblingCachedVisibleSize = grandParent.getChildCachedVisibleSize(parentIndex);\n\t\t\tif (typeof newSiblingCachedVisibleSize === 'number') {\n\t\t\t\tnewSiblingSize = Sizing.Invisible(newSiblingCachedVisibleSize);\n\t\t\t}\n\n\t\t\tconst oldChild = grandParent.removeChild(parentIndex);\n\t\t\toldChild.dispose();\n\n\t\t\tconst newParent = new BranchNode(parent.orientation, parent.layoutController, this.styles, this.proportionalLayout, parent.size, parent.orthogonalSize, grandParent.edgeSnapping);\n\t\t\tgrandParent.addChild(newParent, parent.size, parentIndex);\n\n\t\t\tconst newSibling = new LeafNode(parent.view, grandParent.orientation, this.layoutController, parent.size);\n\t\t\tnewParent.addChild(newSibling, newSiblingSize, 0);\n\n\t\t\tif (typeof size !== 'number' && size.type === 'split') {\n\t\t\t\tsize = Sizing.Split(0);\n\t\t\t}\n\n\t\t\tconst node = new LeafNode(view, grandParent.orientation, this.layoutController, parent.size);\n\t\t\tnewParent.addChild(node, size, index);\n\t\t}\n\n\t\tthis.trySet2x2();\n\t}\n\n\t/**\n\t * Remove a {@link IView view} from this {@link GridView}.\n\t *\n\t * @param location The {@link GridLocation location} of the {@link IView view}.\n\t * @param sizing Whether to distribute other {@link IView view}'s sizes.\n\t */\n\tremoveView(location: GridLocation, sizing?: DistributeSizing | AutoSizing): IView {\n\t\tif (this.hasMaximizedView()) {\n\t\t\tthis.exitMaximizedView();\n\t\t}\n\n\t\tthis.disposable2x2.dispose();\n\t\tthis.disposable2x2 = Disposable.None;\n\n\t\tconst [rest, index] = tail(location);\n\t\tconst [pathToParent, parent] = this.getNode(rest);\n\n\t\tif (!(parent instanceof BranchNode)) {\n\t\t\tthrow new Error('Invalid location');\n\t\t}\n\n\t\tconst node = parent.children[index];\n\n\t\tif (!(node instanceof LeafNode)) {\n\t\t\tthrow new Error('Invalid location');\n\t\t}\n\n\t\tparent.removeChild(index, sizing);\n\t\tnode.dispose();\n\n\t\tif (parent.children.length === 0) {\n\t\t\tthrow new Error('Invalid grid state');\n\t\t}\n\n\t\tif (parent.children.length > 1) {\n\t\t\tthis.trySet2x2();\n\t\t\treturn node.view;\n\t\t}\n\n\t\tif (pathToParent.length === 0) { // parent is root\n\t\t\tconst sibling = parent.children[0];\n\n\t\t\tif (sibling instanceof LeafNode) {\n\t\t\t\treturn node.view;\n\t\t\t}\n\n\t\t\t// we must promote sibling to be the new root\n\t\t\tparent.removeChild(0);\n\t\t\tparent.dispose();\n\t\t\tthis.root = sibling;\n\t\t\tthis.boundarySashes = this.boundarySashes;\n\t\t\tthis.trySet2x2();\n\t\t\treturn node.view;\n\t\t}\n\n\t\tconst [, grandParent] = tail(pathToParent);\n\t\tconst [, parentIndex] = tail(rest);\n\n\t\tconst isSiblingVisible = parent.isChildVisible(0);\n\t\tconst sibling = parent.removeChild(0);\n\n\t\tconst sizes = grandParent.children.map((_, i) => grandParent.getChildSize(i));\n\t\tgrandParent.removeChild(parentIndex, sizing);\n\t\tparent.dispose();\n\n\t\tif (sibling instanceof BranchNode) {\n\t\t\tsizes.splice(parentIndex, 1, ...sibling.children.map(c => c.size));\n\n\t\t\tconst siblingChildren = sibling.removeAllChildren();\n\n\t\t\tfor (let i = 0; i < siblingChildren.length; i++) {\n\t\t\t\tgrandParent.addChild(siblingChildren[i], siblingChildren[i].size, parentIndex + i);\n\t\t\t}\n\t\t} else {\n\t\t\tconst newSibling = new LeafNode(sibling.view, orthogonal(sibling.orientation), this.layoutController, sibling.size);\n\t\t\tconst sizing = isSiblingVisible ? sibling.orthogonalSize : Sizing.Invisible(sibling.orthogonalSize);\n\t\t\tgrandParent.addChild(newSibling, sizing, parentIndex);\n\t\t}\n\n\t\tsibling.dispose();\n\n\t\tfor (let i = 0; i < sizes.length; i++) {\n\t\t\tgrandParent.resizeChild(i, sizes[i]);\n\t\t}\n\n\t\tthis.trySet2x2();\n\t\treturn node.view;\n\t}\n\n\t/**\n\t * Move a {@link IView view} within its parent.\n\t *\n\t * @param parentLocation The {@link GridLocation location} of the {@link IView view}'s parent.\n\t * @param from The index of the {@link IView view} to move.\n\t * @param to The index where the {@link IView view} should move to.\n\t */\n\tmoveView(parentLocation: GridLocation, from: number, to: number): void {\n\t\tif (this.hasMaximizedView()) {\n\t\t\tthis.exitMaximizedView();\n\t\t}\n\n\t\tconst [, parent] = this.getNode(parentLocation);\n\n\t\tif (!(parent instanceof BranchNode)) {\n\t\t\tthrow new Error('Invalid location');\n\t\t}\n\n\t\tparent.moveChild(from, to);\n\n\t\tthis.trySet2x2();\n\t}\n\n\t/**\n\t * Swap two {@link IView views} within the {@link GridView}.\n\t *\n\t * @param from The {@link GridLocation location} of one view.\n\t * @param to The {@link GridLocation location} of another view.\n\t */\n\tswapViews(from: GridLocation, to: GridLocation): void {\n\t\tif (this.hasMaximizedView()) {\n\t\t\tthis.exitMaximizedView();\n\t\t}\n\n\t\tconst [fromRest, fromIndex] = tail(from);\n\t\tconst [, fromParent] = this.getNode(fromRest);\n\n\t\tif (!(fromParent instanceof BranchNode)) {\n\t\t\tthrow new Error('Invalid from location');\n\t\t}\n\n\t\tconst fromSize = fromParent.getChildSize(fromIndex);\n\t\tconst fromNode = fromParent.children[fromIndex];\n\n\t\tif (!(fromNode instanceof LeafNode)) {\n\t\t\tthrow new Error('Invalid from location');\n\t\t}\n\n\t\tconst [toRest, toIndex] = tail(to);\n\t\tconst [, toParent] = this.getNode(toRest);\n\n\t\tif (!(toParent instanceof BranchNode)) {\n\t\t\tthrow new Error('Invalid to location');\n\t\t}\n\n\t\tconst toSize = toParent.getChildSize(toIndex);\n\t\tconst toNode = toParent.children[toIndex];\n\n\t\tif (!(toNode instanceof LeafNode)) {\n\t\t\tthrow new Error('Invalid to location');\n\t\t}\n\n\t\tif (fromParent === toParent) {\n\t\t\tfromParent.swapChildren(fromIndex, toIndex);\n\t\t} else {\n\t\t\tfromParent.removeChild(fromIndex);\n\t\t\ttoParent.removeChild(toIndex);\n\n\t\t\tfromParent.addChild(toNode, fromSize, fromIndex);\n\t\t\ttoParent.addChild(fromNode, toSize, toIndex);\n\t\t}\n\n\t\tthis.trySet2x2();\n\t}\n\n\t/**\n\t * Resize a {@link IView view}.\n\t *\n\t * @param location The {@link GridLocation location} of the view.\n\t * @param size The size the view should be. Optionally provide a single dimension.\n\t */\n\tresizeView(location: GridLocation, size: Partial): void {\n\t\tif (this.hasMaximizedView()) {\n\t\t\tthis.exitMaximizedView();\n\t\t}\n\n\t\tconst [rest, index] = tail(location);\n\t\tconst [pathToParent, parent] = this.getNode(rest);\n\n\t\tif (!(parent instanceof BranchNode)) {\n\t\t\tthrow new Error('Invalid location');\n\t\t}\n\n\t\tif (!size.width && !size.height) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst [parentSize, grandParentSize] = parent.orientation === Orientation.HORIZONTAL ? [size.width, size.height] : [size.height, size.width];\n\n\t\tif (typeof grandParentSize === 'number' && pathToParent.length > 0) {\n\t\t\tconst [, grandParent] = tail(pathToParent);\n\t\t\tconst [, parentIndex] = tail(rest);\n\n\t\t\tgrandParent.resizeChild(parentIndex, grandParentSize);\n\t\t}\n\n\t\tif (typeof parentSize === 'number') {\n\t\t\tparent.resizeChild(index, parentSize);\n\t\t}\n\n\t\tthis.trySet2x2();\n\t}\n\n\t/**\n\t * Get the size of a {@link IView view}.\n\t *\n\t * @param location The {@link GridLocation location} of the view. Provide `undefined` to get\n\t * the size of the grid itself.\n\t */\n\tgetViewSize(location?: GridLocation): IViewSize {\n\t\tif (!location) {\n\t\t\treturn { width: this.root.width, height: this.root.height };\n\t\t}\n\n\t\tconst [, node] = this.getNode(location);\n\t\treturn { width: node.width, height: node.height };\n\t}\n\n\t/**\n\t * Get the cached visible size of a {@link IView view}. This was the size\n\t * of the view at the moment it last became hidden.\n\t *\n\t * @param location The {@link GridLocation location} of the view.\n\t */\n\tgetViewCachedVisibleSize(location: GridLocation): number | undefined {\n\t\tconst [rest, index] = tail(location);\n\t\tconst [, parent] = this.getNode(rest);\n\n\t\tif (!(parent instanceof BranchNode)) {\n\t\t\tthrow new Error('Invalid location');\n\t\t}\n\n\t\treturn parent.getChildCachedVisibleSize(index);\n\t}\n\n\t/**\n\t * Maximize the size of a {@link IView view} by collapsing all other views\n\t * to their minimum sizes.\n\t *\n\t * @param location The {@link GridLocation location} of the view.\n\t */\n\texpandView(location: GridLocation): void {\n\t\tif (this.hasMaximizedView()) {\n\t\t\tthis.exitMaximizedView();\n\t\t}\n\n\t\tconst [ancestors, node] = this.getNode(location);\n\n\t\tif (!(node instanceof LeafNode)) {\n\t\t\tthrow new Error('Invalid location');\n\t\t}\n\n\t\tfor (let i = 0; i < ancestors.length; i++) {\n\t\t\tancestors[i].resizeChild(location[i], Number.POSITIVE_INFINITY);\n\t\t}\n\t}\n\n\t/**\n\t * Returns whether all other {@link IView views} are at their minimum size.\n\t *\n\t * @param location The {@link GridLocation location} of the view.\n\t */\n\tisViewExpanded(location: GridLocation): boolean {\n\t\tif (this.hasMaximizedView()) {\n\t\t\t// No view can be expanded when a view is maximized\n\t\t\treturn false;\n\t\t}\n\n\t\tconst [ancestors, node] = this.getNode(location);\n\n\t\tif (!(node instanceof LeafNode)) {\n\t\t\tthrow new Error('Invalid location');\n\t\t}\n\n\t\tfor (let i = 0; i < ancestors.length; i++) {\n\t\t\tif (!ancestors[i].isChildExpanded(location[i])) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tmaximizeView(location: GridLocation) {\n\t\tconst [, nodeToMaximize] = this.getNode(location);\n\t\tif (!(nodeToMaximize instanceof LeafNode)) {\n\t\t\tthrow new Error('Location is not a LeafNode');\n\t\t}\n\n\t\tif (this.maximizedNode === nodeToMaximize) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.hasMaximizedView()) {\n\t\t\tthis.exitMaximizedView();\n\t\t}\n\n\t\tfunction hideAllViewsBut(parent: BranchNode, exclude: LeafNode): void {\n\t\t\tfor (let i = 0; i < parent.children.length; i++) {\n\t\t\t\tconst child = parent.children[i];\n\t\t\t\tif (child instanceof LeafNode) {\n\t\t\t\t\tif (child !== exclude) {\n\t\t\t\t\t\tparent.setChildVisible(i, false);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\thideAllViewsBut(child, exclude);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\thideAllViewsBut(this.root, nodeToMaximize);\n\n\t\tthis.maximizedNode = nodeToMaximize;\n\t\tthis._onDidChangeViewMaximized.fire(true);\n\t}\n\n\texitMaximizedView(): void {\n\t\tif (!this.maximizedNode) {\n\t\t\treturn;\n\t\t}\n\t\tthis.maximizedNode = undefined;\n\n\t\t// When hiding a view, it's previous size is cached.\n\t\t// To restore the sizes of all views, they need to be made visible in reverse order.\n\t\tfunction showViewsInReverseOrder(parent: BranchNode): void {\n\t\t\tfor (let index = parent.children.length - 1; index >= 0; index--) {\n\t\t\t\tconst child = parent.children[index];\n\t\t\t\tif (child instanceof LeafNode) {\n\t\t\t\t\tparent.setChildVisible(index, true);\n\t\t\t\t} else {\n\t\t\t\t\tshowViewsInReverseOrder(child);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tshowViewsInReverseOrder(this.root);\n\n\t\tthis._onDidChangeViewMaximized.fire(false);\n\t}\n\n\thasMaximizedView(): boolean {\n\t\treturn this.maximizedNode !== undefined;\n\t}\n\n\t/**\n\t * Returns whether the {@link IView view} is maximized.\n\t *\n\t * @param location The {@link GridLocation location} of the view.\n\t */\n\tisViewMaximized(location: GridLocation): boolean {\n\t\tconst [, node] = this.getNode(location);\n\t\tif (!(node instanceof LeafNode)) {\n\t\t\tthrow new Error('Location is not a LeafNode');\n\t\t}\n\t\treturn node === this.maximizedNode;\n\t}\n\n\t/**\n\t * Distribute the size among all {@link IView views} within the entire\n\t * grid or within a single {@link SplitView}.\n\t *\n\t * @param location The {@link GridLocation location} of a view containing\n\t * children views, which will have their sizes distributed within the parent\n\t * view's size. Provide `undefined` to recursively distribute all views' sizes\n\t * in the entire grid.\n\t */\n\tdistributeViewSizes(location?: GridLocation): void {\n\t\tif (this.hasMaximizedView()) {\n\t\t\tthis.exitMaximizedView();\n\t\t}\n\n\t\tif (!location) {\n\t\t\tthis.root.distributeViewSizes(true);\n\t\t\treturn;\n\t\t}\n\n\t\tconst [, node] = this.getNode(location);\n\n\t\tif (!(node instanceof BranchNode)) {\n\t\t\tthrow new Error('Invalid location');\n\t\t}\n\n\t\tnode.distributeViewSizes();\n\t\tthis.trySet2x2();\n\t}\n\n\t/**\n\t * Returns whether a {@link IView view} is visible.\n\t *\n\t * @param location The {@link GridLocation location} of the view.\n\t */\n\tisViewVisible(location: GridLocation): boolean {\n\t\tconst [rest, index] = tail(location);\n\t\tconst [, parent] = this.getNode(rest);\n\n\t\tif (!(parent instanceof BranchNode)) {\n\t\t\tthrow new Error('Invalid from location');\n\t\t}\n\n\t\treturn parent.isChildVisible(index);\n\t}\n\n\t/**\n\t * Set the visibility state of a {@link IView view}.\n\t *\n\t * @param location The {@link GridLocation location} of the view.\n\t */\n\tsetViewVisible(location: GridLocation, visible: boolean): void {\n\t\tif (this.hasMaximizedView()) {\n\t\t\tthis.exitMaximizedView();\n\t\t\treturn;\n\t\t}\n\n\t\tconst [rest, index] = tail(location);\n\t\tconst [, parent] = this.getNode(rest);\n\n\t\tif (!(parent instanceof BranchNode)) {\n\t\t\tthrow new Error('Invalid from location');\n\t\t}\n\n\t\tparent.setChildVisible(index, visible);\n\t}\n\n\t/**\n\t * Returns a descriptor for the entire grid.\n\t */\n\tgetView(): GridBranchNode;\n\n\t/**\n\t * Returns a descriptor for a {@link GridLocation subtree} within the\n\t * {@link GridView}.\n\t *\n\t * @param location The {@link GridLocation location} of the root of\n\t * the {@link GridLocation subtree}.\n\t */\n\tgetView(location: GridLocation): GridNode;\n\tgetView(location?: GridLocation): GridNode {\n\t\tconst node = location ? this.getNode(location)[1] : this._root;\n\t\treturn this._getViews(node, this.orientation);\n\t}\n\n\t/**\n\t * Construct a new {@link GridView} from a JSON object.\n\t *\n\t * @param json The JSON object.\n\t * @param deserializer A deserializer which can revive each view.\n\t * @returns A new {@link GridView} instance.\n\t */\n\tstatic deserialize(json: ISerializedGridView, deserializer: IViewDeserializer, options: IGridViewOptions = {}): GridView {\n\t\tif (typeof json.orientation !== 'number') {\n\t\t\tthrow new Error('Invalid JSON: \\'orientation\\' property must be a number.');\n\t\t} else if (typeof json.width !== 'number') {\n\t\t\tthrow new Error('Invalid JSON: \\'width\\' property must be a number.');\n\t\t} else if (typeof json.height !== 'number') {\n\t\t\tthrow new Error('Invalid JSON: \\'height\\' property must be a number.');\n\t\t} else if (json.root?.type !== 'branch') {\n\t\t\tthrow new Error('Invalid JSON: \\'root\\' property must have \\'type\\' value of branch.');\n\t\t}\n\n\t\tconst orientation = json.orientation;\n\t\tconst height = json.height;\n\n\t\tconst result = new GridView(options);\n\t\tresult._deserialize(json.root as ISerializedBranchNode, orientation, deserializer, height);\n\n\t\treturn result;\n\t}\n\n\tprivate _deserialize(root: ISerializedBranchNode, orientation: Orientation, deserializer: IViewDeserializer, orthogonalSize: number): void {\n\t\tthis.root = this._deserializeNode(root, orientation, deserializer, orthogonalSize) as BranchNode;\n\t}\n\n\tprivate _deserializeNode(node: ISerializedNode, orientation: Orientation, deserializer: IViewDeserializer, orthogonalSize: number): Node {\n\t\tlet result: Node;\n\t\tif (node.type === 'branch') {\n\t\t\tconst serializedChildren = node.data as ISerializedNode[];\n\t\t\tconst children = serializedChildren.map(serializedChild => {\n\t\t\t\treturn {\n\t\t\t\t\tnode: this._deserializeNode(serializedChild, orthogonal(orientation), deserializer, node.size),\n\t\t\t\t\tvisible: (serializedChild as { visible?: boolean }).visible\n\t\t\t\t} as INodeDescriptor;\n\t\t\t});\n\n\t\t\tresult = new BranchNode(orientation, this.layoutController, this.styles, this.proportionalLayout, node.size, orthogonalSize, undefined, children);\n\t\t} else {\n\t\t\tresult = new LeafNode(deserializer.fromJSON(node.data), orientation, this.layoutController, orthogonalSize, node.size);\n\t\t\tif (node.maximized && !this.maximizedNode) {\n\t\t\t\tthis.maximizedNode = result;\n\t\t\t\tthis._onDidChangeViewMaximized.fire(true);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tprivate _getViews(node: Node, orientation: Orientation, cachedVisibleSize?: number): GridNode {\n\t\tconst box = { top: node.top, left: node.left, width: node.width, height: node.height };\n\n\t\tif (node instanceof LeafNode) {\n\t\t\treturn { view: node.view, box, cachedVisibleSize, maximized: this.maximizedNode === node };\n\t\t}\n\n\t\tconst children: GridNode[] = [];\n\n\t\tfor (let i = 0; i < node.children.length; i++) {\n\t\t\tconst child = node.children[i];\n\t\t\tconst cachedVisibleSize = node.getChildCachedVisibleSize(i);\n\n\t\t\tchildren.push(this._getViews(child, orthogonal(orientation), cachedVisibleSize));\n\t\t}\n\n\t\treturn { children, box };\n\t}\n\n\tprivate getNode(location: GridLocation, node: Node = this.root, path: BranchNode[] = []): [BranchNode[], Node] {\n\t\tif (location.length === 0) {\n\t\t\treturn [path, node];\n\t\t}\n\n\t\tif (!(node instanceof BranchNode)) {\n\t\t\tthrow new Error('Invalid location');\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 Error('Invalid location');\n\t\t}\n\n\t\tconst child = node.children[index];\n\t\tpath.push(node);\n\n\t\treturn this.getNode(rest, child, path);\n\t}\n\n\t/**\n\t * Attempt to lock the {@link Sash sashes} in this {@link GridView} so\n\t * the grid behaves as a 2x2 matrix, with a corner sash in the middle.\n\t *\n\t * In case the grid isn't a 2x2 grid _and_ all sashes are not aligned,\n\t * this method is a no-op.\n\t */\n\ttrySet2x2(): void {\n\t\tthis.disposable2x2.dispose();\n\t\tthis.disposable2x2 = Disposable.None;\n\n\t\tif (this.root.children.length !== 2) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst [first, second] = this.root.children;\n\n\t\tif (!(first instanceof BranchNode) || !(second instanceof BranchNode)) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.disposable2x2 = first.trySet2x2(second);\n\t}\n\n\t/**\n\t * Populate a map with views to DOM nodes.\n\t * @remarks To be used internally only.\n\t */\n\tgetViewMap(map: Map, node?: Node): void {\n\t\tif (!node) {\n\t\t\tnode = this.root;\n\t\t}\n\n\t\tif (node instanceof BranchNode) {\n\t\t\tnode.children.forEach(child => this.getViewMap(map, child));\n\t\t} else {\n\t\t\tmap.set(node.view, node.element);\n\t\t}\n\t}\n\n\tdispose(): void {\n\t\tthis.onDidSashResetRelay.dispose();\n\t\tthis.root.dispose();\n\t\tthis.element.parentElement?.removeChild(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 { IBoundarySashes, Orientation } from 'vs/base/browser/ui/sash/sash';\nimport { equals, tail2 as tail } from 'vs/base/common/arrays';\nimport { Event } from 'vs/base/common/event';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport 'vs/css!./gridview';\nimport { Box, GridView, IGridViewOptions, IGridViewStyles, IView as IGridViewView, IViewSize, orthogonal, Sizing as GridViewSizing, GridLocation } from './gridview';\nimport type { SplitView, AutoSizing as SplitViewAutoSizing } from 'vs/base/browser/ui/splitview/splitview';\n\nexport { IViewSize, LayoutPriority, Orientation, orthogonal } from './gridview';\n\nexport const enum Direction {\n\tUp,\n\tDown,\n\tLeft,\n\tRight\n}\n\nfunction oppositeDirection(direction: Direction): Direction {\n\tswitch (direction) {\n\t\tcase Direction.Up: return Direction.Down;\n\t\tcase Direction.Down: return Direction.Up;\n\t\tcase Direction.Left: return Direction.Right;\n\t\tcase Direction.Right: return Direction.Left;\n\t}\n}\n\n/**\n * The interface to implement for views within a {@link Grid}.\n */\nexport interface IView extends IGridViewView {\n\n\t/**\n\t * The preferred width for when the user double clicks a sash\n\t * adjacent to this view.\n\t */\n\treadonly preferredWidth?: number;\n\n\t/**\n\t * The preferred height for when the user double clicks a sash\n\t * adjacent to this view.\n\t */\n\treadonly preferredHeight?: number;\n}\n\nexport interface GridLeafNode {\n\treadonly view: T;\n\treadonly box: Box;\n\treadonly cachedVisibleSize: number | undefined;\n\treadonly maximized: boolean;\n}\n\nexport interface GridBranchNode {\n\treadonly children: GridNode[];\n\treadonly box: Box;\n}\n\nexport type GridNode = GridLeafNode | GridBranchNode;\n\nexport function isGridBranchNode(node: GridNode): node is GridBranchNode {\n\treturn !!(node as any).children;\n}\n\nfunction getGridNode(node: GridNode, location: GridLocation): GridNode {\n\tif (location.length === 0) {\n\t\treturn node;\n\t}\n\n\tif (!isGridBranchNode(node)) {\n\t\tthrow new Error('Invalid location');\n\t}\n\n\tconst [index, ...rest] = location;\n\treturn getGridNode(node.children[index], rest);\n}\n\ninterface Range {\n\treadonly start: number;\n\treadonly end: number;\n}\n\nfunction intersects(one: Range, other: Range): boolean {\n\treturn !(one.start >= other.end || other.start >= one.end);\n}\n\ninterface Boundary {\n\treadonly offset: number;\n\treadonly range: Range;\n}\n\nfunction getBoxBoundary(box: Box, direction: Direction): Boundary {\n\tconst orientation = getDirectionOrientation(direction);\n\tconst offset = direction === Direction.Up ? box.top :\n\t\tdirection === Direction.Right ? box.left + box.width :\n\t\t\tdirection === Direction.Down ? box.top + box.height :\n\t\t\t\tbox.left;\n\n\tconst range = {\n\t\tstart: orientation === Orientation.HORIZONTAL ? box.top : box.left,\n\t\tend: orientation === Orientation.HORIZONTAL ? box.top + box.height : box.left + box.width\n\t};\n\n\treturn { offset, range };\n}\n\nfunction findAdjacentBoxLeafNodes(boxNode: GridNode, direction: Direction, boundary: Boundary): GridLeafNode[] {\n\tconst result: GridLeafNode[] = [];\n\n\tfunction _(boxNode: GridNode, direction: Direction, boundary: Boundary): void {\n\t\tif (isGridBranchNode(boxNode)) {\n\t\t\tfor (const child of boxNode.children) {\n\t\t\t\t_(child, direction, boundary);\n\t\t\t}\n\t\t} else {\n\t\t\tconst { offset, range } = getBoxBoundary(boxNode.box, direction);\n\n\t\t\tif (offset === boundary.offset && intersects(range, boundary.range)) {\n\t\t\t\tresult.push(boxNode);\n\t\t\t}\n\t\t}\n\t}\n\n\t_(boxNode, direction, boundary);\n\treturn result;\n}\n\nfunction getLocationOrientation(rootOrientation: Orientation, location: GridLocation): Orientation {\n\treturn location.length % 2 === 0 ? orthogonal(rootOrientation) : rootOrientation;\n}\n\nfunction getDirectionOrientation(direction: Direction): Orientation {\n\treturn direction === Direction.Up || direction === Direction.Down ? Orientation.VERTICAL : Orientation.HORIZONTAL;\n}\n\nexport function getRelativeLocation(rootOrientation: Orientation, location: GridLocation, direction: Direction): GridLocation {\n\tconst orientation = getLocationOrientation(rootOrientation, location);\n\tconst directionOrientation = getDirectionOrientation(direction);\n\n\tif (orientation === directionOrientation) {\n\t\tlet [rest, index] = tail(location);\n\n\t\tif (direction === Direction.Right || direction === Direction.Down) {\n\t\t\tindex += 1;\n\t\t}\n\n\t\treturn [...rest, index];\n\t} else {\n\t\tconst index = (direction === Direction.Right || direction === Direction.Down) ? 1 : 0;\n\t\treturn [...location, index];\n\t}\n}\n\nfunction indexInParent(element: HTMLElement): number {\n\tconst parentElement = element.parentElement;\n\n\tif (!parentElement) {\n\t\tthrow new Error('Invalid grid element');\n\t}\n\n\tlet el = parentElement.firstElementChild;\n\tlet index = 0;\n\n\twhile (el !== element && el !== parentElement.lastElementChild && el) {\n\t\tel = el.nextElementSibling;\n\t\tindex++;\n\t}\n\n\treturn index;\n}\n\n/**\n * Find the grid location of a specific DOM element by traversing the parent\n * chain and finding each child index on the way.\n *\n * This will break as soon as DOM structures of the Splitview or Gridview change.\n */\nfunction getGridLocation(element: HTMLElement): GridLocation {\n\tconst parentElement = element.parentElement;\n\n\tif (!parentElement) {\n\t\tthrow new Error('Invalid grid element');\n\t}\n\n\tif (/\\bmonaco-grid-view\\b/.test(parentElement.className)) {\n\t\treturn [];\n\t}\n\n\tconst index = indexInParent(parentElement);\n\tconst ancestor = parentElement.parentElement!.parentElement!.parentElement!.parentElement!;\n\treturn [...getGridLocation(ancestor), index];\n}\n\nexport type DistributeSizing = { type: 'distribute' };\nexport type SplitSizing = { type: 'split' };\nexport type AutoSizing = { type: 'auto' };\nexport type InvisibleSizing = { type: 'invisible'; cachedVisibleSize: number };\nexport type Sizing = DistributeSizing | SplitSizing | AutoSizing | InvisibleSizing;\n\nexport namespace Sizing {\n\texport const Distribute: DistributeSizing = { type: 'distribute' };\n\texport const Split: SplitSizing = { type: 'split' };\n\texport const Auto: AutoSizing = { type: 'auto' };\n\texport function Invisible(cachedVisibleSize: number): InvisibleSizing { return { type: 'invisible', cachedVisibleSize }; }\n}\n\nexport interface IGridStyles extends IGridViewStyles { }\nexport interface IGridOptions extends IGridViewOptions { }\n\n/**\n * The {@link Grid} exposes a Grid widget in a friendlier API than the underlying\n * {@link GridView} widget. Namely, all mutation operations are addressed by the\n * model elements, rather than indexes.\n *\n * It support the same features as the {@link GridView}.\n */\nexport class Grid extends Disposable {\n\n\tprotected gridview: GridView;\n\tprivate views = new Map();\n\n\t/**\n\t * The orientation of the grid. Matches the orientation of the root\n\t * {@link SplitView} in the grid's {@link GridLocation} model.\n\t */\n\tget orientation(): Orientation { return this.gridview.orientation; }\n\tset orientation(orientation: Orientation) { this.gridview.orientation = orientation; }\n\n\t/**\n\t * The width of the grid.\n\t */\n\tget width(): number { return this.gridview.width; }\n\n\t/**\n\t * The height of the grid.\n\t */\n\tget height(): number { return this.gridview.height; }\n\n\t/**\n\t * The minimum width of the grid.\n\t */\n\tget minimumWidth(): number { return this.gridview.minimumWidth; }\n\n\t/**\n\t * The minimum height of the grid.\n\t */\n\tget minimumHeight(): number { return this.gridview.minimumHeight; }\n\n\t/**\n\t * The maximum width of the grid.\n\t */\n\tget maximumWidth(): number { return this.gridview.maximumWidth; }\n\n\t/**\n\t * The maximum height of the grid.\n\t */\n\tget maximumHeight(): number { return this.gridview.maximumHeight; }\n\n\t/**\n\t * Fires whenever a view within the grid changes its size constraints.\n\t */\n\treadonly onDidChange: Event<{ width: number; height: number } | undefined>;\n\n\t/**\n\t * Fires whenever the user scrolls a {@link SplitView} within\n\t * the grid.\n\t */\n\treadonly onDidScroll: Event;\n\n\t/**\n\t * A collection of sashes perpendicular to each edge of the grid.\n\t * Corner sashes will be created for each intersection.\n\t */\n\tget boundarySashes(): IBoundarySashes { return this.gridview.boundarySashes; }\n\tset boundarySashes(boundarySashes: IBoundarySashes) { this.gridview.boundarySashes = boundarySashes; }\n\n\t/**\n\t * Enable/disable edge snapping across all grid views.\n\t */\n\tset edgeSnapping(edgeSnapping: boolean) { this.gridview.edgeSnapping = edgeSnapping; }\n\n\t/**\n\t * The DOM element for this view.\n\t */\n\tget element(): HTMLElement { return this.gridview.element; }\n\n\tprivate didLayout = false;\n\n\treadonly onDidChangeViewMaximized: Event;\n\t/**\n\t * Create a new {@link Grid}. A grid must *always* have a view\n\t * inside.\n\t *\n\t * @param view An initial view for this Grid.\n\t */\n\tconstructor(view: T | GridView, options: IGridOptions = {}) {\n\t\tsuper();\n\n\t\tif (view instanceof GridView) {\n\t\t\tthis.gridview = view;\n\t\t\tthis.gridview.getViewMap(this.views);\n\t\t} else {\n\t\t\tthis.gridview = new GridView(options);\n\t\t}\n\n\t\tthis._register(this.gridview);\n\t\tthis._register(this.gridview.onDidSashReset(this.onDidSashReset, this));\n\n\t\tif (!(view instanceof GridView)) {\n\t\t\tthis._addView(view, 0, [0]);\n\t\t}\n\n\t\tthis.onDidChange = this.gridview.onDidChange;\n\t\tthis.onDidScroll = this.gridview.onDidScroll;\n\t\tthis.onDidChangeViewMaximized = this.gridview.onDidChangeViewMaximized;\n\t}\n\n\tstyle(styles: IGridStyles): void {\n\t\tthis.gridview.style(styles);\n\t}\n\n\t/**\n\t * Layout the {@link Grid}.\n\t *\n\t * Optionally provide a `top` and `left` positions, those will propagate\n\t * as an origin for positions passed to {@link IView.layout}.\n\t *\n\t * @param width The width of the {@link Grid}.\n\t * @param height The height of the {@link Grid}.\n\t * @param top Optional, the top location of the {@link Grid}.\n\t * @param left Optional, the left location of the {@link Grid}.\n\t */\n\tlayout(width: number, height: number, top: number = 0, left: number = 0): void {\n\t\tthis.gridview.layout(width, height, top, left);\n\t\tthis.didLayout = true;\n\t}\n\n\t/**\n\t * Add a {@link IView view} to this {@link Grid}, based on another reference view.\n\t *\n\t * Take this grid as an example:\n\t *\n\t * ```\n\t * +-----+---------------+\n\t * | A | B |\n\t * +-----+---------+-----+\n\t * | C | |\n\t * +---------------+ D |\n\t * | E | |\n\t * +---------------+-----+\n\t * ```\n\t *\n\t * Calling `addView(X, Sizing.Distribute, C, Direction.Right)` will make the following\n\t * changes:\n\t *\n\t * ```\n\t * +-----+---------------+\n\t * | A | B |\n\t * +-----+-+-------+-----+\n\t * | C | X | |\n\t * +-------+-------+ D |\n\t * | E | |\n\t * +---------------+-----+\n\t * ```\n\t *\n\t * Or `addView(X, Sizing.Distribute, D, Direction.Down)`:\n\t *\n\t * ```\n\t * +-----+---------------+\n\t * | A | B |\n\t * +-----+---------+-----+\n\t * | C | D |\n\t * +---------------+-----+\n\t * | E | X |\n\t * +---------------+-----+\n\t * ```\n\t *\n\t * @param newView The view to add.\n\t * @param size Either a fixed size, or a dynamic {@link Sizing} strategy.\n\t * @param referenceView Another view to place this new view next to.\n\t * @param direction The direction the new view should be placed next to the reference view.\n\t */\n\taddView(newView: T, size: number | Sizing, referenceView: T, direction: Direction): void {\n\t\tif (this.views.has(newView)) {\n\t\t\tthrow new Error('Can\\'t add same view twice');\n\t\t}\n\n\t\tconst orientation = getDirectionOrientation(direction);\n\n\t\tif (this.views.size === 1 && this.orientation !== orientation) {\n\t\t\tthis.orientation = orientation;\n\t\t}\n\n\t\tconst referenceLocation = this.getViewLocation(referenceView);\n\t\tconst location = getRelativeLocation(this.gridview.orientation, referenceLocation, direction);\n\n\t\tlet viewSize: number | GridViewSizing;\n\n\t\tif (typeof size === 'number') {\n\t\t\tviewSize = size;\n\t\t} else if (size.type === 'split') {\n\t\t\tconst [, index] = tail(referenceLocation);\n\t\t\tviewSize = GridViewSizing.Split(index);\n\t\t} else if (size.type === 'distribute') {\n\t\t\tviewSize = GridViewSizing.Distribute;\n\t\t} else if (size.type === 'auto') {\n\t\t\tconst [, index] = tail(referenceLocation);\n\t\t\tviewSize = GridViewSizing.Auto(index);\n\t\t} else {\n\t\t\tviewSize = size;\n\t\t}\n\n\t\tthis._addView(newView, viewSize, location);\n\t}\n\n\tprivate addViewAt(newView: T, size: number | DistributeSizing | InvisibleSizing, location: GridLocation): void {\n\t\tif (this.views.has(newView)) {\n\t\t\tthrow new Error('Can\\'t add same view twice');\n\t\t}\n\n\t\tlet viewSize: number | GridViewSizing;\n\n\t\tif (typeof size === 'number') {\n\t\t\tviewSize = size;\n\t\t} else if (size.type === 'distribute') {\n\t\t\tviewSize = GridViewSizing.Distribute;\n\t\t} else {\n\t\t\tviewSize = size;\n\t\t}\n\n\t\tthis._addView(newView, viewSize, location);\n\t}\n\n\tprotected _addView(newView: T, size: number | GridViewSizing, location: GridLocation): void {\n\t\tthis.views.set(newView, newView.element);\n\t\tthis.gridview.addView(newView, size, location);\n\t}\n\n\t/**\n\t * Remove a {@link IView view} from this {@link Grid}.\n\t *\n\t * @param view The {@link IView view} to remove.\n\t * @param sizing Whether to distribute other {@link IView view}'s sizes.\n\t */\n\tremoveView(view: T, sizing?: Sizing): void {\n\t\tif (this.views.size === 1) {\n\t\t\tthrow new Error('Can\\'t remove last view');\n\t\t}\n\n\t\tconst location = this.getViewLocation(view);\n\n\t\tlet gridViewSizing: DistributeSizing | SplitViewAutoSizing | undefined;\n\n\t\tif (sizing?.type === 'distribute') {\n\t\t\tgridViewSizing = GridViewSizing.Distribute;\n\t\t} else if (sizing?.type === 'auto') {\n\t\t\tconst index = location[location.length - 1];\n\t\t\tgridViewSizing = GridViewSizing.Auto(index === 0 ? 1 : index - 1);\n\t\t}\n\n\t\tthis.gridview.removeView(location, gridViewSizing);\n\t\tthis.views.delete(view);\n\t}\n\n\t/**\n\t * Move a {@link IView view} to another location in the grid.\n\t *\n\t * @remarks See {@link Grid.addView}.\n\t *\n\t * @param view The {@link IView view} to move.\n\t * @param sizing Either a fixed size, or a dynamic {@link Sizing} strategy.\n\t * @param referenceView Another view to place the view next to.\n\t * @param direction The direction the view should be placed next to the reference view.\n\t */\n\tmoveView(view: T, sizing: number | Sizing, referenceView: T, direction: Direction): void {\n\t\tconst sourceLocation = this.getViewLocation(view);\n\t\tconst [sourceParentLocation, from] = tail(sourceLocation);\n\n\t\tconst referenceLocation = this.getViewLocation(referenceView);\n\t\tconst targetLocation = getRelativeLocation(this.gridview.orientation, referenceLocation, direction);\n\t\tconst [targetParentLocation, to] = tail(targetLocation);\n\n\t\tif (equals(sourceParentLocation, targetParentLocation)) {\n\t\t\tthis.gridview.moveView(sourceParentLocation, from, to);\n\t\t} else {\n\t\t\tthis.removeView(view, typeof sizing === 'number' ? undefined : sizing);\n\t\t\tthis.addView(view, sizing, referenceView, direction);\n\t\t}\n\t}\n\n\t/**\n\t * Move a {@link IView view} to another location in the grid.\n\t *\n\t * @remarks Internal method, do not use without knowing what you're doing.\n\t * @remarks See {@link GridView.moveView}.\n\t *\n\t * @param view The {@link IView view} to move.\n\t * @param location The {@link GridLocation location} to insert the view on.\n\t */\n\tmoveViewTo(view: T, location: GridLocation): void {\n\t\tconst sourceLocation = this.getViewLocation(view);\n\t\tconst [sourceParentLocation, from] = tail(sourceLocation);\n\t\tconst [targetParentLocation, to] = tail(location);\n\n\t\tif (equals(sourceParentLocation, targetParentLocation)) {\n\t\t\tthis.gridview.moveView(sourceParentLocation, from, to);\n\t\t} else {\n\t\t\tconst size = this.getViewSize(view);\n\t\t\tconst orientation = getLocationOrientation(this.gridview.orientation, sourceLocation);\n\t\t\tconst cachedViewSize = this.getViewCachedVisibleSize(view);\n\t\t\tconst sizing = typeof cachedViewSize === 'undefined'\n\t\t\t\t? (orientation === Orientation.HORIZONTAL ? size.width : size.height)\n\t\t\t\t: Sizing.Invisible(cachedViewSize);\n\n\t\t\tthis.removeView(view);\n\t\t\tthis.addViewAt(view, sizing, location);\n\t\t}\n\t}\n\n\t/**\n\t * Swap two {@link IView views} within the {@link Grid}.\n\t *\n\t * @param from One {@link IView view}.\n\t * @param to Another {@link IView view}.\n\t */\n\tswapViews(from: T, to: T): void {\n\t\tconst fromLocation = this.getViewLocation(from);\n\t\tconst toLocation = this.getViewLocation(to);\n\t\treturn this.gridview.swapViews(fromLocation, toLocation);\n\t}\n\n\t/**\n\t * Resize a {@link IView view}.\n\t *\n\t * @param view The {@link IView view} to resize.\n\t * @param size The size the view should be.\n\t */\n\tresizeView(view: T, size: IViewSize): void {\n\t\tconst location = this.getViewLocation(view);\n\t\treturn this.gridview.resizeView(location, size);\n\t}\n\n\t/**\n\t * Returns whether all other {@link IView views} are at their minimum size.\n\t *\n\t * @param view The reference {@link IView view}.\n\t */\n\tisViewExpanded(view: T): boolean {\n\t\tconst location = this.getViewLocation(view);\n\t\treturn this.gridview.isViewExpanded(location);\n\t}\n\n\t/**\n\t * Returns whether the {@link IView view} is maximized.\n\t *\n\t * @param view The reference {@link IView view}.\n\t */\n\tisViewMaximized(view: T): boolean {\n\t\tconst location = this.getViewLocation(view);\n\t\treturn this.gridview.isViewMaximized(location);\n\t}\n\n\t/**\n\t * Returns whether the {@link IView view} is maximized.\n\t *\n\t * @param view The reference {@link IView view}.\n\t */\n\thasMaximizedView(): boolean {\n\t\treturn this.gridview.hasMaximizedView();\n\t}\n\n\t/**\n\t * Get the size of a {@link IView view}.\n\t *\n\t * @param view The {@link IView view}. Provide `undefined` to get the size\n\t * of the grid itself.\n\t */\n\tgetViewSize(view?: T): IViewSize {\n\t\tif (!view) {\n\t\t\treturn this.gridview.getViewSize();\n\t\t}\n\n\t\tconst location = this.getViewLocation(view);\n\t\treturn this.gridview.getViewSize(location);\n\t}\n\n\t/**\n\t * Get the cached visible size of a {@link IView view}. This was the size\n\t * of the view at the moment it last became hidden.\n\t *\n\t * @param view The {@link IView view}.\n\t */\n\tgetViewCachedVisibleSize(view: T): number | undefined {\n\t\tconst location = this.getViewLocation(view);\n\t\treturn this.gridview.getViewCachedVisibleSize(location);\n\t}\n\n\t/**\n\t * Maximizes the specified view and hides all other views.\n\t * @param view The view to maximize.\n\t */\n\tmaximizeView(view: T) {\n\t\tif (this.views.size < 2) {\n\t\t\tthrow new Error('At least two views are required to maximize a view');\n\t\t}\n\t\tconst location = this.getViewLocation(view);\n\t\tthis.gridview.maximizeView(location);\n\t}\n\n\texitMaximizedView(): void {\n\t\tthis.gridview.exitMaximizedView();\n\t}\n\n\t/**\n\t * Expand the size of a {@link IView view} by collapsing all other views\n\t * to their minimum sizes.\n\t *\n\t * @param view The {@link IView view}.\n\t */\n\texpandView(view: T): void {\n\t\tconst location = this.getViewLocation(view);\n\t\tthis.gridview.expandView(location);\n\t}\n\n\t/**\n\t * Distribute the size among all {@link IView views} within the entire\n\t * grid or within a single {@link SplitView}.\n\t */\n\tdistributeViewSizes(): void {\n\t\tthis.gridview.distributeViewSizes();\n\t}\n\n\t/**\n\t * Returns whether a {@link IView view} is visible.\n\t *\n\t * @param view The {@link IView view}.\n\t */\n\tisViewVisible(view: T): boolean {\n\t\tconst location = this.getViewLocation(view);\n\t\treturn this.gridview.isViewVisible(location);\n\t}\n\n\t/**\n\t * Set the visibility state of a {@link IView view}.\n\t *\n\t * @param view The {@link IView view}.\n\t */\n\tsetViewVisible(view: T, visible: boolean): void {\n\t\tconst location = this.getViewLocation(view);\n\t\tthis.gridview.setViewVisible(location, visible);\n\t}\n\n\t/**\n\t * Returns a descriptor for the entire grid.\n\t */\n\tgetViews(): GridBranchNode {\n\t\treturn this.gridview.getView() as GridBranchNode;\n\t}\n\n\t/**\n\t * Utility method to return the collection all views which intersect\n\t * a view's edge.\n\t *\n\t * @param view The {@link IView view}.\n\t * @param direction Which direction edge to be considered.\n\t * @param wrap Whether the grid wraps around (from right to left, from bottom to top).\n\t */\n\tgetNeighborViews(view: T, direction: Direction, wrap: boolean = false): T[] {\n\t\tif (!this.didLayout) {\n\t\t\tthrow new Error('Can\\'t call getNeighborViews before first layout');\n\t\t}\n\n\t\tconst location = this.getViewLocation(view);\n\t\tconst root = this.getViews();\n\t\tconst node = getGridNode(root, location);\n\t\tlet boundary = getBoxBoundary(node.box, direction);\n\n\t\tif (wrap) {\n\t\t\tif (direction === Direction.Up && node.box.top === 0) {\n\t\t\t\tboundary = { offset: root.box.top + root.box.height, range: boundary.range };\n\t\t\t} else if (direction === Direction.Right && node.box.left + node.box.width === root.box.width) {\n\t\t\t\tboundary = { offset: 0, range: boundary.range };\n\t\t\t} else if (direction === Direction.Down && node.box.top + node.box.height === root.box.height) {\n\t\t\t\tboundary = { offset: 0, range: boundary.range };\n\t\t\t} else if (direction === Direction.Left && node.box.left === 0) {\n\t\t\t\tboundary = { offset: root.box.left + root.box.width, range: boundary.range };\n\t\t\t}\n\t\t}\n\n\t\treturn findAdjacentBoxLeafNodes(root, oppositeDirection(direction), boundary)\n\t\t\t.map(node => node.view);\n\t}\n\n\tprivate getViewLocation(view: T): GridLocation {\n\t\tconst element = this.views.get(view);\n\n\t\tif (!element) {\n\t\t\tthrow new Error('View not found');\n\t\t}\n\n\t\treturn getGridLocation(element);\n\t}\n\n\tprivate onDidSashReset(location: GridLocation): void {\n\t\tconst resizeToPreferredSize = (location: GridLocation): boolean => {\n\t\t\tconst node = this.gridview.getView(location) as GridNode;\n\n\t\t\tif (isGridBranchNode(node)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tconst direction = getLocationOrientation(this.orientation, location);\n\t\t\tconst size = direction === Orientation.HORIZONTAL ? node.view.preferredWidth : node.view.preferredHeight;\n\n\t\t\tif (typeof size !== 'number') {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tconst viewSize = direction === Orientation.HORIZONTAL ? { width: Math.round(size) } : { height: Math.round(size) };\n\t\t\tthis.gridview.resizeView(location, viewSize);\n\t\t\treturn true;\n\t\t};\n\n\t\tif (resizeToPreferredSize(location)) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst [parentLocation, index] = tail(location);\n\n\t\tif (resizeToPreferredSize([...parentLocation, index + 1])) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.gridview.distributeViewSizes(parentLocation);\n\t}\n}\n\nexport interface ISerializableView extends IView {\n\ttoJSON(): object;\n}\n\nexport interface IViewDeserializer {\n\tfromJSON(json: any): T;\n}\n\nexport interface ISerializedLeafNode {\n\ttype: 'leaf';\n\tdata: any;\n\tsize: number;\n\tvisible?: boolean;\n\tmaximized?: boolean;\n}\n\nexport interface ISerializedBranchNode {\n\ttype: 'branch';\n\tdata: ISerializedNode[];\n\tsize: number;\n\tvisible?: boolean;\n}\n\nexport type ISerializedNode = ISerializedLeafNode | ISerializedBranchNode;\n\nexport interface ISerializedGrid {\n\troot: ISerializedNode;\n\torientation: Orientation;\n\twidth: number;\n\theight: number;\n}\n\n/**\n * A {@link Grid} which can serialize itself.\n */\nexport class SerializableGrid extends Grid {\n\n\tprivate static serializeNode(node: GridNode, orientation: Orientation): ISerializedNode {\n\t\tconst size = orientation === Orientation.VERTICAL ? node.box.width : node.box.height;\n\n\t\tif (!isGridBranchNode(node)) {\n\t\t\tconst serializedLeafNode: ISerializedLeafNode = { type: 'leaf', data: node.view.toJSON(), size };\n\n\t\t\tif (typeof node.cachedVisibleSize === 'number') {\n\t\t\t\tserializedLeafNode.size = node.cachedVisibleSize;\n\t\t\t\tserializedLeafNode.visible = false;\n\t\t\t} else if (node.maximized) {\n\t\t\t\tserializedLeafNode.maximized = true;\n\t\t\t}\n\n\t\t\treturn serializedLeafNode;\n\t\t}\n\n\t\tconst data = node.children.map(c => SerializableGrid.serializeNode(c, orthogonal(orientation)));\n\t\tif (data.some(c => c.visible !== false)) {\n\t\t\treturn { type: 'branch', data: data, size };\n\t\t}\n\t\treturn { type: 'branch', data: data, size, visible: false };\n\t}\n\n\t/**\n\t * Construct a new {@link SerializableGrid} from a JSON object.\n\t *\n\t * @param json The JSON object.\n\t * @param deserializer A deserializer which can revive each view.\n\t * @returns A new {@link SerializableGrid} instance.\n\t */\n\tstatic deserialize(json: ISerializedGrid, deserializer: IViewDeserializer, options: IGridOptions = {}): SerializableGrid {\n\t\tif (typeof json.orientation !== 'number') {\n\t\t\tthrow new Error('Invalid JSON: \\'orientation\\' property must be a number.');\n\t\t} else if (typeof json.width !== 'number') {\n\t\t\tthrow new Error('Invalid JSON: \\'width\\' property must be a number.');\n\t\t} else if (typeof json.height !== 'number') {\n\t\t\tthrow new Error('Invalid JSON: \\'height\\' property must be a number.');\n\t\t}\n\n\t\tconst gridview = GridView.deserialize(json, deserializer, options);\n\t\tconst result = new SerializableGrid(gridview, options);\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Construct a new {@link SerializableGrid} from a grid descriptor.\n\t *\n\t * @param gridDescriptor A grid descriptor in which leaf nodes point to actual views.\n\t * @returns A new {@link SerializableGrid} instance.\n\t */\n\tstatic from(gridDescriptor: GridDescriptor, options: IGridOptions = {}): SerializableGrid {\n\t\treturn SerializableGrid.deserialize(createSerializedGrid(gridDescriptor), { fromJSON: view => view }, options);\n\t}\n\n\t/**\n\t * Useful information in order to proportionally restore view sizes\n\t * upon the very first layout call.\n\t */\n\tprivate initialLayoutContext: boolean = true;\n\n\t/**\n\t * Serialize this grid into a JSON object.\n\t */\n\tserialize(): ISerializedGrid {\n\t\treturn {\n\t\t\troot: SerializableGrid.serializeNode(this.getViews(), this.orientation),\n\t\t\torientation: this.orientation,\n\t\t\twidth: this.width,\n\t\t\theight: this.height\n\t\t};\n\t}\n\n\toverride layout(width: number, height: number, top: number = 0, left: number = 0): void {\n\t\tsuper.layout(width, height, top, left);\n\n\t\tif (this.initialLayoutContext) {\n\t\t\tthis.initialLayoutContext = false;\n\t\t\tthis.gridview.trySet2x2();\n\t\t}\n\t}\n}\n\nexport type GridLeafNodeDescriptor = { size?: number; data?: any };\nexport type GridBranchNodeDescriptor = { size?: number; groups: GridNodeDescriptor[] };\nexport type GridNodeDescriptor = GridBranchNodeDescriptor | GridLeafNodeDescriptor;\nexport type GridDescriptor = { orientation: Orientation } & GridBranchNodeDescriptor;\n\nfunction isGridBranchNodeDescriptor(nodeDescriptor: GridNodeDescriptor): nodeDescriptor is GridBranchNodeDescriptor {\n\treturn !!(nodeDescriptor as GridBranchNodeDescriptor).groups;\n}\n\nexport function sanitizeGridNodeDescriptor(nodeDescriptor: GridNodeDescriptor, rootNode: boolean): void {\n\tif (!rootNode && (nodeDescriptor as any).groups && (nodeDescriptor as any).groups.length <= 1) {\n\t\t(nodeDescriptor as any).groups = undefined;\n\t}\n\n\tif (!isGridBranchNodeDescriptor(nodeDescriptor)) {\n\t\treturn;\n\t}\n\n\tlet totalDefinedSize = 0;\n\tlet totalDefinedSizeCount = 0;\n\n\tfor (const child of nodeDescriptor.groups) {\n\t\tsanitizeGridNodeDescriptor(child, false);\n\n\t\tif (child.size) {\n\t\t\ttotalDefinedSize += child.size;\n\t\t\ttotalDefinedSizeCount++;\n\t\t}\n\t}\n\n\tconst totalUndefinedSize = totalDefinedSizeCount > 0 ? totalDefinedSize : 1;\n\tconst totalUndefinedSizeCount = nodeDescriptor.groups.length - totalDefinedSizeCount;\n\tconst eachUndefinedSize = totalUndefinedSize / totalUndefinedSizeCount;\n\n\tfor (const child of nodeDescriptor.groups) {\n\t\tif (!child.size) {\n\t\t\tchild.size = eachUndefinedSize;\n\t\t}\n\t}\n}\n\nfunction createSerializedNode(nodeDescriptor: GridNodeDescriptor): ISerializedNode {\n\tif (isGridBranchNodeDescriptor(nodeDescriptor)) {\n\t\treturn { type: 'branch', data: nodeDescriptor.groups.map(c => createSerializedNode(c)), size: nodeDescriptor.size! };\n\t} else {\n\t\treturn { type: 'leaf', data: nodeDescriptor.data, size: nodeDescriptor.size! };\n\t}\n}\n\nfunction getDimensions(node: ISerializedNode, orientation: Orientation): { width?: number; height?: number } {\n\tif (node.type === 'branch') {\n\t\tconst childrenDimensions = node.data.map(c => getDimensions(c, orthogonal(orientation)));\n\n\t\tif (orientation === Orientation.VERTICAL) {\n\t\t\tconst width = node.size || (childrenDimensions.length === 0 ? undefined : Math.max(...childrenDimensions.map(d => d.width || 0)));\n\t\t\tconst height = childrenDimensions.length === 0 ? undefined : childrenDimensions.reduce((r, d) => r + (d.height || 0), 0);\n\t\t\treturn { width, height };\n\t\t} else {\n\t\t\tconst width = childrenDimensions.length === 0 ? undefined : childrenDimensions.reduce((r, d) => r + (d.width || 0), 0);\n\t\t\tconst height = node.size || (childrenDimensions.length === 0 ? undefined : Math.max(...childrenDimensions.map(d => d.height || 0)));\n\t\t\treturn { width, height };\n\t\t}\n\t} else {\n\t\tconst width = orientation === Orientation.VERTICAL ? node.size : undefined;\n\t\tconst height = orientation === Orientation.VERTICAL ? undefined : node.size;\n\t\treturn { width, height };\n\t}\n}\n\n/**\n * Creates a new JSON object from a {@link GridDescriptor}, which can\n * be deserialized by {@link SerializableGrid.deserialize}.\n */\nexport function createSerializedGrid(gridDescriptor: GridDescriptor): ISerializedGrid {\n\tsanitizeGridNodeDescriptor(gridDescriptor, true);\n\n\tconst root = createSerializedNode(gridDescriptor);\n\tconst { width, height } = getDimensions(root, gridDescriptor.orientation);\n\n\treturn {\n\t\troot,\n\t\torientation: gridDescriptor.orientation,\n\t\twidth: width || 1,\n\t\theight: height || 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 { isFirefox } from 'vs/base/browser/browser';\nimport { DataTransfers } from 'vs/base/browser/dnd';\nimport { $, addDisposableListener, append, clearNode, EventHelper, EventType, getWindow, trackFocus } from 'vs/base/browser/dom';\nimport { DomEmitter } from 'vs/base/browser/event';\nimport { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';\nimport { Gesture, EventType as TouchEventType } from 'vs/base/browser/touch';\nimport { IBoundarySashes, Orientation } from 'vs/base/browser/ui/sash/sash';\nimport { Color, RGBA } from 'vs/base/common/color';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { KeyCode } from 'vs/base/common/keyCodes';\nimport { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';\nimport { ScrollEvent } from 'vs/base/common/scrollable';\nimport 'vs/css!./paneview';\nimport { localize } from 'vs/nls';\nimport { IView, Sizing, SplitView } from './splitview';\n\nexport interface IPaneOptions {\n\tminimumBodySize?: number;\n\tmaximumBodySize?: number;\n\texpanded?: boolean;\n\torientation?: Orientation;\n\ttitle: string;\n\ttitleDescription?: string;\n}\n\nexport interface IPaneStyles {\n\treadonly dropBackground: string | undefined;\n\treadonly headerForeground: string | undefined;\n\treadonly headerBackground: string | undefined;\n\treadonly headerBorder: string | undefined;\n\treadonly leftBorder: string | undefined;\n}\n\n/**\n * A Pane is a structured SplitView view.\n *\n * WARNING: You must call `render()` after you construct it.\n * It can't be done automatically at the end of the ctor\n * because of the order of property initialization in TypeScript.\n * Subclasses wouldn't be able to set own properties\n * before the `render()` call, thus forbidding their use.\n */\nexport abstract class Pane extends Disposable implements IView {\n\n\tprivate static readonly HEADER_SIZE = 22;\n\n\treadonly element: HTMLElement;\n\tprivate header!: HTMLElement;\n\tprivate body!: HTMLElement;\n\n\tprotected _expanded: boolean;\n\tprotected _orientation: Orientation;\n\n\tprivate expandedSize: number | undefined = undefined;\n\tprivate _headerVisible = true;\n\tprivate _collapsible = true;\n\tprivate _bodyRendered = false;\n\tprivate _minimumBodySize: number;\n\tprivate _maximumBodySize: number;\n\tprivate _ariaHeaderLabel: string;\n\tprivate styles: IPaneStyles = {\n\t\tdropBackground: undefined,\n\t\theaderBackground: undefined,\n\t\theaderBorder: undefined,\n\t\theaderForeground: undefined,\n\t\tleftBorder: undefined\n\t};\n\tprivate animationTimer: number | undefined = undefined;\n\n\tprivate readonly _onDidChange = this._register(new Emitter());\n\treadonly onDidChange: Event = this._onDidChange.event;\n\n\tprivate readonly _onDidChangeExpansionState = this._register(new Emitter());\n\treadonly onDidChangeExpansionState: Event = this._onDidChangeExpansionState.event;\n\n\tget ariaHeaderLabel(): string {\n\t\treturn this._ariaHeaderLabel;\n\t}\n\n\tset ariaHeaderLabel(newLabel: string) {\n\t\tthis._ariaHeaderLabel = newLabel;\n\t\tthis.header.setAttribute('aria-label', this.ariaHeaderLabel);\n\t}\n\n\tget draggableElement(): HTMLElement {\n\t\treturn this.header;\n\t}\n\n\tget dropTargetElement(): HTMLElement {\n\t\treturn this.element;\n\t}\n\n\tget dropBackground(): string | undefined {\n\t\treturn this.styles.dropBackground;\n\t}\n\n\tget minimumBodySize(): number {\n\t\treturn this._minimumBodySize;\n\t}\n\n\tset minimumBodySize(size: number) {\n\t\tthis._minimumBodySize = size;\n\t\tthis._onDidChange.fire(undefined);\n\t}\n\n\tget maximumBodySize(): number {\n\t\treturn this._maximumBodySize;\n\t}\n\n\tset maximumBodySize(size: number) {\n\t\tthis._maximumBodySize = size;\n\t\tthis._onDidChange.fire(undefined);\n\t}\n\n\tprivate get headerSize(): number {\n\t\treturn this.headerVisible ? Pane.HEADER_SIZE : 0;\n\t}\n\n\tget minimumSize(): number {\n\t\tconst headerSize = this.headerSize;\n\t\tconst expanded = !this.headerVisible || this.isExpanded();\n\t\tconst minimumBodySize = expanded ? this.minimumBodySize : 0;\n\n\t\treturn headerSize + minimumBodySize;\n\t}\n\n\tget maximumSize(): number {\n\t\tconst headerSize = this.headerSize;\n\t\tconst expanded = !this.headerVisible || this.isExpanded();\n\t\tconst maximumBodySize = expanded ? this.maximumBodySize : 0;\n\n\t\treturn headerSize + maximumBodySize;\n\t}\n\n\torthogonalSize: number = 0;\n\n\tconstructor(options: IPaneOptions) {\n\t\tsuper();\n\t\tthis._expanded = typeof options.expanded === 'undefined' ? true : !!options.expanded;\n\t\tthis._orientation = typeof options.orientation === 'undefined' ? Orientation.VERTICAL : options.orientation;\n\t\tthis._ariaHeaderLabel = localize('viewSection', \"{0} Section\", options.title);\n\t\tthis._minimumBodySize = typeof options.minimumBodySize === 'number' ? options.minimumBodySize : this._orientation === Orientation.HORIZONTAL ? 200 : 120;\n\t\tthis._maximumBodySize = typeof options.maximumBodySize === 'number' ? options.maximumBodySize : Number.POSITIVE_INFINITY;\n\n\t\tthis.element = $('.pane');\n\t}\n\n\tisExpanded(): boolean {\n\t\treturn this._expanded;\n\t}\n\n\tsetExpanded(expanded: boolean): boolean {\n\t\tif (!expanded && !this.collapsible) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (this._expanded === !!expanded) {\n\t\t\treturn false;\n\t\t}\n\n\t\tthis.element?.classList.toggle('expanded', expanded);\n\n\t\tthis._expanded = !!expanded;\n\t\tthis.updateHeader();\n\n\t\tif (expanded) {\n\t\t\tif (!this._bodyRendered) {\n\t\t\t\tthis.renderBody(this.body);\n\t\t\t\tthis._bodyRendered = true;\n\t\t\t}\n\n\t\t\tif (typeof this.animationTimer === 'number') {\n\t\t\t\tgetWindow(this.element).clearTimeout(this.animationTimer);\n\t\t\t}\n\t\t\tappend(this.element, this.body);\n\t\t} else {\n\t\t\tthis.animationTimer = getWindow(this.element).setTimeout(() => {\n\t\t\t\tthis.body.remove();\n\t\t\t}, 200);\n\t\t}\n\n\t\tthis._onDidChangeExpansionState.fire(expanded);\n\t\tthis._onDidChange.fire(expanded ? this.expandedSize : undefined);\n\t\treturn true;\n\t}\n\n\tget headerVisible(): boolean {\n\t\treturn this._headerVisible;\n\t}\n\n\tset headerVisible(visible: boolean) {\n\t\tif (this._headerVisible === !!visible) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._headerVisible = !!visible;\n\t\tthis.updateHeader();\n\t\tthis._onDidChange.fire(undefined);\n\t}\n\n\tget collapsible(): boolean {\n\t\treturn this._collapsible;\n\t}\n\n\tset collapsible(collapsible: boolean) {\n\t\tif (this._collapsible === !!collapsible) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._collapsible = !!collapsible;\n\t\tthis.updateHeader();\n\t}\n\n\tget orientation(): Orientation {\n\t\treturn this._orientation;\n\t}\n\n\tset orientation(orientation: Orientation) {\n\t\tif (this._orientation === orientation) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._orientation = orientation;\n\n\t\tif (this.element) {\n\t\t\tthis.element.classList.toggle('horizontal', this.orientation === Orientation.HORIZONTAL);\n\t\t\tthis.element.classList.toggle('vertical', this.orientation === Orientation.VERTICAL);\n\t\t}\n\n\t\tif (this.header) {\n\t\t\tthis.updateHeader();\n\t\t}\n\t}\n\n\trender(): void {\n\t\tthis.element.classList.toggle('expanded', this.isExpanded());\n\t\tthis.element.classList.toggle('horizontal', this.orientation === Orientation.HORIZONTAL);\n\t\tthis.element.classList.toggle('vertical', this.orientation === Orientation.VERTICAL);\n\n\t\tthis.header = $('.pane-header');\n\t\tappend(this.element, this.header);\n\t\tthis.header.setAttribute('tabindex', '0');\n\t\t// Use role button so the aria-expanded state gets read https://github.com/microsoft/vscode/issues/95996\n\t\tthis.header.setAttribute('role', 'button');\n\t\tthis.header.setAttribute('aria-label', this.ariaHeaderLabel);\n\t\tthis.renderHeader(this.header);\n\n\t\tconst focusTracker = trackFocus(this.header);\n\t\tthis._register(focusTracker);\n\t\tthis._register(focusTracker.onDidFocus(() => this.header.classList.add('focused'), null));\n\t\tthis._register(focusTracker.onDidBlur(() => this.header.classList.remove('focused'), null));\n\n\t\tthis.updateHeader();\n\n\t\tconst eventDisposables = this._register(new DisposableStore());\n\t\tconst onKeyDown = this._register(new DomEmitter(this.header, 'keydown'));\n\t\tconst onHeaderKeyDown = Event.map(onKeyDown.event, e => new StandardKeyboardEvent(e), eventDisposables);\n\n\t\tthis._register(Event.filter(onHeaderKeyDown, e => e.keyCode === KeyCode.Enter || e.keyCode === KeyCode.Space, eventDisposables)(() => this.setExpanded(!this.isExpanded()), null));\n\n\t\tthis._register(Event.filter(onHeaderKeyDown, e => e.keyCode === KeyCode.LeftArrow, eventDisposables)(() => this.setExpanded(false), null));\n\n\t\tthis._register(Event.filter(onHeaderKeyDown, e => e.keyCode === KeyCode.RightArrow, eventDisposables)(() => this.setExpanded(true), null));\n\n\t\tthis._register(Gesture.addTarget(this.header));\n\n\t\t[EventType.CLICK, TouchEventType.Tap].forEach(eventType => {\n\t\t\tthis._register(addDisposableListener(this.header, eventType, e => {\n\t\t\t\tif (!e.defaultPrevented) {\n\t\t\t\t\tthis.setExpanded(!this.isExpanded());\n\t\t\t\t}\n\t\t\t}));\n\t\t});\n\n\t\tthis.body = append(this.element, $('.pane-body'));\n\n\t\t// Only render the body if it will be visible\n\t\t// Otherwise, render it when the pane is expanded\n\t\tif (!this._bodyRendered && this.isExpanded()) {\n\t\t\tthis.renderBody(this.body);\n\t\t\tthis._bodyRendered = true;\n\t\t}\n\n\t\tif (!this.isExpanded()) {\n\t\t\tthis.body.remove();\n\t\t}\n\t}\n\n\tlayout(size: number): void {\n\t\tconst headerSize = this.headerVisible ? Pane.HEADER_SIZE : 0;\n\n\t\tconst width = this._orientation === Orientation.VERTICAL ? this.orthogonalSize : size;\n\t\tconst height = this._orientation === Orientation.VERTICAL ? size - headerSize : this.orthogonalSize - headerSize;\n\n\t\tif (this.isExpanded()) {\n\t\t\tthis.body.classList.toggle('wide', width >= 600);\n\t\t\tthis.layoutBody(height, width);\n\t\t\tthis.expandedSize = size;\n\t\t}\n\t}\n\n\tstyle(styles: IPaneStyles): void {\n\t\tthis.styles = styles;\n\n\t\tif (!this.header) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.updateHeader();\n\t}\n\n\tprotected updateHeader(): void {\n\t\tconst expanded = !this.headerVisible || this.isExpanded();\n\n\t\tif (this.collapsible) {\n\t\t\tthis.header.setAttribute('tabindex', '0');\n\t\t\tthis.header.setAttribute('role', 'button');\n\t\t} else {\n\t\t\tthis.header.removeAttribute('tabindex');\n\t\t\tthis.header.removeAttribute('role');\n\t\t}\n\n\t\tthis.header.style.lineHeight = `${this.headerSize}px`;\n\t\tthis.header.classList.toggle('hidden', !this.headerVisible);\n\t\tthis.header.classList.toggle('expanded', expanded);\n\t\tthis.header.classList.toggle('not-collapsible', !this.collapsible);\n\t\tthis.header.setAttribute('aria-expanded', String(expanded));\n\n\t\tthis.header.style.color = this.collapsible ? this.styles.headerForeground ?? '' : '';\n\t\tthis.header.style.backgroundColor = (this.collapsible ? this.styles.headerBackground : 'transparent') ?? '';\n\t\tthis.header.style.borderTop = this.styles.headerBorder && this.orientation === Orientation.VERTICAL ? `1px solid ${this.styles.headerBorder}` : '';\n\t\tthis.element.style.borderLeft = this.styles.leftBorder && this.orientation === Orientation.HORIZONTAL ? `1px solid ${this.styles.leftBorder}` : '';\n\t}\n\n\tprotected abstract renderHeader(container: HTMLElement): void;\n\tprotected abstract renderBody(container: HTMLElement): void;\n\tprotected abstract layoutBody(height: number, width: number): void;\n}\n\ninterface IDndContext {\n\tdraggable: PaneDraggable | null;\n}\n\nclass PaneDraggable extends Disposable {\n\n\tprivate static readonly DefaultDragOverBackgroundColor = new Color(new RGBA(128, 128, 128, 0.5));\n\n\tprivate dragOverCounter = 0; // see https://github.com/microsoft/vscode/issues/14470\n\n\tprivate _onDidDrop = this._register(new Emitter<{ from: Pane; to: Pane }>());\n\treadonly onDidDrop = this._onDidDrop.event;\n\n\tconstructor(private pane: Pane, private dnd: IPaneDndController, private context: IDndContext) {\n\t\tsuper();\n\n\t\tpane.draggableElement.draggable = true;\n\t\tthis._register(addDisposableListener(pane.draggableElement, 'dragstart', e => this.onDragStart(e)));\n\t\tthis._register(addDisposableListener(pane.dropTargetElement, 'dragenter', e => this.onDragEnter(e)));\n\t\tthis._register(addDisposableListener(pane.dropTargetElement, 'dragleave', e => this.onDragLeave(e)));\n\t\tthis._register(addDisposableListener(pane.dropTargetElement, 'dragend', e => this.onDragEnd(e)));\n\t\tthis._register(addDisposableListener(pane.dropTargetElement, 'drop', e => this.onDrop(e)));\n\t}\n\n\tprivate onDragStart(e: DragEvent): void {\n\t\tif (!this.dnd.canDrag(this.pane) || !e.dataTransfer) {\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t\treturn;\n\t\t}\n\n\t\te.dataTransfer.effectAllowed = 'move';\n\n\t\tif (isFirefox) {\n\t\t\t// Firefox: requires to set a text data transfer to get going\n\t\t\te.dataTransfer?.setData(DataTransfers.TEXT, this.pane.draggableElement.textContent || '');\n\t\t}\n\n\t\tconst dragImage = append(this.pane.element.ownerDocument.body, $('.monaco-drag-image', {}, this.pane.draggableElement.textContent || ''));\n\t\te.dataTransfer.setDragImage(dragImage, -10, -10);\n\t\tsetTimeout(() => this.pane.element.ownerDocument.body.removeChild(dragImage), 0);\n\n\t\tthis.context.draggable = this;\n\t}\n\n\tprivate onDragEnter(e: DragEvent): void {\n\t\tif (!this.context.draggable || this.context.draggable === this) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this.dnd.canDrop(this.context.draggable.pane, this.pane)) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.dragOverCounter++;\n\t\tthis.render();\n\t}\n\n\tprivate onDragLeave(e: DragEvent): void {\n\t\tif (!this.context.draggable || this.context.draggable === this) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this.dnd.canDrop(this.context.draggable.pane, this.pane)) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.dragOverCounter--;\n\n\t\tif (this.dragOverCounter === 0) {\n\t\t\tthis.render();\n\t\t}\n\t}\n\n\tprivate onDragEnd(e: DragEvent): void {\n\t\tif (!this.context.draggable) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.dragOverCounter = 0;\n\t\tthis.render();\n\t\tthis.context.draggable = null;\n\t}\n\n\tprivate onDrop(e: DragEvent): void {\n\t\tif (!this.context.draggable) {\n\t\t\treturn;\n\t\t}\n\n\t\tEventHelper.stop(e);\n\n\t\tthis.dragOverCounter = 0;\n\t\tthis.render();\n\n\t\tif (this.dnd.canDrop(this.context.draggable.pane, this.pane) && this.context.draggable !== this) {\n\t\t\tthis._onDidDrop.fire({ from: this.context.draggable.pane, to: this.pane });\n\t\t}\n\n\t\tthis.context.draggable = null;\n\t}\n\n\tprivate render(): void {\n\t\tlet backgroundColor: string | null = null;\n\n\t\tif (this.dragOverCounter > 0) {\n\t\t\tbackgroundColor = this.pane.dropBackground ?? PaneDraggable.DefaultDragOverBackgroundColor.toString();\n\t\t}\n\n\t\tthis.pane.dropTargetElement.style.backgroundColor = backgroundColor || '';\n\t}\n}\n\nexport interface IPaneDndController {\n\tcanDrag(pane: Pane): boolean;\n\tcanDrop(pane: Pane, overPane: Pane): boolean;\n}\n\nexport class DefaultPaneDndController implements IPaneDndController {\n\n\tcanDrag(pane: Pane): boolean {\n\t\treturn true;\n\t}\n\n\tcanDrop(pane: Pane, overPane: Pane): boolean {\n\t\treturn true;\n\t}\n}\n\nexport interface IPaneViewOptions {\n\tdnd?: IPaneDndController;\n\torientation?: Orientation;\n}\n\ninterface IPaneItem {\n\tpane: Pane;\n\tdisposable: IDisposable;\n}\n\nexport class PaneView extends Disposable {\n\n\tprivate dnd: IPaneDndController | undefined;\n\tprivate dndContext: IDndContext = { draggable: null };\n\treadonly element: HTMLElement;\n\tprivate paneItems: IPaneItem[] = [];\n\tprivate orthogonalSize: number = 0;\n\tprivate size: number = 0;\n\tprivate splitview: SplitView;\n\tprivate animationTimer: number | undefined = undefined;\n\n\tprivate _onDidDrop = this._register(new Emitter<{ from: Pane; to: Pane }>());\n\treadonly onDidDrop: Event<{ from: Pane; to: Pane }> = this._onDidDrop.event;\n\n\torientation: Orientation;\n\tprivate boundarySashes: IBoundarySashes | undefined;\n\treadonly onDidSashChange: Event;\n\treadonly onDidSashReset: Event;\n\treadonly onDidScroll: Event;\n\n\tconstructor(container: HTMLElement, options: IPaneViewOptions = {}) {\n\t\tsuper();\n\n\t\tthis.dnd = options.dnd;\n\t\tthis.orientation = options.orientation ?? Orientation.VERTICAL;\n\t\tthis.element = append(container, $('.monaco-pane-view'));\n\t\tthis.splitview = this._register(new SplitView(this.element, { orientation: this.orientation }));\n\t\tthis.onDidSashReset = this.splitview.onDidSashReset;\n\t\tthis.onDidSashChange = this.splitview.onDidSashChange;\n\t\tthis.onDidScroll = this.splitview.onDidScroll;\n\n\t\tconst eventDisposables = this._register(new DisposableStore());\n\t\tconst onKeyDown = this._register(new DomEmitter(this.element, 'keydown'));\n\t\tconst onHeaderKeyDown = Event.map(Event.filter(onKeyDown.event, e => e.target instanceof HTMLElement && e.target.classList.contains('pane-header'), eventDisposables), e => new StandardKeyboardEvent(e), eventDisposables);\n\n\t\tthis._register(Event.filter(onHeaderKeyDown, e => e.keyCode === KeyCode.UpArrow, eventDisposables)(() => this.focusPrevious()));\n\t\tthis._register(Event.filter(onHeaderKeyDown, e => e.keyCode === KeyCode.DownArrow, eventDisposables)(() => this.focusNext()));\n\t}\n\n\taddPane(pane: Pane, size: number, index = this.splitview.length): void {\n\t\tconst disposables = new DisposableStore();\n\t\tpane.onDidChangeExpansionState(this.setupAnimation, this, disposables);\n\n\t\tconst paneItem = { pane: pane, disposable: disposables };\n\t\tthis.paneItems.splice(index, 0, paneItem);\n\t\tpane.orientation = this.orientation;\n\t\tpane.orthogonalSize = this.orthogonalSize;\n\t\tthis.splitview.addView(pane, size, index);\n\n\t\tif (this.dnd) {\n\t\t\tconst draggable = new PaneDraggable(pane, this.dnd, this.dndContext);\n\t\t\tdisposables.add(draggable);\n\t\t\tdisposables.add(draggable.onDidDrop(this._onDidDrop.fire, this._onDidDrop));\n\t\t}\n\t}\n\n\tremovePane(pane: Pane): void {\n\t\tconst index = this.paneItems.findIndex(item => item.pane === pane);\n\n\t\tif (index === -1) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.splitview.removeView(index, pane.isExpanded() ? Sizing.Distribute : undefined);\n\t\tconst paneItem = this.paneItems.splice(index, 1)[0];\n\t\tpaneItem.disposable.dispose();\n\t}\n\n\tmovePane(from: Pane, to: Pane): void {\n\t\tconst fromIndex = this.paneItems.findIndex(item => item.pane === from);\n\t\tconst toIndex = this.paneItems.findIndex(item => item.pane === to);\n\n\t\tif (fromIndex === -1 || toIndex === -1) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst [paneItem] = this.paneItems.splice(fromIndex, 1);\n\t\tthis.paneItems.splice(toIndex, 0, paneItem);\n\n\t\tthis.splitview.moveView(fromIndex, toIndex);\n\t}\n\n\tresizePane(pane: Pane, size: number): void {\n\t\tconst index = this.paneItems.findIndex(item => item.pane === pane);\n\n\t\tif (index === -1) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.splitview.resizeView(index, size);\n\t}\n\n\tgetPaneSize(pane: Pane): number {\n\t\tconst index = this.paneItems.findIndex(item => item.pane === pane);\n\n\t\tif (index === -1) {\n\t\t\treturn -1;\n\t\t}\n\n\t\treturn this.splitview.getViewSize(index);\n\t}\n\n\tlayout(height: number, width: number): void {\n\t\tthis.orthogonalSize = this.orientation === Orientation.VERTICAL ? width : height;\n\t\tthis.size = this.orientation === Orientation.HORIZONTAL ? width : height;\n\n\t\tfor (const paneItem of this.paneItems) {\n\t\t\tpaneItem.pane.orthogonalSize = this.orthogonalSize;\n\t\t}\n\n\t\tthis.splitview.layout(this.size);\n\t}\n\n\tsetBoundarySashes(sashes: IBoundarySashes) {\n\t\tthis.boundarySashes = sashes;\n\t\tthis.updateSplitviewOrthogonalSashes(sashes);\n\t}\n\n\tprivate updateSplitviewOrthogonalSashes(sashes: IBoundarySashes | undefined) {\n\t\tif (this.orientation === Orientation.VERTICAL) {\n\t\t\tthis.splitview.orthogonalStartSash = sashes?.left;\n\t\t\tthis.splitview.orthogonalEndSash = sashes?.right;\n\t\t} else {\n\t\t\tthis.splitview.orthogonalEndSash = sashes?.bottom;\n\t\t}\n\t}\n\n\tflipOrientation(height: number, width: number): void {\n\t\tthis.orientation = this.orientation === Orientation.VERTICAL ? Orientation.HORIZONTAL : Orientation.VERTICAL;\n\t\tconst paneSizes = this.paneItems.map(pane => this.getPaneSize(pane.pane));\n\n\t\tthis.splitview.dispose();\n\t\tclearNode(this.element);\n\n\t\tthis.splitview = this._register(new SplitView(this.element, { orientation: this.orientation }));\n\t\tthis.updateSplitviewOrthogonalSashes(this.boundarySashes);\n\n\t\tconst newOrthogonalSize = this.orientation === Orientation.VERTICAL ? width : height;\n\t\tconst newSize = this.orientation === Orientation.HORIZONTAL ? width : height;\n\n\t\tthis.paneItems.forEach((pane, index) => {\n\t\t\tpane.pane.orthogonalSize = newOrthogonalSize;\n\t\t\tpane.pane.orientation = this.orientation;\n\n\t\t\tconst viewSize = this.size === 0 ? 0 : (newSize * paneSizes[index]) / this.size;\n\t\t\tthis.splitview.addView(pane.pane, viewSize, index);\n\t\t});\n\n\t\tthis.size = newSize;\n\t\tthis.orthogonalSize = newOrthogonalSize;\n\n\t\tthis.splitview.layout(this.size);\n\t}\n\n\tprivate setupAnimation(): void {\n\t\tif (typeof this.animationTimer === 'number') {\n\t\t\tgetWindow(this.element).clearTimeout(this.animationTimer);\n\t\t}\n\n\t\tthis.element.classList.add('animated');\n\n\t\tthis.animationTimer = getWindow(this.element).setTimeout(() => {\n\t\t\tthis.animationTimer = undefined;\n\t\t\tthis.element.classList.remove('animated');\n\t\t}, 200);\n\t}\n\n\tprivate getPaneHeaderElements(): HTMLElement[] {\n\t\treturn [...this.element.querySelectorAll('.pane-header')] as HTMLElement[];\n\t}\n\n\tprivate focusPrevious(): void {\n\t\tconst headers = this.getPaneHeaderElements();\n\t\tconst index = headers.indexOf(this.element.ownerDocument.activeElement as HTMLElement);\n\n\t\tif (index === -1) {\n\t\t\treturn;\n\t\t}\n\n\t\theaders[Math.max(index - 1, 0)].focus();\n\t}\n\n\tprivate focusNext(): void {\n\t\tconst headers = this.getPaneHeaderElements();\n\t\tconst index = headers.indexOf(this.element.ownerDocument.activeElement as HTMLElement);\n\n\t\tif (index === -1) {\n\t\t\treturn;\n\t\t}\n\n\t\theaders[Math.min(index + 1, headers.length - 1)].focus();\n\t}\n\n\toverride dispose(): void {\n\t\tsuper.dispose();\n\n\t\tthis.paneItems.forEach(i => i.disposable.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 { equals } from 'vs/base/common/arrays';\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\nexport function getEmptyExpression(): IExpression {\n\treturn Object.create(null);\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\nexport function getBasenameTerms(patternOrExpression: ParsedPattern | ParsedExpression): string[] {\n\treturn (patternOrExpression).allBasenames || [];\n}\n\nexport function getPathTerms(patternOrExpression: ParsedPattern | ParsedExpression): string[] {\n\treturn (patternOrExpression).allPaths || [];\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\nexport function patternsEquals(patternsA: Array | undefined, patternsB: Array | undefined): boolean {\n\treturn equals(patternsA, patternsB, (a, b) => {\n\t\tif (typeof a === 'string' && typeof b === 'string') {\n\t\t\treturn a === b;\n\t\t}\n\n\t\tif (typeof a !== 'string' && typeof b !== 'string') {\n\t\t\treturn a.base === b.base && a.pattern === b.pattern;\n\t\t}\n\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 { 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 } 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\tbaseUrl?: never;\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}\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\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(markdown, renderedMarkdown) as unknown as string, 'text/html');\n\n\tmarkdownHtmlDoc.body.querySelectorAll('img')\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.src = _href(href, true);\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(markdown, 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\nfunction sanitizeRenderedMarkdown(\n\toptions: { isTrusted?: boolean | MarkdownStringTrustedOptions },\n\trenderedMarkdown: string,\n): TrustedHTML {\n\tconst { config, allowedSchemes } = getSanitizerOptions(options);\n\tdompurify.addHook('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\tdompurify.addHook('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 {\n\t\t\t\telement.parentElement?.removeChild(element);\n\t\t\t}\n\t\t}\n\t});\n\n\n\tconst hook = DOM.hookDomPurifyHrefAndSrcSanitizer(allowedSchemes);\n\n\ttry {\n\t\treturn dompurify.sanitize(renderedMarkdown, { ...config, RETURN_TRUSTED_TYPE: true });\n\t} finally {\n\t\tdompurify.removeHook('uponSanitizeAttribute');\n\t\thook.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: { readonly isTrusted?: boolean | MarkdownStringTrustedOptions }): { 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: [...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 */\nexport function renderMarkdownAsPlaintext(markdown: IMarkdownString) {\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: 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\nconst plainTextRenderer = new Lazy(() => {\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});\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.ListItem | marked.Tokens.Paragraph): marked.Token | undefined {\n\tfor (let i = 0; i < token.tokens.length; 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} else if (lastLine.includes('**')) {\n\t\t\t\treturn completeDoublestar(token);\n\t\t\t} else if (lastLine.match(/\\*\\w/)) {\n\t\t\t\treturn completeStar(token);\n\t\t\t} else if (lastLine.match(/(^|\\s)__\\w/)) {\n\t\t\t\treturn completeDoubleUnderscore(token);\n\t\t\t} else if (lastLine.match(/(^|\\s)_\\w/)) {\n\t\t\t\treturn completeUnderscore(token);\n\t\t\t} else if (lastLine.match(/(^|\\s)\\[.*\\]\\(\\w*/)) {\n\t\t\t\tconst nextTwoSubTokens = token.tokens.slice(i + 1);\n\t\t\t\tif (nextTwoSubTokens[0]?.type === 'link' && nextTwoSubTokens[1]?.type === 'text' && nextTwoSubTokens[1].raw.match(/^ *\"[^\"]*$/)) {\n\t\t\t\t\t// A markdown link can look like\n\t\t\t\t\t// [link text](https://microsoft.com \"more text\")\n\t\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\t\treturn completeLinkTargetArg(token);\n\t\t\t\t}\n\t\t\t\treturn completeLinkTarget(token);\n\t\t\t} else if (hasStartOfLinkTarget(lastLine)) {\n\t\t\t\treturn completeLinkTarget(token);\n\t\t\t} else if (lastLine.match(/(^|\\s)\\[\\w/) && !token.tokens.slice(i + 1).some(t => hasStartOfLinkTarget(t.raw))) {\n\t\t\t\treturn completeLinkText(token);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\nfunction hasStartOfLinkTarget(str: string): boolean {\n\treturn !!str.match(/^[^\\[]*\\]\\([^\\)]*$/);\n}\n\n// function completeListItemPattern(token: marked.Tokens.List): marked.Tokens.List | undefined {\n// \t// Patch up this one list item\n// \tconst lastItem = token.items[token.items.length - 1];\n\n// \tconst newList = completeSingleLinePattern(lastItem);\n// \tif (!newList || newList.type !== 'list') {\n// \t\t// Nothing to fix, or not a pattern we were expecting\n// \t\treturn;\n// \t}\n\n// \t// Re-parse the whole list with the last item replaced\n// \tconst completeList = marked.lexer(mergeRawTokenText(token.items.slice(0, token.items.length - 1)) + newList.items[0].raw);\n// \tif (completeList.length === 1 && completeList[0].type === 'list') {\n// \t\treturn completeList[0];\n// \t}\n\n// \t// Not a pattern we were expecting\n// \treturn undefined;\n// }\n\nexport function fillInIncompleteTokens(tokens: marked.TokensList): marked.TokensList {\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\t// if (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 tokens;\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, '](about:blank)');\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","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { HoverPosition } from 'vs/base/browser/ui/hover/hoverWidget';\nimport { IHoverDelegate, IHoverDelegateOptions, IHoverDelegateTarget, IHoverWidget } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate';\nimport { TimeoutTimer } from 'vs/base/common/async';\nimport { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';\nimport { IMarkdownString, isMarkdownString } from 'vs/base/common/htmlContent';\nimport { stripIcons } from 'vs/base/common/iconLabels';\nimport { DisposableStore, IDisposable } from 'vs/base/common/lifecycle';\nimport { isFunction, isString } from 'vs/base/common/types';\nimport { localize } from 'vs/nls';\n\nexport interface ITooltipMarkdownString {\n\tmarkdown: IMarkdownString | string | undefined | ((token: CancellationToken) => Promise);\n\tmarkdownNotSupportedFallback: string | undefined;\n}\n\nexport function setupNativeHover(htmlElement: HTMLElement, tooltip: string | ITooltipMarkdownString | undefined): void {\n\tif (isString(tooltip)) {\n\t\t// Icons don't render in the native hover so we strip them out\n\t\thtmlElement.title = stripIcons(tooltip);\n\t} else if (tooltip?.markdownNotSupportedFallback) {\n\t\thtmlElement.title = tooltip.markdownNotSupportedFallback;\n\t} else {\n\t\thtmlElement.removeAttribute('title');\n\t}\n}\n\ntype IHoverContent = string | ITooltipMarkdownString | HTMLElement | undefined;\ntype IHoverContentOrFactory = IHoverContent | (() => IHoverContent);\ntype IResolvedHoverContent = IMarkdownString | string | HTMLElement | undefined;\n\n/**\n * Copied from src\\vs\\workbench\\services\\hover\\browser\\hover.ts\n * @deprecated Use IHoverService\n */\ninterface IHoverAction {\n\tlabel: string;\n\tcommandId: string;\n\ticonClass?: string;\n\trun(target: HTMLElement): void;\n}\n\nexport interface IUpdatableHoverOptions {\n\tactions?: IHoverAction[];\n\tlinkHandler?(url: string): void;\n}\n\nexport interface ICustomHover extends IDisposable {\n\n\t/**\n\t * Allows to programmatically open the hover.\n\t */\n\tshow(focus?: boolean): void;\n\n\t/**\n\t * Allows to programmatically hide the hover.\n\t */\n\thide(): void;\n\n\t/**\n\t * Updates the contents of the hover.\n\t */\n\tupdate(tooltip: IHoverContent, options?: IUpdatableHoverOptions): void;\n}\n\n\nclass 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: IHoverContent, 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);\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: IResolvedHoverContent, 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: IResolvedHoverContent): 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\nexport function setupCustomHover(hoverDelegate: IHoverDelegate, htmlElement: HTMLElement, content: IHoverContentOrFactory, options?: IUpdatableHoverOptions): ICustomHover {\n\tlet hoverPreparation: IDisposable | undefined;\n\n\tlet hoverWidget: UpdatableHoverWidget | undefined;\n\n\tconst hideHover = (disposeWidget: boolean, disposePreparation: boolean) => {\n\t\tconst hadHover = hoverWidget !== undefined;\n\t\tif (disposeWidget) {\n\t\t\thoverWidget?.dispose();\n\t\t\thoverWidget = undefined;\n\t\t}\n\t\tif (disposePreparation) {\n\t\t\thoverPreparation?.dispose();\n\t\t\thoverPreparation = undefined;\n\t\t}\n\t\tif (hadHover) {\n\t\t\thoverDelegate.onDidHideHover?.();\n\t\t\thoverWidget = undefined;\n\t\t}\n\t};\n\n\tconst triggerShowHover = (delay: number, focus?: boolean, target?: IHoverDelegateTarget) => {\n\t\treturn new TimeoutTimer(async () => {\n\t\t\tif (!hoverWidget || hoverWidget.isDisposed) {\n\t\t\t\thoverWidget = new UpdatableHoverWidget(hoverDelegate, target || htmlElement, delay > 0);\n\t\t\t\tawait hoverWidget.update(typeof content === 'function' ? content() : content, focus, options);\n\t\t\t}\n\t\t}, delay);\n\t};\n\n\tlet isMouseDown = false;\n\tconst mouseDownEmitter = dom.addDisposableListener(htmlElement, dom.EventType.MOUSE_DOWN, () => {\n\t\tisMouseDown = true;\n\t\thideHover(true, true);\n\t}, true);\n\tconst mouseUpEmitter = dom.addDisposableListener(htmlElement, dom.EventType.MOUSE_UP, () => {\n\t\tisMouseDown = false;\n\t}, true);\n\tconst mouseLeaveEmitter = dom.addDisposableListener(htmlElement, dom.EventType.MOUSE_LEAVE, (e: MouseEvent) => {\n\t\tisMouseDown = false;\n\t\thideHover(false, (e).fromElement === htmlElement);\n\t}, true);\n\n\tconst onMouseOver = () => {\n\t\tif (hoverPreparation) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst toDispose: DisposableStore = new DisposableStore();\n\n\t\tconst target: IHoverDelegateTarget = {\n\t\t\ttargetElements: [htmlElement],\n\t\t\tdispose: () => { }\n\t\t};\n\t\tif (hoverDelegate.placement === undefined || hoverDelegate.placement === 'mouse') {\n\t\t\t// track the mouse position\n\t\t\tconst onMouseMove = (e: MouseEvent) => {\n\t\t\t\ttarget.x = e.x + 10;\n\t\t\t\tif ((e.target instanceof HTMLElement) && e.target.classList.contains('action-label')) {\n\t\t\t\t\thideHover(true, true);\n\t\t\t\t}\n\t\t\t};\n\t\t\ttoDispose.add(dom.addDisposableListener(htmlElement, dom.EventType.MOUSE_MOVE, onMouseMove, true));\n\t\t}\n\t\ttoDispose.add(triggerShowHover(hoverDelegate.delay, false, target));\n\n\t\thoverPreparation = toDispose;\n\t};\n\tconst mouseOverDomEmitter = dom.addDisposableListener(htmlElement, dom.EventType.MOUSE_OVER, onMouseOver, true);\n\n\tconst onFocus = () => {\n\t\tif (isMouseDown || hoverPreparation) {\n\t\t\treturn;\n\t\t}\n\t\tconst target: IHoverDelegateTarget = {\n\t\t\ttargetElements: [htmlElement],\n\t\t\tdispose: () => { }\n\t\t};\n\t\tconst toDispose: DisposableStore = new DisposableStore();\n\t\tconst onBlur = () => hideHover(true, true);\n\t\ttoDispose.add(dom.addDisposableListener(htmlElement, dom.EventType.BLUR, onBlur, true));\n\t\ttoDispose.add(triggerShowHover(hoverDelegate.delay, false, target));\n\t\thoverPreparation = toDispose;\n\t};\n\tconst focusDomEmitter = dom.addDisposableListener(htmlElement, dom.EventType.FOCUS, onFocus, true);\n\tconst hover: ICustomHover = {\n\t\tshow: focus => {\n\t\t\thideHover(false, true); // terminate a ongoing mouse over preparation\n\t\t\ttriggerShowHover(0, focus); // show hover immediately\n\t\t},\n\t\thide: () => {\n\t\t\thideHover(true, true);\n\t\t},\n\t\tupdate: async (newContent, hoverOptions) => {\n\t\t\tcontent = newContent;\n\t\t\tawait hoverWidget?.update(content, undefined, hoverOptions);\n\t\t},\n\t\tdispose: () => {\n\t\t\tmouseOverDomEmitter.dispose();\n\t\t\tmouseLeaveEmitter.dispose();\n\t\t\tmouseDownEmitter.dispose();\n\t\t\tmouseUpEmitter.dispose();\n\t\t\tfocusDomEmitter.dispose();\n\t\t\thideHover(true, true);\n\t\t}\n\t};\n\treturn hover;\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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, EventHelper, EventType, IFocusTracker, isActiveElement, 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/hoverDelegate';\nimport { ICustomHover, setupCustomHover } from 'vs/base/browser/ui/iconLabel/iconLabelHover';\nimport { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels';\nimport { Action, IAction, IActionRunner } from 'vs/base/common/actions';\nimport { Codicon } from 'vs/base/common/codicons';\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, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';\nimport { ThemeIcon } from 'vs/base/common/themables';\nimport 'vs/css!./button';\nimport { localize } from 'vs/nls';\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}\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\treadonly element: HTMLElement;\n\treadonly onDidClick: BaseEvent;\n\n\tset label(value: string | IMarkdownString);\n\tset icon(value: ThemeIcon);\n\tset enabled(value: boolean);\n\n\tfocus(): void;\n\thasFocus(): boolean;\n}\n\nexport interface IButtonWithDescription extends IButton {\n\tdescription: string;\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: ICustomHover | 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\tget onDidEscape(): BaseEvent { return this._onDidEscape.event; }\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.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\t\tif (!this._hover) {\n\t\t\tthis._hover = this._register(setupCustomHover(getDefaultHoverDelegate('mouse'), this._element, title));\n\t\t} else {\n\t\t\tthis._hover.update(title);\n\t\t}\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', this._element.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 labelShort(value: string) {\n\t\tif (!this.options.supportShortLabel || !this._labelShortElement) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.options.supportIcons) {\n\t\t\treset(this._labelShortElement, ...this.getContentElements(value));\n\t\t} else {\n\t\t\tthis._labelShortElement.textContent = value;\n\t\t}\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\tfocus(): void {\n\t\tthis._element.focus();\n\t}\n\n\thasFocus(): boolean {\n\t\treturn isActiveElement(this._element);\n\t}\n}\n\nexport interface IButtonWithDropdownOptions extends IButtonOptions {\n\treadonly contextMenuProvider: IContextMenuProvider;\n\treadonly actions: readonly IAction[];\n\treadonly actionRunner?: IActionRunner;\n\treadonly addPrimaryActionToDropdown?: boolean;\n}\n\nexport class ButtonWithDropdown extends Disposable implements IButton {\n\n\tprivate readonly button: Button;\n\tprivate readonly action: Action;\n\tprivate readonly dropdownButton: Button;\n\tprivate readonly separatorContainer: HTMLDivElement;\n\tprivate readonly separator: HTMLDivElement;\n\n\treadonly element: HTMLElement;\n\tprivate readonly _onDidClick = this._register(new Emitter());\n\treadonly onDidClick = this._onDidClick.event;\n\n\tconstructor(container: HTMLElement, options: IButtonWithDropdownOptions) {\n\t\tsuper();\n\n\t\tthis.element = document.createElement('div');\n\t\tthis.element.classList.add('monaco-button-dropdown');\n\t\tcontainer.appendChild(this.element);\n\n\t\tthis.button = this._register(new Button(this.element, options));\n\t\tthis._register(this.button.onDidClick(e => this._onDidClick.fire(e)));\n\t\tthis.action = this._register(new Action('primaryAction', renderStringAsPlaintext(this.button.label), undefined, true, async () => this._onDidClick.fire(undefined)));\n\n\t\tthis.separatorContainer = document.createElement('div');\n\t\tthis.separatorContainer.classList.add('monaco-button-dropdown-separator');\n\n\t\tthis.separator = document.createElement('div');\n\t\tthis.separatorContainer.appendChild(this.separator);\n\t\tthis.element.appendChild(this.separatorContainer);\n\n\t\t// Separator styles\n\t\tconst border = options.buttonBorder;\n\t\tif (border) {\n\t\t\tthis.separatorContainer.style.borderTop = '1px solid ' + border;\n\t\t\tthis.separatorContainer.style.borderBottom = '1px solid ' + border;\n\t\t}\n\n\t\tconst buttonBackground = options.secondary ? options.buttonSecondaryBackground : options.buttonBackground;\n\t\tthis.separatorContainer.style.backgroundColor = buttonBackground ?? '';\n\t\tthis.separator.style.backgroundColor = options.buttonSeparator ?? '';\n\n\t\tthis.dropdownButton = this._register(new Button(this.element, { ...options, title: false, supportIcons: true }));\n\t\tthis._register(setupCustomHover(getDefaultHoverDelegate('mouse'), this.dropdownButton.element, localize(\"button dropdown more actions\", 'More Actions...')));\n\t\tthis.dropdownButton.element.setAttribute('aria-haspopup', 'true');\n\t\tthis.dropdownButton.element.setAttribute('aria-expanded', 'false');\n\t\tthis.dropdownButton.element.classList.add('monaco-dropdown-button');\n\t\tthis.dropdownButton.icon = Codicon.dropDownButton;\n\t\tthis._register(this.dropdownButton.onDidClick(e => {\n\t\t\toptions.contextMenuProvider.showContextMenu({\n\t\t\t\tgetAnchor: () => this.dropdownButton.element,\n\t\t\t\tgetActions: () => options.addPrimaryActionToDropdown === false ? [...options.actions] : [this.action, ...options.actions],\n\t\t\t\tactionRunner: options.actionRunner,\n\t\t\t\tonHide: () => this.dropdownButton.element.setAttribute('aria-expanded', 'false')\n\t\t\t});\n\t\t\tthis.dropdownButton.element.setAttribute('aria-expanded', 'true');\n\t\t}));\n\t}\n\n\toverride dispose() {\n\t\tsuper.dispose();\n\t\tthis.element.remove();\n\t}\n\n\tset label(value: string) {\n\t\tthis.button.label = value;\n\t\tthis.action.label = value;\n\t}\n\n\tset icon(icon: ThemeIcon) {\n\t\tthis.button.icon = icon;\n\t}\n\n\tset enabled(enabled: boolean) {\n\t\tthis.button.enabled = enabled;\n\t\tthis.dropdownButton.enabled = enabled;\n\n\t\tthis.element.classList.toggle('disabled', !enabled);\n\t}\n\n\tget enabled(): boolean {\n\t\treturn this.button.enabled;\n\t}\n\n\tfocus(): void {\n\t\tthis.button.focus();\n\t}\n\n\thasFocus(): boolean {\n\t\treturn this.button.hasFocus() || this.dropdownButton.hasFocus();\n\t}\n}\n\nexport class ButtonWithDescription implements IButtonWithDescription {\n\tprivate _button: Button;\n\tprivate _element: HTMLElement;\n\tprivate _descriptionElement: HTMLElement;\n\n\tconstructor(container: HTMLElement, private readonly options: IButtonOptions) {\n\t\tthis._element = document.createElement('div');\n\t\tthis._element.classList.add('monaco-description-button');\n\t\tthis._button = new Button(this._element, options);\n\n\t\tthis._descriptionElement = document.createElement('div');\n\t\tthis._descriptionElement.classList.add('monaco-button-description');\n\t\tthis._element.appendChild(this._descriptionElement);\n\n\t\tcontainer.appendChild(this._element);\n\t}\n\n\tget onDidClick(): BaseEvent {\n\t\treturn this._button.onDidClick;\n\t}\n\n\tget element(): HTMLElement {\n\t\treturn this._element;\n\t}\n\n\tset label(value: string) {\n\t\tthis._button.label = value;\n\t}\n\n\tset icon(icon: ThemeIcon) {\n\t\tthis._button.icon = icon;\n\t}\n\n\tget enabled(): boolean {\n\t\treturn this._button.enabled;\n\t}\n\n\tset enabled(enabled: boolean) {\n\t\tthis._button.enabled = enabled;\n\t}\n\n\tfocus(): void {\n\t\tthis._button.focus();\n\t}\n\thasFocus(): boolean {\n\t\treturn this._button.hasFocus();\n\t}\n\tdispose(): void {\n\t\tthis._button.dispose();\n\t}\n\n\tset description(value: string) {\n\t\tif (this.options.supportIcons) {\n\t\t\treset(this._descriptionElement, ...renderLabelWithIcons(value));\n\t\t} else {\n\t\t\tthis._descriptionElement.textContent = value;\n\t\t}\n\t}\n}\n\nexport class ButtonBar {\n\n\tprivate readonly _buttons: IButton[] = [];\n\tprivate readonly _buttonStore = new DisposableStore();\n\n\tconstructor(private readonly container: HTMLElement) {\n\n\t}\n\n\tdispose(): void {\n\t\tthis._buttonStore.dispose();\n\t}\n\n\tget buttons(): IButton[] {\n\t\treturn this._buttons;\n\t}\n\n\tclear(): void {\n\t\tthis._buttonStore.clear();\n\t\tthis._buttons.length = 0;\n\t}\n\n\taddButton(options: IButtonOptions): IButton {\n\t\tconst button = this._buttonStore.add(new Button(this.container, options));\n\t\tthis.pushButton(button);\n\t\treturn button;\n\t}\n\n\taddButtonWithDescription(options: IButtonOptions): IButtonWithDescription {\n\t\tconst button = this._buttonStore.add(new ButtonWithDescription(this.container, options));\n\t\tthis.pushButton(button);\n\t\treturn button;\n\t}\n\n\taddButtonWithDropdown(options: IButtonWithDropdownOptions): IButton {\n\t\tconst button = this._buttonStore.add(new ButtonWithDropdown(this.container, options));\n\t\tthis.pushButton(button);\n\t\treturn button;\n\t}\n\n\tprivate pushButton(button: IButton): void {\n\t\tthis._buttons.push(button);\n\n\t\tconst index = this._buttons.length - 1;\n\t\tthis._buttonStore.add(addDisposableListener(button.element, EventType.KEY_DOWN, e => {\n\t\t\tconst event = new StandardKeyboardEvent(e);\n\t\t\tlet eventHandled = true;\n\n\t\t\t// Next / Previous Button\n\t\t\tlet buttonIndexToFocus: number | undefined;\n\t\t\tif (event.equals(KeyCode.LeftArrow)) {\n\t\t\t\tbuttonIndexToFocus = index > 0 ? index - 1 : this._buttons.length - 1;\n\t\t\t} else if (event.equals(KeyCode.RightArrow)) {\n\t\t\t\tbuttonIndexToFocus = index === this._buttons.length - 1 ? 0 : index + 1;\n\t\t\t} else {\n\t\t\t\teventHandled = false;\n\t\t\t}\n\n\t\t\tif (eventHandled && typeof buttonIndexToFocus === 'number') {\n\t\t\t\tthis._buttons[buttonIndexToFocus].focus();\n\t\t\t\tEventHelper.stop(e, true);\n\t\t\t}\n\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 { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate';\nimport { ICustomHover, setupCustomHover } from 'vs/base/browser/ui/iconLabel/iconLabelHover';\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\tprivate hover: ICustomHover | undefined;\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\tget label() {\n\t\treturn this._label;\n\t}\n\n\tset tooltip(tooltip: string) {\n\t\tif (this._label) {\n\t\t\tif (!this.hover) {\n\t\t\t\tthis.hover = this._register(setupCustomHover(getDefaultHoverDelegate('mouse'), this._label, tooltip));\n\t\t\t} else {\n\t\t\t\tthis.hover.update(tooltip);\n\t\t\t}\n\t\t}\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\tisVisible(): boolean {\n\t\treturn !!this.visible;\n\t}\n\n\tprotected onEvent(_e: Event, activeElement: HTMLElement): void {\n\t\tthis.hide();\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 '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/iconLabel/iconHoverDelegate';\nimport { ITooltipMarkdownString, setupCustomHover, setupNativeHover } from 'vs/base/browser/ui/iconLabel/iconLabelHover';\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/hoverDelegate';\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 | ITooltipMarkdownString;\n\tdescriptionTitle?: string | ITooltipMarkdownString;\n\tsuffix?: string;\n\thideIcon?: boolean;\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}\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 = 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\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 | ITooltipMarkdownString | 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\tsetupNativeHover(htmlElement, tooltip);\n\t\t} else {\n\t\t\tconst hoverDisposable = setupCustomHover(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 = 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 {\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\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 = 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 = 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 { 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 { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate';\nimport { ICustomHover, setupCustomHover } from 'vs/base/browser/ui/iconLabel/iconLabelHover';\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: ICustomHover;\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._hover = this._register(setupCustomHover(getDefaultHoverDelegate('mouse'), this.selectElement, ''));\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\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._hover.update(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\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._hover.update(this.options[this.selected].text);\n\t\t}\n\t}\n\n\tpublic setAriaLabel(label: string): void {\n\t\tthis.selectBoxOptions.ariaLabel = label;\n\t\tthis.selectElement.setAttribute('aria-label', this.selectBoxOptions.ariaLabel);\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._hover.update(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._hover.update(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, unthemedListStyles } 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\tsetAriaLabel(label: string): 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 const unthemedSelectBoxStyles: ISelectBoxStyles = {\n\t...unthemedListStyles,\n\tselectBackground: '#3C3C3C',\n\tselectForeground: '#F0F0F0',\n\tselectBorder: '#3C3C3C',\n\tdecoratorRightForeground: undefined,\n\tselectListBackground: undefined,\n\tselectListBorder: undefined,\n\tfocusBorder: 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\tsetAriaLabel(label: string): void {\n\t\tthis.selectBoxDelegate.setAriaLabel(label);\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/hoverDelegate';\nimport { IHoverDelegate } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate';\nimport { ICustomHover, setupCustomHover } from 'vs/base/browser/ui/iconLabel/iconLabelHover';\nimport { ISelectBoxOptions, ISelectBoxStyles, ISelectOptionItem, SelectBox } from 'vs/base/browser/ui/selectBox/selectBox';\nimport { IToggleStyles } from 'vs/base/browser/ui/toggle/toggle';\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';\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?: ICustomHover;\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\tisFocused(): boolean {\n\t\treturn !!this.element?.classList.contains('focused');\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 supported with context view */\n\t\t\tthis.element.title = title;\n\t\t} else {\n\t\t\tif (!this.customHover) {\n\t\t\t\tconst hoverDelegate = this.options.hoverDelegate ?? getDefaultHoverDelegate('element');\n\t\t\t\tthis.customHover = setupCustomHover(hoverDelegate, this.element, title);\n\t\t\t\tthis._store.add(this.customHover);\n\t\t\t} else {\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\ttoggleStyles?: IToggleStyles;\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 isFocused(): boolean {\n\t\treturn !!this.label && this.label?.tabIndex === 0;\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\tsetOptions(options: ISelectOptionItem[], selected?: number): void {\n\t\tthis.selectBox.setOptions(options, selected);\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 { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate';\nimport { IHoverDelegate } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate';\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(getDefaultHoverDelegate('element', true));\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\tsetAriaLabel(label: string): void {\n\t\tif (label) {\n\t\t\tthis.actionsList.setAttribute('aria-label', label);\n\t\t} else {\n\t\t\tthis.actionsList.removeAttribute('aria-label');\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\thasAction(action: IAction): boolean {\n\t\treturn this.viewItems.findIndex(candidate => candidate.action.id === action.id) !== -1;\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\tgetWidth(index: number): number {\n\t\tif (index >= 0 && index < this.actionsList.children.length) {\n\t\t\tconst item = this.actionsList.children.item(index);\n\t\t\tif (item) {\n\t\t\t\treturn item.clientWidth;\n\t\t\t}\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\tgetHeight(index: number): number {\n\t\tif (index >= 0 && index < this.actionsList.children.length) {\n\t\t\tconst item = this.actionsList.children.item(index);\n\t\t\tif (item) {\n\t\t\t\treturn item.clientHeight;\n\t\t\t}\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\tpull(index: number): void {\n\t\tif (index >= 0 && index < this.viewItems.length) {\n\t\t\tthis.actionsList.removeChild(this.actionsList.childNodes[index]);\n\t\t\tthis.viewItemDisposables.deleteAndDispose(this.viewItems[index]);\n\t\t\tdispose(this.viewItems.splice(index, 1));\n\t\t\tthis.refreshRole();\n\t\t}\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\nexport function prepareActions(actions: IAction[]): IAction[] {\n\tif (!actions.length) {\n\t\treturn actions;\n\t}\n\n\t// Clean up leading separators\n\tlet firstIndexOfAction = -1;\n\tfor (let i = 0; i < actions.length; i++) {\n\t\tif (actions[i].id === Separator.ID) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tfirstIndexOfAction = i;\n\t\tbreak;\n\t}\n\n\tif (firstIndexOfAction === -1) {\n\t\treturn [];\n\t}\n\n\tactions = actions.slice(firstIndexOfAction);\n\n\t// Clean up trailing separators\n\tfor (let h = actions.length - 1; h >= 0; h--) {\n\t\tconst isSeparator = actions[h].id === Separator.ID;\n\t\tif (isSeparator) {\n\t\t\tactions.splice(h, 1);\n\t\t} else {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Clean up separator duplicates\n\tlet foundAction = false;\n\tfor (let k = actions.length - 1; k >= 0; k--) {\n\t\tconst isSeparator = actions[k].id === Separator.ID;\n\t\tif (isSeparator && !foundAction) {\n\t\t\tactions.splice(k, 1);\n\t\t} else if (!isSeparator) {\n\t\t\tfoundAction = true;\n\t\t} else if (isSeparator) {\n\t\t\tfoundAction = false;\n\t\t}\n\t}\n\n\treturn actions;\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { IContextMenuProvider } from 'vs/base/browser/contextmenu';\nimport { $, addDisposableListener, append, EventType, h } from 'vs/base/browser/dom';\nimport { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';\nimport { IActionViewItemProvider } from 'vs/base/browser/ui/actionbar/actionbar';\nimport { ActionViewItem, BaseActionViewItem, IActionViewItemOptions, 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 { Action, IAction, IActionRunner } from 'vs/base/common/actions';\nimport { Codicon } from 'vs/base/common/codicons';\nimport { ThemeIcon } from 'vs/base/common/themables';\nimport { Emitter } from 'vs/base/common/event';\nimport { KeyCode } from 'vs/base/common/keyCodes';\nimport { ResolvedKeybinding } from 'vs/base/common/keybindings';\nimport { IDisposable } from 'vs/base/common/lifecycle';\nimport 'vs/css!./dropdown';\nimport { setupCustomHover } from 'vs/base/browser/ui/iconLabel/iconLabelHover';\nimport { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate';\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(setupCustomHover(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\nexport interface IActionWithDropdownActionViewItemOptions extends IActionViewItemOptions {\n\treadonly menuActionsOrProvider: readonly IAction[] | IActionProvider;\n\treadonly menuActionClassNames?: string[];\n}\n\nexport class ActionWithDropdownActionViewItem extends ActionViewItem {\n\n\tprotected dropdownMenuActionViewItem: DropdownMenuActionViewItem | undefined;\n\n\tconstructor(\n\t\tcontext: unknown,\n\t\taction: IAction,\n\t\toptions: IActionWithDropdownActionViewItemOptions,\n\t\tprivate readonly contextMenuProvider: IContextMenuProvider\n\t) {\n\t\tsuper(context, action, options);\n\t}\n\n\toverride render(container: HTMLElement): void {\n\t\tsuper.render(container);\n\t\tif (this.element) {\n\t\t\tthis.element.classList.add('action-dropdown-item');\n\t\t\tconst menuActionsProvider = {\n\t\t\t\tgetActions: () => {\n\t\t\t\t\tconst actionsProvider = (this.options).menuActionsOrProvider;\n\t\t\t\t\treturn Array.isArray(actionsProvider) ? actionsProvider : (actionsProvider as IActionProvider).getActions(); // TODO: microsoft/TypeScript#42768\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tconst menuActionClassNames = (this.options).menuActionClassNames || [];\n\t\t\tconst separator = h('div.action-dropdown-item-separator', [h('div', {})]).root;\n\t\t\tseparator.classList.toggle('prominent', menuActionClassNames.includes('prominent'));\n\t\t\tappend(this.element, separator);\n\n\t\t\tthis.dropdownMenuActionViewItem = this._register(new DropdownMenuActionViewItem(this._register(new Action('dropdownAction', nls.localize('moreActions', \"More Actions...\"))), menuActionsProvider, this.contextMenuProvider, { classNames: ['dropdown', ...ThemeIcon.asClassNameArray(Codicon.dropDownButton), ...menuActionClassNames], hoverDelegate: this.options.hoverDelegate }));\n\t\t\tthis.dropdownMenuActionViewItem.render(this.element);\n\n\t\t\tthis._register(addDisposableListener(this.element, EventType.KEY_DOWN, e => {\n\t\t\t\t// If we don't have any actions then the dropdown is hidden so don't try to focus it #164050\n\t\t\t\tif (menuActionsProvider.getActions().length === 0) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst event = new StandardKeyboardEvent(e);\n\t\t\t\tlet handled: boolean = false;\n\t\t\t\tif (this.dropdownMenuActionViewItem?.isFocused() && event.equals(KeyCode.LeftArrow)) {\n\t\t\t\t\thandled = true;\n\t\t\t\t\tthis.dropdownMenuActionViewItem?.blur();\n\t\t\t\t\tthis.focus();\n\t\t\t\t} else if (this.isFocused() && event.equals(KeyCode.RightArrow)) {\n\t\t\t\t\thandled = true;\n\t\t\t\t\tthis.blur();\n\t\t\t\t\tthis.dropdownMenuActionViewItem?.focus();\n\t\t\t\t}\n\t\t\t\tif (handled) {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t}\n\t\t\t}));\n\t\t}\n\t}\n\n\toverride blur(): void {\n\t\tsuper.blur();\n\t\tthis.dropdownMenuActionViewItem?.blur();\n\t}\n\n\toverride setFocusable(focusable: boolean): void {\n\t\tsuper.setFocusable(focusable);\n\t\tthis.dropdownMenuActionViewItem?.setFocusable(focusable);\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { 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\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\tthis.input.title = tooltip;\n\t}\n\n\tpublic setAriaLabel(label: string): void {\n\t\tthis.ariaLabel = label;\n\n\t\tif (label) {\n\t\t\tthis.input.setAttribute('aria-label', this.ariaLabel);\n\t\t} else {\n\t\t\tthis.input.removeAttribute('aria-label');\n\t\t}\n\t}\n\n\tpublic getAriaLabel(): string {\n\t\treturn this.ariaLabel;\n\t}\n\n\tpublic get mirrorElement(): HTMLElement | undefined {\n\t\treturn this.mirror;\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 step(): string {\n\t\treturn this.input.step;\n\t}\n\n\tpublic set step(newValue: string) {\n\t\tthis.input.step = newValue;\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 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 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 get width(): number {\n\t\treturn dom.getTotalWidth(this.input);\n\t}\n\n\tpublic set width(width: number) {\n\t\tif (this.options.flexibleHeight && this.options.flexibleWidth) {\n\t\t\t// textarea with horizontal scrolling\n\t\t\tlet horizontalPadding = 0;\n\t\t\tif (this.mirror) {\n\t\t\t\tconst paddingLeft = parseFloat(this.mirror.style.paddingLeft || '') || 0;\n\t\t\t\tconst paddingRight = parseFloat(this.mirror.style.paddingRight || '') || 0;\n\t\t\t\thorizontalPadding = paddingLeft + paddingRight;\n\t\t\t}\n\t\t\tthis.input.style.width = (width - horizontalPadding) + 'px';\n\t\t} else {\n\t\t\tthis.input.style.width = width + 'px';\n\t\t}\n\n\t\tif (this.mirror) {\n\t\t\tthis.mirror.style.width = width + 'px';\n\t\t}\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 isInputValid(): boolean {\n\t\treturn !!this.validation && !this.validation(this.value);\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 prependHistory(restoredHistory: string[]): void {\n\t\tconst newHistory = this.getHistory();\n\t\tthis.clearHistory();\n\n\t\trestoredHistory.forEach((item) => {\n\t\t\tthis.history.add(item);\n\t\t});\n\n\t\tnewHistory.forEach(item => {\n\t\t\tthis.history.add(item);\n\t\t});\n\t}\n\n\tpublic getHistory(): string[] {\n\t\treturn this.history.getHistory();\n\t}\n\n\tpublic isAtFirstInHistory(): boolean {\n\t\treturn this.history.isFirst();\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 clearHistory(): void {\n\t\tthis.history.clear();\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 'vs/css!./iconSelectBox';\nimport * as dom from 'vs/base/browser/dom';\nimport { alert } from 'vs/base/browser/ui/aria/aria';\nimport { IInputBoxStyles, InputBox } from 'vs/base/browser/ui/inputbox/inputBox';\nimport { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';\nimport { Emitter } from 'vs/base/common/event';\nimport { IDisposable, DisposableStore, Disposable, MutableDisposable } from 'vs/base/common/lifecycle';\nimport { ThemeIcon } from 'vs/base/common/themables';\nimport { localize } from 'vs/nls';\nimport { IMatch } from 'vs/base/common/filters';\nimport { ScrollbarVisibility } from 'vs/base/common/scrollable';\nimport { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';\n\nexport interface IIconSelectBoxOptions {\n\treadonly icons: ThemeIcon[];\n\treadonly inputBoxStyles: IInputBoxStyles;\n\treadonly showIconInfo?: boolean;\n}\n\ninterface IRenderedIconItem {\n\treadonly icon: ThemeIcon;\n\treadonly element: HTMLElement;\n\treadonly highlightMatches?: IMatch[];\n}\n\nexport class IconSelectBox extends Disposable {\n\n\tprivate static InstanceCount = 0;\n\treadonly domId = `icon_select_box_id_${++IconSelectBox.InstanceCount}`;\n\n\treadonly domNode: HTMLElement;\n\n\tprivate _onDidSelect = this._register(new Emitter());\n\treadonly onDidSelect = this._onDidSelect.event;\n\n\tprivate renderedIcons: IRenderedIconItem[] = [];\n\n\tprivate focusedItemIndex: number = 0;\n\tprivate numberOfElementsPerRow: number = 1;\n\n\tprotected inputBox: InputBox | undefined;\n\tprivate scrollableElement: DomScrollableElement | undefined;\n\tprivate iconsContainer: HTMLElement | undefined;\n\tprivate iconIdElement: HighlightedLabel | undefined;\n\tprivate readonly iconContainerWidth = 36;\n\tprivate readonly iconContainerHeight = 36;\n\n\tconstructor(\n\t\tprivate readonly options: IIconSelectBoxOptions,\n\t) {\n\t\tsuper();\n\t\tthis.domNode = dom.$('.icon-select-box');\n\t\tthis._register(this.create());\n\t}\n\n\tprivate create(): IDisposable {\n\t\tconst disposables = new DisposableStore();\n\n\t\tconst iconSelectBoxContainer = dom.append(this.domNode, dom.$('.icon-select-box-container'));\n\t\ticonSelectBoxContainer.style.margin = '10px 15px';\n\n\t\tconst iconSelectInputContainer = dom.append(iconSelectBoxContainer, dom.$('.icon-select-input-container'));\n\t\ticonSelectInputContainer.style.paddingBottom = '10px';\n\t\tthis.inputBox = disposables.add(new InputBox(iconSelectInputContainer, undefined, {\n\t\t\tplaceholder: localize('iconSelect.placeholder', \"Search icons\"),\n\t\t\tinputBoxStyles: this.options.inputBoxStyles,\n\t\t}));\n\n\t\tconst iconsContainer = this.iconsContainer = dom.$('.icon-select-icons-container', { id: `${this.domId}_icons` });\n\t\ticonsContainer.role = 'listbox';\n\t\ticonsContainer.tabIndex = 0;\n\t\tthis.scrollableElement = disposables.add(new DomScrollableElement(iconsContainer, {\n\t\t\tuseShadows: false,\n\t\t\thorizontal: ScrollbarVisibility.Hidden,\n\t\t}));\n\t\tdom.append(iconSelectBoxContainer, this.scrollableElement.getDomNode());\n\n\t\tif (this.options.showIconInfo) {\n\t\t\tthis.iconIdElement = new HighlightedLabel(dom.append(dom.append(iconSelectBoxContainer, dom.$('.icon-select-id-container')), dom.$('.icon-select-id-label')));\n\t\t}\n\n\t\tconst iconsDisposables = disposables.add(new MutableDisposable());\n\t\ticonsDisposables.value = this.renderIcons(this.options.icons, [], iconsContainer);\n\t\tthis.scrollableElement.scanDomNode();\n\n\t\tdisposables.add(this.inputBox.onDidChange(value => {\n\t\t\tconst icons = [], matches = [];\n\t\t\tfor (const icon of this.options.icons) {\n\t\t\t\tconst match = this.matchesContiguous(value, icon.id);\n\t\t\t\tif (match) {\n\t\t\t\t\ticons.push(icon);\n\t\t\t\t\tmatches.push(match);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (icons.length) {\n\t\t\t\ticonsDisposables.value = this.renderIcons(icons, matches, iconsContainer);\n\t\t\t\tthis.scrollableElement?.scanDomNode();\n\t\t\t}\n\t\t}));\n\n\t\tthis.inputBox.inputElement.role = 'combobox';\n\t\tthis.inputBox.inputElement.ariaHasPopup = 'menu';\n\t\tthis.inputBox.inputElement.ariaAutoComplete = 'list';\n\t\tthis.inputBox.inputElement.ariaExpanded = 'true';\n\t\tthis.inputBox.inputElement.setAttribute('aria-controls', iconsContainer.id);\n\n\t\treturn disposables;\n\t}\n\n\tprivate renderIcons(icons: ThemeIcon[], matches: IMatch[][], container: HTMLElement): IDisposable {\n\t\tconst disposables = new DisposableStore();\n\t\tdom.clearNode(container);\n\t\tconst focusedIcon = this.renderedIcons[this.focusedItemIndex]?.icon;\n\t\tlet focusedIconIndex = 0;\n\t\tconst renderedIcons: IRenderedIconItem[] = [];\n\t\tif (icons.length) {\n\t\t\tfor (let index = 0; index < icons.length; index++) {\n\t\t\t\tconst icon = icons[index];\n\t\t\t\tconst iconContainer = dom.append(container, dom.$('.icon-container', { id: `${this.domId}_icons_${index}` }));\n\t\t\t\ticonContainer.style.width = `${this.iconContainerWidth}px`;\n\t\t\t\ticonContainer.style.height = `${this.iconContainerHeight}px`;\n\t\t\t\ticonContainer.title = icon.id;\n\t\t\t\ticonContainer.role = 'button';\n\t\t\t\ticonContainer.setAttribute('aria-setsize', `${icons.length}`);\n\t\t\t\ticonContainer.setAttribute('aria-posinset', `${index + 1}`);\n\t\t\t\tdom.append(iconContainer, dom.$(ThemeIcon.asCSSSelector(icon)));\n\t\t\t\trenderedIcons.push({ icon, element: iconContainer, highlightMatches: matches[index] });\n\n\t\t\t\tdisposables.add(dom.addDisposableListener(iconContainer, dom.EventType.CLICK, (e: MouseEvent) => {\n\t\t\t\t\te.stopPropagation();\n\t\t\t\t\tthis.setSelection(index);\n\t\t\t\t}));\n\n\t\t\t\tif (icon === focusedIcon) {\n\t\t\t\t\tfocusedIconIndex = index;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tconst noResults = localize('iconSelect.noResults', \"No results\");\n\t\t\tdom.append(container, dom.$('.icon-no-results', undefined, noResults));\n\t\t\talert(noResults);\n\t\t}\n\n\t\tthis.renderedIcons.splice(0, this.renderedIcons.length, ...renderedIcons);\n\t\tthis.focusIcon(focusedIconIndex);\n\n\t\treturn disposables;\n\t}\n\n\tprivate focusIcon(index: number): void {\n\t\tconst existing = this.renderedIcons[this.focusedItemIndex];\n\t\tif (existing) {\n\t\t\texisting.element.classList.remove('focused');\n\t\t}\n\n\t\tthis.focusedItemIndex = index;\n\t\tconst renderedItem = this.renderedIcons[index];\n\n\t\tif (renderedItem) {\n\t\t\trenderedItem.element.classList.add('focused');\n\t\t}\n\n\t\tif (this.inputBox) {\n\t\t\tif (renderedItem) {\n\t\t\t\tthis.inputBox.inputElement.setAttribute('aria-activedescendant', renderedItem.element.id);\n\t\t\t} else {\n\t\t\t\tthis.inputBox.inputElement.removeAttribute('aria-activedescendant');\n\t\t\t}\n\t\t}\n\n\t\tif (this.iconIdElement) {\n\t\t\tif (renderedItem) {\n\t\t\t\tthis.iconIdElement.set(renderedItem.icon.id, renderedItem.highlightMatches);\n\t\t\t} else {\n\t\t\t\tthis.iconIdElement.set('');\n\t\t\t}\n\t\t}\n\n\t\tthis.reveal(index);\n\t}\n\n\tprivate reveal(index: number): void {\n\t\tif (!this.scrollableElement) {\n\t\t\treturn;\n\t\t}\n\t\tif (index < 0 || index >= this.renderedIcons.length) {\n\t\t\treturn;\n\t\t}\n\t\tconst element = this.renderedIcons[index].element;\n\t\tif (!element) {\n\t\t\treturn;\n\t\t}\n\t\tconst { height } = this.scrollableElement.getScrollDimensions();\n\t\tconst { scrollTop } = this.scrollableElement.getScrollPosition();\n\t\tif (element.offsetTop + this.iconContainerHeight > scrollTop + height) {\n\t\t\tthis.scrollableElement.setScrollPosition({ scrollTop: element.offsetTop + this.iconContainerHeight - height });\n\t\t} else if (element.offsetTop < scrollTop) {\n\t\t\tthis.scrollableElement.setScrollPosition({ scrollTop: element.offsetTop });\n\t\t}\n\t}\n\n\tprivate matchesContiguous(word: string, wordToMatchAgainst: string): IMatch[] | null {\n\t\tconst matchIndex = wordToMatchAgainst.toLowerCase().indexOf(word.toLowerCase());\n\t\tif (matchIndex !== -1) {\n\t\t\treturn [{ start: matchIndex, end: matchIndex + word.length }];\n\t\t}\n\t\treturn null;\n\t}\n\n\tlayout(dimension: dom.Dimension): void {\n\t\tthis.domNode.style.width = `${dimension.width}px`;\n\t\tthis.domNode.style.height = `${dimension.height}px`;\n\n\t\tconst iconsContainerWidth = dimension.width - 30;\n\t\tthis.numberOfElementsPerRow = Math.floor(iconsContainerWidth / this.iconContainerWidth);\n\t\tif (this.numberOfElementsPerRow === 0) {\n\t\t\tthrow new Error('Insufficient width');\n\t\t}\n\n\t\tconst extraSpace = iconsContainerWidth % this.iconContainerWidth;\n\t\tconst iconElementMargin = Math.floor(extraSpace / this.numberOfElementsPerRow);\n\t\tfor (const { element } of this.renderedIcons) {\n\t\t\telement.style.marginRight = `${iconElementMargin}px`;\n\t\t}\n\n\t\tconst containerPadding = extraSpace % this.numberOfElementsPerRow;\n\t\tif (this.iconsContainer) {\n\t\t\tthis.iconsContainer.style.paddingLeft = `${Math.floor(containerPadding / 2)}px`;\n\t\t\tthis.iconsContainer.style.paddingRight = `${Math.ceil(containerPadding / 2)}px`;\n\t\t}\n\n\t\tif (this.scrollableElement) {\n\t\t\tthis.scrollableElement.getDomNode().style.height = `${this.iconIdElement ? dimension.height - 80 : dimension.height - 40}px`;\n\t\t\tthis.scrollableElement.scanDomNode();\n\t\t}\n\t}\n\n\tgetFocus(): number[] {\n\t\treturn [this.focusedItemIndex];\n\t}\n\n\tsetSelection(index: number): void {\n\t\tif (index < 0 || index >= this.renderedIcons.length) {\n\t\t\tthrow new Error(`Invalid index ${index}`);\n\t\t}\n\t\tthis.focusIcon(index);\n\t\tthis._onDidSelect.fire(this.renderedIcons[index].icon);\n\t}\n\n\tclearInput(): void {\n\t\tif (this.inputBox) {\n\t\t\tthis.inputBox.value = '';\n\t\t}\n\t}\n\n\tfocus(): void {\n\t\tthis.inputBox?.focus();\n\t\tthis.focusIcon(0);\n\t}\n\n\tfocusNext(): void {\n\t\tthis.focusIcon((this.focusedItemIndex + 1) % this.renderedIcons.length);\n\t}\n\n\tfocusPrevious(): void {\n\t\tthis.focusIcon((this.focusedItemIndex - 1 + this.renderedIcons.length) % this.renderedIcons.length);\n\t}\n\n\tfocusNextRow(): void {\n\t\tlet nextRowIndex = this.focusedItemIndex + this.numberOfElementsPerRow;\n\t\tif (nextRowIndex >= this.renderedIcons.length) {\n\t\t\tnextRowIndex = (nextRowIndex + 1) % this.numberOfElementsPerRow;\n\t\t\tnextRowIndex = nextRowIndex >= this.renderedIcons.length ? 0 : nextRowIndex;\n\t\t}\n\t\tthis.focusIcon(nextRowIndex);\n\t}\n\n\tfocusPreviousRow(): void {\n\t\tlet previousRowIndex = this.focusedItemIndex - this.numberOfElementsPerRow;\n\t\tif (previousRowIndex < 0) {\n\t\t\tconst numberOfRows = Math.floor(this.renderedIcons.length / this.numberOfElementsPerRow);\n\t\t\tpreviousRowIndex = this.focusedItemIndex + (this.numberOfElementsPerRow * numberOfRows) - 1;\n\t\t\tpreviousRowIndex = previousRowIndex < 0\n\t\t\t\t? this.renderedIcons.length - 1\n\t\t\t\t: previousRowIndex >= this.renderedIcons.length\n\t\t\t\t\t? previousRowIndex - this.numberOfElementsPerRow\n\t\t\t\t\t: previousRowIndex;\n\t\t}\n\t\tthis.focusIcon(previousRowIndex);\n\t}\n\n\tgetFocusedIcon(): ThemeIcon {\n\t\treturn this.renderedIcons[this.focusedItemIndex].icon;\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 { 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, getCodiconFontCharacters } from 'vs/base/common/codicons';\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 Direction {\n\tRight,\n\tLeft\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?: Direction;\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\nexport const unthemedMenuStyles: IMenuStyles = {\n\tshadowColor: undefined,\n\tborderColor: undefined,\n\tforegroundColor: undefined,\n\tbackgroundColor: undefined,\n\tselectionForegroundColor: undefined,\n\tselectionBackgroundColor: undefined,\n\tselectionBorderColor: undefined,\n\tseparatorColor: undefined,\n\tscrollbarShadow: undefined,\n\tscrollbarSliderBackground: undefined,\n\tscrollbarSliderHoverBackground: undefined,\n\tscrollbarSliderActiveBackground: 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\tget scrollOffset(): number {\n\t\treturn this.menuElement.scrollTop;\n\t}\n\n\ttrigger(index: number): void {\n\t\tif (index <= this.viewItems.length && index >= 0) {\n\t\t\tconst item = this.viewItems[index];\n\t\t\tif (item instanceof SubmenuMenuActionViewItem) {\n\t\t\t\tsuper.focus(index);\n\t\t\t\titem.open(true);\n\t\t\t} else if (item instanceof BaseMenuActionViewItem) {\n\t\t\t\tsuper.run(item._action, item._context);\n\t\t\t} else {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\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: Direction;\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 : Direction.Right;\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\topen(selectFirst?: boolean): void {\n\t\tthis.cleanupExistingSubmenu(false);\n\t\tthis.createSubmenu(selectFirst);\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: Direction): { 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 === Direction.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}\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 * as browser from 'vs/base/browser/browser';\nimport * as DOM from 'vs/base/browser/dom';\nimport { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';\nimport { StandardMouseEvent } from 'vs/base/browser/mouseEvent';\nimport { EventType, Gesture, GestureEvent } from 'vs/base/browser/touch';\nimport { cleanMnemonic, Direction, IMenuOptions, IMenuStyles, Menu, MENU_ESCAPED_MNEMONIC_REGEX, MENU_MNEMONIC_REGEX } from 'vs/base/browser/ui/menu/menu';\nimport { ActionRunner, IAction, IActionRunner, Separator, SubmenuAction } from 'vs/base/common/actions';\nimport { asArray } from 'vs/base/common/arrays';\nimport { RunOnceScheduler } from 'vs/base/common/async';\nimport { Codicon } from 'vs/base/common/codicons';\nimport { ThemeIcon } from 'vs/base/common/themables';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { KeyCode, KeyMod, ScanCode, ScanCodeUtils } from 'vs/base/common/keyCodes';\nimport { ResolvedKeybinding } from 'vs/base/common/keybindings';\nimport { Disposable, DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle';\nimport { isMacintosh } from 'vs/base/common/platform';\nimport * as strings from 'vs/base/common/strings';\nimport 'vs/css!./menubar';\nimport * as nls from 'vs/nls';\nimport { mainWindow } from 'vs/base/browser/window';\n\nconst $ = DOM.$;\n\nexport interface IMenuBarOptions {\n\tenableMnemonics?: boolean;\n\tdisableAltFocus?: boolean;\n\tvisibility?: string;\n\tgetKeybinding?: (action: IAction) => ResolvedKeybinding | undefined;\n\talwaysOnMnemonics?: boolean;\n\tcompactMode?: Direction;\n\tactionRunner?: IActionRunner;\n\tgetCompactMenuActions?: () => IAction[];\n}\n\nexport interface MenuBarMenu {\n\tactions: IAction[];\n\tlabel: string;\n}\n\ninterface MenuBarMenuWithElements extends MenuBarMenu {\n\ttitleElement?: HTMLElement;\n\tbuttonElement?: HTMLElement;\n}\n\nenum MenubarState {\n\tHIDDEN,\n\tVISIBLE,\n\tFOCUSED,\n\tOPEN\n}\n\nexport class MenuBar extends Disposable {\n\n\tstatic readonly OVERFLOW_INDEX: number = -1;\n\n\tprivate menus: MenuBarMenuWithElements[];\n\n\tprivate overflowMenu!: MenuBarMenuWithElements & { titleElement: HTMLElement; buttonElement: HTMLElement };\n\n\tprivate focusedMenu: {\n\t\tindex: number;\n\t\tholder?: HTMLElement;\n\t\twidget?: Menu;\n\t} | undefined;\n\n\tprivate focusToReturn: HTMLElement | undefined;\n\tprivate menuUpdater: RunOnceScheduler;\n\n\t// Input-related\n\tprivate _mnemonicsInUse: boolean = false;\n\tprivate openedViaKeyboard: boolean = false;\n\tprivate awaitingAltRelease: boolean = false;\n\tprivate ignoreNextMouseUp: boolean = false;\n\tprivate mnemonics: Map;\n\n\tprivate updatePending: boolean = false;\n\tprivate _focusState: MenubarState;\n\tprivate actionRunner: IActionRunner;\n\n\tprivate readonly _onVisibilityChange: Emitter;\n\tprivate readonly _onFocusStateChange: Emitter;\n\n\tprivate numMenusShown: number = 0;\n\tprivate overflowLayoutScheduled: IDisposable | undefined = undefined;\n\n\tprivate readonly menuDisposables = this._register(new DisposableStore());\n\n\tconstructor(private container: HTMLElement, private options: IMenuBarOptions, private menuStyle: IMenuStyles) {\n\t\tsuper();\n\n\t\tthis.container.setAttribute('role', 'menubar');\n\t\tif (this.isCompact) {\n\t\t\tthis.container.classList.add('compact');\n\t\t}\n\n\t\tthis.menus = [];\n\t\tthis.mnemonics = new Map();\n\n\t\tthis._focusState = MenubarState.VISIBLE;\n\n\t\tthis._onVisibilityChange = this._register(new Emitter());\n\t\tthis._onFocusStateChange = this._register(new Emitter());\n\n\t\tthis.createOverflowMenu();\n\n\t\tthis.menuUpdater = this._register(new RunOnceScheduler(() => this.update(), 200));\n\n\t\tthis.actionRunner = this.options.actionRunner ?? this._register(new ActionRunner());\n\t\tthis._register(this.actionRunner.onWillRun(() => {\n\t\t\tthis.setUnfocusedState();\n\t\t}));\n\n\t\tthis._register(DOM.ModifierKeyEmitter.getInstance().event(this.onModifierKeyToggled, this));\n\n\t\tthis._register(DOM.addDisposableListener(this.container, DOM.EventType.KEY_DOWN, (e) => {\n\t\t\tconst event = new StandardKeyboardEvent(e as KeyboardEvent);\n\t\t\tlet eventHandled = true;\n\t\t\tconst key = !!e.key ? e.key.toLocaleLowerCase() : '';\n\n\t\t\tconst tabNav = isMacintosh && !this.isCompact;\n\n\t\t\tif (event.equals(KeyCode.LeftArrow) || (tabNav && event.equals(KeyCode.Tab | KeyMod.Shift))) {\n\t\t\t\tthis.focusPrevious();\n\t\t\t} else if (event.equals(KeyCode.RightArrow) || (tabNav && event.equals(KeyCode.Tab))) {\n\t\t\t\tthis.focusNext();\n\t\t\t} else if (event.equals(KeyCode.Escape) && this.isFocused && !this.isOpen) {\n\t\t\t\tthis.setUnfocusedState();\n\t\t\t} else if (!this.isOpen && !event.ctrlKey && this.options.enableMnemonics && this.mnemonicsInUse && this.mnemonics.has(key)) {\n\t\t\t\tconst menuIndex = this.mnemonics.get(key)!;\n\t\t\t\tthis.onMenuTriggered(menuIndex, false);\n\t\t\t} else {\n\t\t\t\teventHandled = false;\n\t\t\t}\n\n\t\t\t// Never allow default tab behavior when not compact\n\t\t\tif (!this.isCompact && (event.equals(KeyCode.Tab | KeyMod.Shift) || event.equals(KeyCode.Tab))) {\n\t\t\t\tevent.preventDefault();\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\tconst window = DOM.getWindow(this.container);\n\t\tthis._register(DOM.addDisposableListener(window, DOM.EventType.MOUSE_DOWN, () => {\n\t\t\t// This mouse event is outside the menubar so it counts as a focus out\n\t\t\tif (this.isFocused) {\n\t\t\t\tthis.setUnfocusedState();\n\t\t\t}\n\t\t}));\n\n\t\tthis._register(DOM.addDisposableListener(this.container, DOM.EventType.FOCUS_IN, (e) => {\n\t\t\tconst event = e as FocusEvent;\n\n\t\t\tif (event.relatedTarget) {\n\t\t\t\tif (!this.container.contains(event.relatedTarget as HTMLElement)) {\n\t\t\t\t\tthis.focusToReturn = event.relatedTarget as HTMLElement;\n\t\t\t\t}\n\t\t\t}\n\t\t}));\n\n\t\tthis._register(DOM.addDisposableListener(this.container, DOM.EventType.FOCUS_OUT, (e) => {\n\t\t\tconst event = e as FocusEvent;\n\n\t\t\t// We are losing focus and there is no related target, e.g. webview case\n\t\t\tif (!event.relatedTarget) {\n\t\t\t\tthis.setUnfocusedState();\n\t\t\t}\n\t\t\t// We are losing focus and there is a target, reset focusToReturn value as not to redirect\n\t\t\telse if (event.relatedTarget && !this.container.contains(event.relatedTarget as HTMLElement)) {\n\t\t\t\tthis.focusToReturn = undefined;\n\t\t\t\tthis.setUnfocusedState();\n\t\t\t}\n\t\t}));\n\n\t\tthis._register(DOM.addDisposableListener(window, DOM.EventType.KEY_DOWN, (e: KeyboardEvent) => {\n\t\t\tif (!this.options.enableMnemonics || !e.altKey || e.ctrlKey || e.defaultPrevented) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst key = e.key.toLocaleLowerCase();\n\t\t\tif (!this.mnemonics.has(key)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.mnemonicsInUse = true;\n\t\t\tthis.updateMnemonicVisibility(true);\n\n\t\t\tconst menuIndex = this.mnemonics.get(key)!;\n\t\t\tthis.onMenuTriggered(menuIndex, false);\n\t\t}));\n\n\t\tthis.setUnfocusedState();\n\t}\n\n\tpush(arg: MenuBarMenu | MenuBarMenu[]): void {\n\t\tconst menus: MenuBarMenu[] = asArray(arg);\n\n\t\tmenus.forEach((menuBarMenu) => {\n\t\t\tconst menuIndex = this.menus.length;\n\t\t\tconst cleanMenuLabel = cleanMnemonic(menuBarMenu.label);\n\n\t\t\tconst mnemonicMatches = MENU_MNEMONIC_REGEX.exec(menuBarMenu.label);\n\n\t\t\t// Register mnemonics\n\t\t\tif (mnemonicMatches) {\n\t\t\t\tconst mnemonic = !!mnemonicMatches[1] ? mnemonicMatches[1] : mnemonicMatches[3];\n\n\t\t\t\tthis.registerMnemonic(this.menus.length, mnemonic);\n\t\t\t}\n\n\t\t\tif (this.isCompact) {\n\t\t\t\tthis.menus.push(menuBarMenu);\n\t\t\t} else {\n\t\t\t\tconst buttonElement = $('div.menubar-menu-button', { 'role': 'menuitem', 'tabindex': -1, 'aria-label': cleanMenuLabel, 'aria-haspopup': true });\n\t\t\t\tconst titleElement = $('div.menubar-menu-title', { 'role': 'none', 'aria-hidden': true });\n\n\t\t\t\tbuttonElement.appendChild(titleElement);\n\t\t\t\tthis.container.insertBefore(buttonElement, this.overflowMenu.buttonElement);\n\n\t\t\t\tthis.updateLabels(titleElement, buttonElement, menuBarMenu.label);\n\n\t\t\t\tthis._register(DOM.addDisposableListener(buttonElement, DOM.EventType.KEY_UP, (e) => {\n\t\t\t\t\tconst event = new StandardKeyboardEvent(e as KeyboardEvent);\n\t\t\t\t\tlet eventHandled = true;\n\n\t\t\t\t\tif ((event.equals(KeyCode.DownArrow) || event.equals(KeyCode.Enter)) && !this.isOpen) {\n\t\t\t\t\t\tthis.focusedMenu = { index: menuIndex };\n\t\t\t\t\t\tthis.openedViaKeyboard = true;\n\t\t\t\t\t\tthis.focusState = MenubarState.OPEN;\n\t\t\t\t\t} else {\n\t\t\t\t\t\teventHandled = false;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (eventHandled) {\n\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t\t}\n\t\t\t\t}));\n\n\t\t\t\tthis._register(Gesture.addTarget(buttonElement));\n\t\t\t\tthis._register(DOM.addDisposableListener(buttonElement, EventType.Tap, (e: GestureEvent) => {\n\t\t\t\t\t// Ignore this touch if the menu is touched\n\t\t\t\t\tif (this.isOpen && this.focusedMenu && this.focusedMenu.holder && DOM.isAncestor(e.initialTarget as HTMLElement, this.focusedMenu.holder)) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.ignoreNextMouseUp = false;\n\t\t\t\t\tthis.onMenuTriggered(menuIndex, true);\n\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\te.stopPropagation();\n\t\t\t\t}));\n\n\t\t\t\tthis._register(DOM.addDisposableListener(buttonElement, DOM.EventType.MOUSE_DOWN, (e: MouseEvent) => {\n\t\t\t\t\t// Ignore non-left-click\n\t\t\t\t\tconst mouseEvent = new StandardMouseEvent(DOM.getWindow(buttonElement), e);\n\t\t\t\t\tif (!mouseEvent.leftButton) {\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!this.isOpen) {\n\t\t\t\t\t\t// Open the menu with mouse down and ignore the following mouse up event\n\t\t\t\t\t\tthis.ignoreNextMouseUp = true;\n\t\t\t\t\t\tthis.onMenuTriggered(menuIndex, true);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.ignoreNextMouseUp = false;\n\t\t\t\t\t}\n\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\te.stopPropagation();\n\t\t\t\t}));\n\n\t\t\t\tthis._register(DOM.addDisposableListener(buttonElement, DOM.EventType.MOUSE_UP, (e) => {\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\tif (!this.ignoreNextMouseUp) {\n\t\t\t\t\t\tif (this.isFocused) {\n\t\t\t\t\t\t\tthis.onMenuTriggered(menuIndex, true);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.ignoreNextMouseUp = false;\n\t\t\t\t\t}\n\t\t\t\t}));\n\n\t\t\t\tthis._register(DOM.addDisposableListener(buttonElement, DOM.EventType.MOUSE_ENTER, () => {\n\t\t\t\t\tif (this.isOpen && !this.isCurrentMenu(menuIndex)) {\n\t\t\t\t\t\tbuttonElement.focus();\n\t\t\t\t\t\tthis.cleanupCustomMenu();\n\t\t\t\t\t\tthis.showCustomMenu(menuIndex, false);\n\t\t\t\t\t} else if (this.isFocused && !this.isOpen) {\n\t\t\t\t\t\tthis.focusedMenu = { index: menuIndex };\n\t\t\t\t\t\tbuttonElement.focus();\n\t\t\t\t\t}\n\t\t\t\t}));\n\n\t\t\t\tthis.menus.push({\n\t\t\t\t\tlabel: menuBarMenu.label,\n\t\t\t\t\tactions: menuBarMenu.actions,\n\t\t\t\t\tbuttonElement: buttonElement,\n\t\t\t\t\ttitleElement: titleElement\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t}\n\n\tcreateOverflowMenu(): void {\n\t\tconst label = this.isCompact ? nls.localize('mAppMenu', 'Application Menu') : nls.localize('mMore', 'More');\n\t\tconst buttonElement = $('div.menubar-menu-button', { 'role': 'menuitem', 'tabindex': this.isCompact ? 0 : -1, 'aria-label': label, 'aria-haspopup': true });\n\t\tconst titleElement = $('div.menubar-menu-title.toolbar-toggle-more' + ThemeIcon.asCSSSelector(Codicon.menuBarMore), { 'role': 'none', 'aria-hidden': true });\n\n\t\tbuttonElement.appendChild(titleElement);\n\t\tthis.container.appendChild(buttonElement);\n\t\tbuttonElement.style.visibility = 'hidden';\n\n\t\tthis._register(DOM.addDisposableListener(buttonElement, DOM.EventType.KEY_UP, (e) => {\n\t\t\tconst event = new StandardKeyboardEvent(e as KeyboardEvent);\n\t\t\tlet eventHandled = true;\n\n\t\t\tconst triggerKeys = [KeyCode.Enter];\n\t\t\tif (!this.isCompact) {\n\t\t\t\ttriggerKeys.push(KeyCode.DownArrow);\n\t\t\t} else {\n\t\t\t\ttriggerKeys.push(KeyCode.Space);\n\n\t\t\t\tif (this.options.compactMode === Direction.Right) {\n\t\t\t\t\ttriggerKeys.push(KeyCode.RightArrow);\n\t\t\t\t} else if (this.options.compactMode === Direction.Left) {\n\t\t\t\t\ttriggerKeys.push(KeyCode.LeftArrow);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ((triggerKeys.some(k => event.equals(k)) && !this.isOpen)) {\n\t\t\t\tthis.focusedMenu = { index: MenuBar.OVERFLOW_INDEX };\n\t\t\t\tthis.openedViaKeyboard = true;\n\t\t\t\tthis.focusState = MenubarState.OPEN;\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(Gesture.addTarget(buttonElement));\n\t\tthis._register(DOM.addDisposableListener(buttonElement, EventType.Tap, (e: GestureEvent) => {\n\t\t\t// Ignore this touch if the menu is touched\n\t\t\tif (this.isOpen && this.focusedMenu && this.focusedMenu.holder && DOM.isAncestor(e.initialTarget as HTMLElement, this.focusedMenu.holder)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.ignoreNextMouseUp = false;\n\t\t\tthis.onMenuTriggered(MenuBar.OVERFLOW_INDEX, true);\n\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t}));\n\n\t\tthis._register(DOM.addDisposableListener(buttonElement, DOM.EventType.MOUSE_DOWN, (e) => {\n\t\t\t// Ignore non-left-click\n\t\t\tconst mouseEvent = new StandardMouseEvent(DOM.getWindow(buttonElement), e);\n\t\t\tif (!mouseEvent.leftButton) {\n\t\t\t\te.preventDefault();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (!this.isOpen) {\n\t\t\t\t// Open the menu with mouse down and ignore the following mouse up event\n\t\t\t\tthis.ignoreNextMouseUp = true;\n\t\t\t\tthis.onMenuTriggered(MenuBar.OVERFLOW_INDEX, true);\n\t\t\t} else {\n\t\t\t\tthis.ignoreNextMouseUp = false;\n\t\t\t}\n\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t}));\n\n\t\tthis._register(DOM.addDisposableListener(buttonElement, DOM.EventType.MOUSE_UP, (e) => {\n\t\t\tif (e.defaultPrevented) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (!this.ignoreNextMouseUp) {\n\t\t\t\tif (this.isFocused) {\n\t\t\t\t\tthis.onMenuTriggered(MenuBar.OVERFLOW_INDEX, true);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.ignoreNextMouseUp = false;\n\t\t\t}\n\t\t}));\n\n\t\tthis._register(DOM.addDisposableListener(buttonElement, DOM.EventType.MOUSE_ENTER, () => {\n\t\t\tif (this.isOpen && !this.isCurrentMenu(MenuBar.OVERFLOW_INDEX)) {\n\t\t\t\tthis.overflowMenu.buttonElement.focus();\n\t\t\t\tthis.cleanupCustomMenu();\n\t\t\t\tthis.showCustomMenu(MenuBar.OVERFLOW_INDEX, false);\n\t\t\t} else if (this.isFocused && !this.isOpen) {\n\t\t\t\tthis.focusedMenu = { index: MenuBar.OVERFLOW_INDEX };\n\t\t\t\tbuttonElement.focus();\n\t\t\t}\n\t\t}));\n\n\t\tthis.overflowMenu = {\n\t\t\tbuttonElement: buttonElement,\n\t\t\ttitleElement: titleElement,\n\t\t\tlabel: 'More',\n\t\t\tactions: []\n\t\t};\n\t}\n\n\tupdateMenu(menu: MenuBarMenu): void {\n\t\tconst menuToUpdate = this.menus.filter(menuBarMenu => menuBarMenu.label === menu.label);\n\t\tif (menuToUpdate && menuToUpdate.length) {\n\t\t\tmenuToUpdate[0].actions = menu.actions;\n\t\t}\n\t}\n\n\toverride dispose(): void {\n\t\tsuper.dispose();\n\n\t\tthis.menus.forEach(menuBarMenu => {\n\t\t\tmenuBarMenu.titleElement?.remove();\n\t\t\tmenuBarMenu.buttonElement?.remove();\n\t\t});\n\n\t\tthis.overflowMenu.titleElement.remove();\n\t\tthis.overflowMenu.buttonElement.remove();\n\n\t\tdispose(this.overflowLayoutScheduled);\n\t\tthis.overflowLayoutScheduled = undefined;\n\t}\n\n\tblur(): void {\n\t\tthis.setUnfocusedState();\n\t}\n\n\tgetWidth(): number {\n\t\tif (!this.isCompact && this.menus) {\n\t\t\tconst left = this.menus[0].buttonElement!.getBoundingClientRect().left;\n\t\t\tconst right = this.hasOverflow ? this.overflowMenu.buttonElement.getBoundingClientRect().right : this.menus[this.menus.length - 1].buttonElement!.getBoundingClientRect().right;\n\t\t\treturn right - left;\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\tgetHeight(): number {\n\t\treturn this.container.clientHeight;\n\t}\n\n\ttoggleFocus(): void {\n\t\tif (!this.isFocused && this.options.visibility !== 'hidden') {\n\t\t\tthis.mnemonicsInUse = true;\n\t\t\tthis.focusedMenu = { index: this.numMenusShown > 0 ? 0 : MenuBar.OVERFLOW_INDEX };\n\t\t\tthis.focusState = MenubarState.FOCUSED;\n\t\t} else if (!this.isOpen) {\n\t\t\tthis.setUnfocusedState();\n\t\t}\n\t}\n\n\tprivate updateOverflowAction(): void {\n\t\tif (!this.menus || !this.menus.length) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst overflowMenuOnlyClass = 'overflow-menu-only';\n\n\t\t// Remove overflow only restriction to allow the most space\n\t\tthis.container.classList.toggle(overflowMenuOnlyClass, false);\n\n\t\tconst sizeAvailable = this.container.offsetWidth;\n\t\tlet currentSize = 0;\n\t\tlet full = this.isCompact;\n\t\tconst prevNumMenusShown = this.numMenusShown;\n\t\tthis.numMenusShown = 0;\n\n\t\tconst showableMenus = this.menus.filter(menu => menu.buttonElement !== undefined && menu.titleElement !== undefined) as (MenuBarMenuWithElements & { titleElement: HTMLElement; buttonElement: HTMLElement })[];\n\t\tfor (const menuBarMenu of showableMenus) {\n\t\t\tif (!full) {\n\t\t\t\tconst size = menuBarMenu.buttonElement.offsetWidth;\n\t\t\t\tif (currentSize + size > sizeAvailable) {\n\t\t\t\t\tfull = true;\n\t\t\t\t} else {\n\t\t\t\t\tcurrentSize += size;\n\t\t\t\t\tthis.numMenusShown++;\n\t\t\t\t\tif (this.numMenusShown > prevNumMenusShown) {\n\t\t\t\t\t\tmenuBarMenu.buttonElement.style.visibility = 'visible';\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (full) {\n\t\t\t\tmenuBarMenu.buttonElement.style.visibility = 'hidden';\n\t\t\t}\n\t\t}\n\n\n\t\t// If below minimium menu threshold, show the overflow menu only as hamburger menu\n\t\tif (this.numMenusShown - 1 <= showableMenus.length / 4) {\n\t\t\tfor (const menuBarMenu of showableMenus) {\n\t\t\t\tmenuBarMenu.buttonElement.style.visibility = 'hidden';\n\t\t\t}\n\n\t\t\tfull = true;\n\t\t\tthis.numMenusShown = 0;\n\t\t\tcurrentSize = 0;\n\t\t}\n\n\t\t// Overflow\n\t\tif (this.isCompact) {\n\t\t\tthis.overflowMenu.actions = [];\n\t\t\tfor (let idx = this.numMenusShown; idx < this.menus.length; idx++) {\n\t\t\t\tthis.overflowMenu.actions.push(new SubmenuAction(`menubar.submenu.${this.menus[idx].label}`, this.menus[idx].label, this.menus[idx].actions || []));\n\t\t\t}\n\n\t\t\tconst compactMenuActions = this.options.getCompactMenuActions?.();\n\t\t\tif (compactMenuActions && compactMenuActions.length) {\n\t\t\t\tthis.overflowMenu.actions.push(new Separator());\n\t\t\t\tthis.overflowMenu.actions.push(...compactMenuActions);\n\t\t\t}\n\n\t\t\tthis.overflowMenu.buttonElement.style.visibility = 'visible';\n\t\t} else if (full) {\n\t\t\t// Can't fit the more button, need to remove more menus\n\t\t\twhile (currentSize + this.overflowMenu.buttonElement.offsetWidth > sizeAvailable && this.numMenusShown > 0) {\n\t\t\t\tthis.numMenusShown--;\n\t\t\t\tconst size = showableMenus[this.numMenusShown].buttonElement.offsetWidth;\n\t\t\t\tshowableMenus[this.numMenusShown].buttonElement.style.visibility = 'hidden';\n\t\t\t\tcurrentSize -= size;\n\t\t\t}\n\n\t\t\tthis.overflowMenu.actions = [];\n\t\t\tfor (let idx = this.numMenusShown; idx < showableMenus.length; idx++) {\n\t\t\t\tthis.overflowMenu.actions.push(new SubmenuAction(`menubar.submenu.${showableMenus[idx].label}`, showableMenus[idx].label, showableMenus[idx].actions || []));\n\t\t\t}\n\n\t\t\tif (this.overflowMenu.buttonElement.nextElementSibling !== showableMenus[this.numMenusShown].buttonElement) {\n\t\t\t\tthis.overflowMenu.buttonElement.remove();\n\t\t\t\tthis.container.insertBefore(this.overflowMenu.buttonElement, showableMenus[this.numMenusShown].buttonElement);\n\t\t\t}\n\n\t\t\tthis.overflowMenu.buttonElement.style.visibility = 'visible';\n\t\t} else {\n\t\t\tthis.overflowMenu.buttonElement.remove();\n\t\t\tthis.container.appendChild(this.overflowMenu.buttonElement);\n\t\t\tthis.overflowMenu.buttonElement.style.visibility = 'hidden';\n\t\t}\n\n\t\t// If we are only showing the overflow, add this class to avoid taking up space\n\t\tthis.container.classList.toggle(overflowMenuOnlyClass, this.numMenusShown === 0);\n\t}\n\n\tprivate updateLabels(titleElement: HTMLElement, buttonElement: HTMLElement, label: string): void {\n\t\tconst cleanMenuLabel = cleanMnemonic(label);\n\n\t\t// Update the button label to reflect mnemonics\n\n\t\tif (this.options.enableMnemonics) {\n\t\t\tconst cleanLabel = strings.escape(label);\n\n\t\t\t// This is global so reset it\n\t\t\tMENU_ESCAPED_MNEMONIC_REGEX.lastIndex = 0;\n\t\t\tlet escMatch = MENU_ESCAPED_MNEMONIC_REGEX.exec(cleanLabel);\n\n\t\t\t// We can't use negative lookbehind so we match our negative and skip\n\t\t\twhile (escMatch && escMatch[1]) {\n\t\t\t\tescMatch = MENU_ESCAPED_MNEMONIC_REGEX.exec(cleanLabel);\n\t\t\t}\n\n\t\t\tconst replaceDoubleEscapes = (str: string) => str.replace(/&&/g, '&');\n\n\t\t\tif (escMatch) {\n\t\t\t\ttitleElement.innerText = '';\n\t\t\t\ttitleElement.append(\n\t\t\t\t\tstrings.ltrim(replaceDoubleEscapes(cleanLabel.substr(0, escMatch.index)), ' '),\n\t\t\t\t\t$('mnemonic', { 'aria-hidden': 'true' }, escMatch[3]),\n\t\t\t\t\tstrings.rtrim(replaceDoubleEscapes(cleanLabel.substr(escMatch.index + escMatch[0].length)), ' ')\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\ttitleElement.innerText = replaceDoubleEscapes(cleanLabel).trim();\n\t\t\t}\n\t\t} else {\n\t\t\ttitleElement.innerText = cleanMenuLabel.replace(/&&/g, '&');\n\t\t}\n\n\t\tconst mnemonicMatches = MENU_MNEMONIC_REGEX.exec(label);\n\n\t\t// Register mnemonics\n\t\tif (mnemonicMatches) {\n\t\t\tconst mnemonic = !!mnemonicMatches[1] ? mnemonicMatches[1] : mnemonicMatches[3];\n\n\t\t\tif (this.options.enableMnemonics) {\n\t\t\t\tbuttonElement.setAttribute('aria-keyshortcuts', 'Alt+' + mnemonic.toLocaleLowerCase());\n\t\t\t} else {\n\t\t\t\tbuttonElement.removeAttribute('aria-keyshortcuts');\n\t\t\t}\n\t\t}\n\t}\n\n\tupdate(options?: IMenuBarOptions): void {\n\t\tif (options) {\n\t\t\tthis.options = options;\n\t\t}\n\n\t\t// Don't update while using the menu\n\t\tif (this.isFocused) {\n\t\t\tthis.updatePending = true;\n\t\t\treturn;\n\t\t}\n\n\t\tthis.menus.forEach(menuBarMenu => {\n\t\t\tif (!menuBarMenu.buttonElement || !menuBarMenu.titleElement) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.updateLabels(menuBarMenu.titleElement, menuBarMenu.buttonElement, menuBarMenu.label);\n\t\t});\n\n\t\tif (!this.overflowLayoutScheduled) {\n\t\t\tthis.overflowLayoutScheduled = DOM.scheduleAtNextAnimationFrame(DOM.getWindow(this.container), () => {\n\t\t\t\tthis.updateOverflowAction();\n\t\t\t\tthis.overflowLayoutScheduled = undefined;\n\t\t\t});\n\t\t}\n\n\t\tthis.setUnfocusedState();\n\t}\n\n\tprivate registerMnemonic(menuIndex: number, mnemonic: string): void {\n\t\tthis.mnemonics.set(mnemonic.toLocaleLowerCase(), menuIndex);\n\t}\n\n\tprivate hideMenubar(): void {\n\t\tif (this.container.style.display !== 'none') {\n\t\t\tthis.container.style.display = 'none';\n\t\t\tthis._onVisibilityChange.fire(false);\n\t\t}\n\t}\n\n\tprivate showMenubar(): void {\n\t\tif (this.container.style.display !== 'flex') {\n\t\t\tthis.container.style.display = 'flex';\n\t\t\tthis._onVisibilityChange.fire(true);\n\n\t\t\tthis.updateOverflowAction();\n\t\t}\n\t}\n\n\tprivate get focusState(): MenubarState {\n\t\treturn this._focusState;\n\t}\n\n\tprivate set focusState(value: MenubarState) {\n\t\tif (this._focusState >= MenubarState.FOCUSED && value < MenubarState.FOCUSED) {\n\t\t\t// Losing focus, update the menu if needed\n\n\t\t\tif (this.updatePending) {\n\t\t\t\tthis.menuUpdater.schedule();\n\t\t\t\tthis.updatePending = false;\n\t\t\t}\n\t\t}\n\n\t\tif (value === this._focusState) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst isVisible = this.isVisible;\n\t\tconst isOpen = this.isOpen;\n\t\tconst isFocused = this.isFocused;\n\n\t\tthis._focusState = value;\n\n\t\tswitch (value) {\n\t\t\tcase MenubarState.HIDDEN:\n\t\t\t\tif (isVisible) {\n\t\t\t\t\tthis.hideMenubar();\n\t\t\t\t}\n\n\t\t\t\tif (isOpen) {\n\t\t\t\t\tthis.cleanupCustomMenu();\n\t\t\t\t}\n\n\t\t\t\tif (isFocused) {\n\t\t\t\t\tthis.focusedMenu = undefined;\n\n\t\t\t\t\tif (this.focusToReturn) {\n\t\t\t\t\t\tthis.focusToReturn.focus();\n\t\t\t\t\t\tthis.focusToReturn = undefined;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\n\t\t\t\tbreak;\n\t\t\tcase MenubarState.VISIBLE:\n\t\t\t\tif (!isVisible) {\n\t\t\t\t\tthis.showMenubar();\n\t\t\t\t}\n\n\t\t\t\tif (isOpen) {\n\t\t\t\t\tthis.cleanupCustomMenu();\n\t\t\t\t}\n\n\t\t\t\tif (isFocused) {\n\t\t\t\t\tif (this.focusedMenu) {\n\t\t\t\t\t\tif (this.focusedMenu.index === MenuBar.OVERFLOW_INDEX) {\n\t\t\t\t\t\t\tthis.overflowMenu.buttonElement.blur();\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthis.menus[this.focusedMenu.index].buttonElement?.blur();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.focusedMenu = undefined;\n\n\t\t\t\t\tif (this.focusToReturn) {\n\t\t\t\t\t\tthis.focusToReturn.focus();\n\t\t\t\t\t\tthis.focusToReturn = undefined;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\tcase MenubarState.FOCUSED:\n\t\t\t\tif (!isVisible) {\n\t\t\t\t\tthis.showMenubar();\n\t\t\t\t}\n\n\t\t\t\tif (isOpen) {\n\t\t\t\t\tthis.cleanupCustomMenu();\n\t\t\t\t}\n\n\t\t\t\tif (this.focusedMenu) {\n\t\t\t\t\tif (this.focusedMenu.index === MenuBar.OVERFLOW_INDEX) {\n\t\t\t\t\t\tthis.overflowMenu.buttonElement.focus();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.menus[this.focusedMenu.index].buttonElement?.focus();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase MenubarState.OPEN:\n\t\t\t\tif (!isVisible) {\n\t\t\t\t\tthis.showMenubar();\n\t\t\t\t}\n\n\t\t\t\tif (this.focusedMenu) {\n\t\t\t\t\tthis.cleanupCustomMenu();\n\t\t\t\t\tthis.showCustomMenu(this.focusedMenu.index, this.openedViaKeyboard);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\n\t\tthis._focusState = value;\n\t\tthis._onFocusStateChange.fire(this.focusState >= MenubarState.FOCUSED);\n\t}\n\n\tget isVisible(): boolean {\n\t\treturn this.focusState >= MenubarState.VISIBLE;\n\t}\n\n\tprivate get isFocused(): boolean {\n\t\treturn this.focusState >= MenubarState.FOCUSED;\n\t}\n\n\tprivate get isOpen(): boolean {\n\t\treturn this.focusState >= MenubarState.OPEN;\n\t}\n\n\tprivate get hasOverflow(): boolean {\n\t\treturn this.isCompact || this.numMenusShown < this.menus.length;\n\t}\n\n\tprivate get isCompact(): boolean {\n\t\treturn this.options.compactMode !== undefined;\n\t}\n\n\tprivate setUnfocusedState(): void {\n\t\tif (this.options.visibility === 'toggle' || this.options.visibility === 'hidden') {\n\t\t\tthis.focusState = MenubarState.HIDDEN;\n\t\t} else if (this.options.visibility === 'classic' && browser.isFullscreen(mainWindow)) {\n\t\t\tthis.focusState = MenubarState.HIDDEN;\n\t\t} else {\n\t\t\tthis.focusState = MenubarState.VISIBLE;\n\t\t}\n\n\t\tthis.ignoreNextMouseUp = false;\n\t\tthis.mnemonicsInUse = false;\n\t\tthis.updateMnemonicVisibility(false);\n\t}\n\n\tprivate focusPrevious(): void {\n\n\t\tif (!this.focusedMenu || this.numMenusShown === 0) {\n\t\t\treturn;\n\t\t}\n\n\n\t\tlet newFocusedIndex = (this.focusedMenu.index - 1 + this.numMenusShown) % this.numMenusShown;\n\t\tif (this.focusedMenu.index === MenuBar.OVERFLOW_INDEX) {\n\t\t\tnewFocusedIndex = this.numMenusShown - 1;\n\t\t} else if (this.focusedMenu.index === 0 && this.hasOverflow) {\n\t\t\tnewFocusedIndex = MenuBar.OVERFLOW_INDEX;\n\t\t}\n\n\t\tif (newFocusedIndex === this.focusedMenu.index) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.isOpen) {\n\t\t\tthis.cleanupCustomMenu();\n\t\t\tthis.showCustomMenu(newFocusedIndex);\n\t\t} else if (this.isFocused) {\n\t\t\tthis.focusedMenu.index = newFocusedIndex;\n\t\t\tif (newFocusedIndex === MenuBar.OVERFLOW_INDEX) {\n\t\t\t\tthis.overflowMenu.buttonElement.focus();\n\t\t\t} else {\n\t\t\t\tthis.menus[newFocusedIndex].buttonElement?.focus();\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate focusNext(): void {\n\t\tif (!this.focusedMenu || this.numMenusShown === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet newFocusedIndex = (this.focusedMenu.index + 1) % this.numMenusShown;\n\t\tif (this.focusedMenu.index === MenuBar.OVERFLOW_INDEX) {\n\t\t\tnewFocusedIndex = 0;\n\t\t} else if (this.focusedMenu.index === this.numMenusShown - 1) {\n\t\t\tnewFocusedIndex = MenuBar.OVERFLOW_INDEX;\n\t\t}\n\n\t\tif (newFocusedIndex === this.focusedMenu.index) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.isOpen) {\n\t\t\tthis.cleanupCustomMenu();\n\t\t\tthis.showCustomMenu(newFocusedIndex);\n\t\t} else if (this.isFocused) {\n\t\t\tthis.focusedMenu.index = newFocusedIndex;\n\t\t\tif (newFocusedIndex === MenuBar.OVERFLOW_INDEX) {\n\t\t\t\tthis.overflowMenu.buttonElement.focus();\n\t\t\t} else {\n\t\t\t\tthis.menus[newFocusedIndex].buttonElement?.focus();\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate updateMnemonicVisibility(visible: boolean): void {\n\t\tif (this.menus) {\n\t\t\tthis.menus.forEach(menuBarMenu => {\n\t\t\t\tif (menuBarMenu.titleElement && menuBarMenu.titleElement.children.length) {\n\t\t\t\t\tconst child = menuBarMenu.titleElement.children.item(0) as HTMLElement;\n\t\t\t\t\tif (child) {\n\t\t\t\t\t\tchild.style.textDecoration = (this.options.alwaysOnMnemonics || visible) ? 'underline' : '';\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate get mnemonicsInUse(): boolean {\n\t\treturn this._mnemonicsInUse;\n\t}\n\n\tprivate set mnemonicsInUse(value: boolean) {\n\t\tthis._mnemonicsInUse = value;\n\t}\n\n\tprivate get shouldAltKeyFocus(): boolean {\n\t\tif (isMacintosh) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (!this.options.disableAltFocus) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (this.options.visibility === 'toggle') {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tpublic get onVisibilityChange(): Event {\n\t\treturn this._onVisibilityChange.event;\n\t}\n\n\tpublic get onFocusStateChange(): Event {\n\t\treturn this._onFocusStateChange.event;\n\t}\n\n\tprivate onMenuTriggered(menuIndex: number, clicked: boolean) {\n\t\tif (this.isOpen) {\n\t\t\tif (this.isCurrentMenu(menuIndex)) {\n\t\t\t\tthis.setUnfocusedState();\n\t\t\t} else {\n\t\t\t\tthis.cleanupCustomMenu();\n\t\t\t\tthis.showCustomMenu(menuIndex, this.openedViaKeyboard);\n\t\t\t}\n\t\t} else {\n\t\t\tthis.focusedMenu = { index: menuIndex };\n\t\t\tthis.openedViaKeyboard = !clicked;\n\t\t\tthis.focusState = MenubarState.OPEN;\n\t\t}\n\t}\n\n\tprivate onModifierKeyToggled(modifierKeyStatus: DOM.IModifierKeyStatus): void {\n\t\tconst allModifiersReleased = !modifierKeyStatus.altKey && !modifierKeyStatus.ctrlKey && !modifierKeyStatus.shiftKey && !modifierKeyStatus.metaKey;\n\n\t\tif (this.options.visibility === 'hidden') {\n\t\t\treturn;\n\t\t}\n\n\t\t// Prevent alt-key default if the menu is not hidden and we use alt to focus\n\t\tif (modifierKeyStatus.event && this.shouldAltKeyFocus) {\n\t\t\tif (ScanCodeUtils.toEnum(modifierKeyStatus.event.code) === ScanCode.AltLeft) {\n\t\t\t\tmodifierKeyStatus.event.preventDefault();\n\t\t\t}\n\t\t}\n\n\t\t// Alt key pressed while menu is focused. This should return focus away from the menubar\n\t\tif (this.isFocused && modifierKeyStatus.lastKeyPressed === 'alt' && modifierKeyStatus.altKey) {\n\t\t\tthis.setUnfocusedState();\n\t\t\tthis.mnemonicsInUse = false;\n\t\t\tthis.awaitingAltRelease = true;\n\t\t}\n\n\t\t// Clean alt key press and release\n\t\tif (allModifiersReleased && modifierKeyStatus.lastKeyPressed === 'alt' && modifierKeyStatus.lastKeyReleased === 'alt') {\n\t\t\tif (!this.awaitingAltRelease) {\n\t\t\t\tif (!this.isFocused && this.shouldAltKeyFocus) {\n\t\t\t\t\tthis.mnemonicsInUse = true;\n\t\t\t\t\tthis.focusedMenu = { index: this.numMenusShown > 0 ? 0 : MenuBar.OVERFLOW_INDEX };\n\t\t\t\t\tthis.focusState = MenubarState.FOCUSED;\n\t\t\t\t} else if (!this.isOpen) {\n\t\t\t\t\tthis.setUnfocusedState();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Alt key released\n\t\tif (!modifierKeyStatus.altKey && modifierKeyStatus.lastKeyReleased === 'alt') {\n\t\t\tthis.awaitingAltRelease = false;\n\t\t}\n\n\t\tif (this.options.enableMnemonics && this.menus && !this.isOpen) {\n\t\t\tthis.updateMnemonicVisibility((!this.awaitingAltRelease && modifierKeyStatus.altKey) || this.mnemonicsInUse);\n\t\t}\n\t}\n\n\tprivate isCurrentMenu(menuIndex: number): boolean {\n\t\tif (!this.focusedMenu) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn this.focusedMenu.index === menuIndex;\n\t}\n\n\tprivate cleanupCustomMenu(): void {\n\t\tif (this.focusedMenu) {\n\t\t\t// Remove focus from the menus first\n\t\t\tif (this.focusedMenu.index === MenuBar.OVERFLOW_INDEX) {\n\t\t\t\tthis.overflowMenu.buttonElement.focus();\n\t\t\t} else {\n\t\t\t\tthis.menus[this.focusedMenu.index].buttonElement?.focus();\n\t\t\t}\n\n\t\t\tif (this.focusedMenu.holder) {\n\t\t\t\tthis.focusedMenu.holder.parentElement?.classList.remove('open');\n\n\t\t\t\tthis.focusedMenu.holder.remove();\n\t\t\t}\n\n\t\t\tthis.focusedMenu.widget?.dispose();\n\n\t\t\tthis.focusedMenu = { index: this.focusedMenu.index };\n\t\t}\n\t\tthis.menuDisposables.clear();\n\t}\n\n\tprivate showCustomMenu(menuIndex: number, selectFirst = true): void {\n\t\tconst actualMenuIndex = menuIndex >= this.numMenusShown ? MenuBar.OVERFLOW_INDEX : menuIndex;\n\t\tconst customMenu = actualMenuIndex === MenuBar.OVERFLOW_INDEX ? this.overflowMenu : this.menus[actualMenuIndex];\n\n\t\tif (!customMenu.actions || !customMenu.buttonElement || !customMenu.titleElement) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst menuHolder = $('div.menubar-menu-items-holder', { 'title': '' });\n\n\t\tcustomMenu.buttonElement.classList.add('open');\n\n\t\tconst titleBoundingRect = customMenu.titleElement.getBoundingClientRect();\n\t\tconst titleBoundingRectZoom = DOM.getDomNodeZoomLevel(customMenu.titleElement);\n\n\t\tif (this.options.compactMode === Direction.Right) {\n\t\t\tmenuHolder.style.top = `${titleBoundingRect.top}px`;\n\t\t\tmenuHolder.style.left = `${titleBoundingRect.left + this.container.clientWidth}px`;\n\t\t} else if (this.options.compactMode === Direction.Left) {\n\t\t\tmenuHolder.style.top = `${titleBoundingRect.top}px`;\n\t\t\tmenuHolder.style.right = `${this.container.clientWidth}px`;\n\t\t\tmenuHolder.style.left = 'auto';\n\t\t} else {\n\t\t\tmenuHolder.style.top = `${titleBoundingRect.bottom * titleBoundingRectZoom}px`;\n\t\t\tmenuHolder.style.left = `${titleBoundingRect.left * titleBoundingRectZoom}px`;\n\t\t}\n\n\t\tcustomMenu.buttonElement.appendChild(menuHolder);\n\n\t\tconst menuOptions: IMenuOptions = {\n\t\t\tgetKeyBinding: this.options.getKeybinding,\n\t\t\tactionRunner: this.actionRunner,\n\t\t\tenableMnemonics: this.options.alwaysOnMnemonics || (this.mnemonicsInUse && this.options.enableMnemonics),\n\t\t\tariaLabel: customMenu.buttonElement.getAttribute('aria-label') ?? undefined,\n\t\t\texpandDirection: this.isCompact ? this.options.compactMode : Direction.Right,\n\t\t\tuseEventAsContext: true\n\t\t};\n\n\t\tconst menuWidget = this.menuDisposables.add(new Menu(menuHolder, customMenu.actions, menuOptions, this.menuStyle));\n\t\tthis.menuDisposables.add(menuWidget.onDidCancel(() => {\n\t\t\tthis.focusState = MenubarState.FOCUSED;\n\t\t}));\n\n\t\tif (actualMenuIndex !== menuIndex) {\n\t\t\tmenuWidget.trigger(menuIndex - this.numMenusShown);\n\t\t} else {\n\t\t\tmenuWidget.focus(selectFirst);\n\t\t}\n\n\t\tthis.focusedMenu = {\n\t\t\tindex: actualMenuIndex,\n\t\t\tholder: menuHolder,\n\t\t\twidget: menuWidget\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 { $, append, clearNode, createStyleSheet, getContentHeight, getContentWidth } from 'vs/base/browser/dom';\nimport { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate';\nimport { setupCustomHover } from 'vs/base/browser/ui/iconLabel/iconLabelHover';\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, ITableContextMenuEvent, ITableEvent, ITableGestureEvent, ITableMouseEvent, ITableRenderer, ITableTouchEvent, 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\t\tthis._register(setupCustomHover(getDefaultHoverDelegate('mouse'), this.element, column.tooltip));\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 onMouseClick(): Event> { return this.list.onMouseClick; }\n\tget onMouseDblClick(): Event> { return this.list.onMouseDblClick; }\n\tget onMouseMiddleClick(): Event> { return this.list.onMouseMiddleClick; }\n\tget onPointer(): Event> { return this.list.onPointer; }\n\tget onMouseUp(): Event> { return this.list.onMouseUp; }\n\tget onMouseDown(): Event> { return this.list.onMouseDown; }\n\tget onMouseOver(): Event> { return this.list.onMouseOver; }\n\tget onMouseMove(): Event> { return this.list.onMouseMove; }\n\tget onMouseOut(): Event> { return this.list.onMouseOut; }\n\tget onTouchStart(): Event> { return this.list.onTouchStart; }\n\tget onTap(): Event> { return this.list.onTap; }\n\tget onContextMenu(): Event> { return this.list.onContextMenu; }\n\n\tget onDidFocus(): Event { return this.list.onDidFocus; }\n\tget onDidBlur(): Event { return this.list.onDidBlur; }\n\n\tget scrollTop(): number { return this.list.scrollTop; }\n\tset scrollTop(scrollTop: number) { this.list.scrollTop = scrollTop; }\n\tget scrollLeft(): number { return this.list.scrollLeft; }\n\tset scrollLeft(scrollLeft: number) { this.list.scrollLeft = scrollLeft; }\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\trerender(): void {\n\t\tthis.list.rerender();\n\t}\n\n\trow(index: number): TRow {\n\t\treturn this.list.element(index);\n\t}\n\n\tindexOf(element: TRow): number {\n\t\treturn this.list.indexOf(element);\n\t}\n\n\tget length(): number {\n\t\treturn this.list.length;\n\t}\n\n\tgetHTMLElement(): HTMLElement {\n\t\treturn this.domNode;\n\t}\n\n\tlayout(height?: number, width?: number): void {\n\t\theight = height ?? getContentHeight(this.domNode);\n\t\twidth = width ?? getContentWidth(this.domNode);\n\n\t\tthis.cachedWidth = width;\n\t\tthis.cachedHeight = height;\n\t\tthis.splitview.layout(width);\n\n\t\tconst listHeight = height - this.virtualDelegate.headerRowHeight;\n\t\tthis.list.getHTMLElement().style.height = `${listHeight}px`;\n\t\tthis.list.layout(listHeight, width);\n\t}\n\n\ttriggerTypeNavigation(): void {\n\t\tthis.list.triggerTypeNavigation();\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\tdomFocus(): void {\n\t\tthis.list.domFocus();\n\t}\n\n\tsetAnchor(index: number | undefined): void {\n\t\tthis.list.setAnchor(index);\n\t}\n\n\tgetAnchor(): number | undefined {\n\t\treturn this.list.getAnchor();\n\t}\n\n\tgetSelectedElements(): TRow[] {\n\t\treturn this.list.getSelectedElements();\n\t}\n\n\tsetSelection(indexes: number[], browserEvent?: UIEvent): void {\n\t\tthis.list.setSelection(indexes, browserEvent);\n\t}\n\n\tgetSelection(): number[] {\n\t\treturn this.list.getSelection();\n\t}\n\n\tsetFocus(indexes: number[], browserEvent?: UIEvent): void {\n\t\tthis.list.setFocus(indexes, browserEvent);\n\t}\n\n\tfocusNext(n = 1, loop = false, browserEvent?: UIEvent): void {\n\t\tthis.list.focusNext(n, loop, browserEvent);\n\t}\n\n\tfocusPrevious(n = 1, loop = false, browserEvent?: UIEvent): void {\n\t\tthis.list.focusPrevious(n, loop, browserEvent);\n\t}\n\n\tfocusNextPage(browserEvent?: UIEvent): Promise {\n\t\treturn this.list.focusNextPage(browserEvent);\n\t}\n\n\tfocusPreviousPage(browserEvent?: UIEvent): Promise {\n\t\treturn this.list.focusPreviousPage(browserEvent);\n\t}\n\n\tfocusFirst(browserEvent?: UIEvent): void {\n\t\tthis.list.focusFirst(browserEvent);\n\t}\n\n\tfocusLast(browserEvent?: UIEvent): void {\n\t\tthis.list.focusLast(browserEvent);\n\t}\n\n\tgetFocus(): number[] {\n\t\treturn this.list.getFocus();\n\t}\n\n\tgetFocusedElements(): TRow[] {\n\t\treturn this.list.getFocusedElements();\n\t}\n\n\tgetRelativeTop(index: number): number | null {\n\t\treturn this.list.getRelativeTop(index);\n\t}\n\n\treveal(index: number, relativeTop?: number): void {\n\t\tthis.list.reveal(index, relativeTop);\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 { BaseActionViewItem, IActionViewItemOptions } from 'vs/base/browser/ui/actionbar/actionViewItems';\nimport { Widget } from 'vs/base/browser/ui/widget';\nimport { IAction } from 'vs/base/common/actions';\nimport { Codicon } from 'vs/base/common/codicons';\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 { isActiveElement, $, addDisposableListener, EventType } from 'vs/base/browser/dom';\nimport { ICustomHover, setupCustomHover } from 'vs/base/browser/ui/iconLabel/iconLabelHover';\nimport { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate';\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}\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 ToggleActionViewItem extends BaseActionViewItem {\n\n\tprotected readonly toggle: Toggle;\n\n\tconstructor(context: any, action: IAction, options: IActionViewItemOptions) {\n\t\tsuper(context, action, options);\n\n\t\tthis.toggle = this._register(new Toggle({\n\t\t\tactionClassName: this._action.class,\n\t\t\tisChecked: !!this._action.checked,\n\t\t\ttitle: (this.options).keybinding ? `${this._action.label} (${(this.options).keybinding})` : this._action.label,\n\t\t\tnotFocusable: true,\n\t\t\tinputActiveOptionBackground: options.toggleStyles?.inputActiveOptionBackground,\n\t\t\tinputActiveOptionBorder: options.toggleStyles?.inputActiveOptionBorder,\n\t\t\tinputActiveOptionForeground: options.toggleStyles?.inputActiveOptionForeground,\n\t\t}));\n\t\tthis._register(this.toggle.onChange(() => this._action.checked = !!this.toggle && this.toggle.checked));\n\t}\n\n\toverride render(container: HTMLElement): void {\n\t\tthis.element = container;\n\t\tthis.element.appendChild(this.toggle.domNode);\n\t}\n\n\tprotected override updateEnabled(): void {\n\t\tif (this.toggle) {\n\t\t\tif (this.isEnabled()) {\n\t\t\t\tthis.toggle.enable();\n\t\t\t} else {\n\t\t\t\tthis.toggle.disable();\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected override updateChecked(): void {\n\t\tthis.toggle.checked = !!this._action.checked;\n\t}\n\n\toverride focus(): void {\n\t\tthis.toggle.domNode.tabIndex = 0;\n\t\tthis.toggle.focus();\n\t}\n\n\toverride blur(): void {\n\t\tthis.toggle.domNode.tabIndex = -1;\n\t\tthis.toggle.domNode.blur();\n\t}\n\n\toverride setFocusable(focusable: boolean): void {\n\t\tthis.toggle.domNode.tabIndex = focusable ? 0 : -1;\n\t}\n\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: ICustomHover;\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(setupCustomHover(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\tsetIcon(icon: ThemeIcon | undefined): void {\n\t\tif (this._icon) {\n\t\t\tthis.domNode.classList.remove(...ThemeIcon.asClassNameArray(this._icon));\n\t\t}\n\t\tthis._icon = icon;\n\t\tif (this._icon) {\n\t\t\tthis.domNode.classList.add(...ThemeIcon.asClassNameArray(this._icon));\n\t\t}\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\tsetTitle(newTitle: string): void {\n\t\tthis._hover.update(newTitle);\n\t\tthis.domNode.setAttribute('aria-label', newTitle);\n\t}\n}\n\nexport class Checkbox extends Widget {\n\n\tprivate readonly _onChange = this._register(new Emitter());\n\treadonly onChange: Event = this._onChange.event;\n\n\tprivate checkbox: Toggle;\n\tprivate styles: ICheckboxStyles;\n\n\treadonly domNode: HTMLElement;\n\n\tconstructor(private title: string, private isChecked: boolean, styles: ICheckboxStyles) {\n\t\tsuper();\n\n\t\tthis.checkbox = new Toggle({ title: this.title, isChecked: this.isChecked, icon: Codicon.check, actionClassName: 'monaco-checkbox', ...unthemedToggleStyles });\n\n\t\tthis.domNode = this.checkbox.domNode;\n\n\t\tthis.styles = styles;\n\n\t\tthis.applyStyles();\n\n\t\tthis._register(this.checkbox.onChange(keyboard => {\n\t\t\tthis.applyStyles();\n\t\t\tthis._onChange.fire(keyboard);\n\t\t}));\n\t}\n\n\tget checked(): boolean {\n\t\treturn this.checkbox.checked;\n\t}\n\n\tset checked(newIsChecked: boolean) {\n\t\tthis.checkbox.checked = newIsChecked;\n\n\t\tthis.applyStyles();\n\t}\n\n\tfocus(): void {\n\t\tthis.domNode.focus();\n\t}\n\n\thasFocus(): boolean {\n\t\treturn isActiveElement(this.domNode);\n\t}\n\n\tenable(): void {\n\t\tthis.checkbox.enable();\n\t}\n\n\tdisable(): void {\n\t\tthis.checkbox.disable();\n\t}\n\n\tprotected applyStyles(): void {\n\t\tthis.domNode.style.color = this.styles.checkboxForeground || '';\n\t\tthis.domNode.style.backgroundColor = this.styles.checkboxBackground || '';\n\t\tthis.domNode.style.borderColor = this.styles.checkboxBorder || '';\n\t}\n}\n\nexport interface ICheckboxActionViewItemOptions extends IActionViewItemOptions {\n\tcheckboxStyles: ICheckboxStyles;\n}\n\nexport class CheckboxActionViewItem extends BaseActionViewItem {\n\n\tprotected readonly toggle: Checkbox;\n\tprivate cssClass?: string;\n\n\tconstructor(context: any, action: IAction, options: ICheckboxActionViewItemOptions) {\n\t\tsuper(context, action, options);\n\n\t\tthis.toggle = this._register(new Checkbox(this._action.label, !!this._action.checked, options.checkboxStyles));\n\t\tthis._register(this.toggle.onChange(() => this.onChange()));\n\t}\n\n\toverride render(container: HTMLElement): void {\n\t\tthis.element = container;\n\t\tthis.element.classList.add('checkbox-action-item');\n\t\tthis.element.appendChild(this.toggle.domNode);\n\t\tif ((this.options).label && this._action.label) {\n\t\t\tconst label = this.element.appendChild($('span.checkbox-label', undefined, this._action.label));\n\t\t\tthis._register(addDisposableListener(label, EventType.CLICK, (e: MouseEvent) => {\n\t\t\t\tthis.toggle.checked = !this.toggle.checked;\n\t\t\t\te.stopPropagation();\n\t\t\t\te.preventDefault();\n\t\t\t\tthis.onChange();\n\t\t\t}));\n\t\t}\n\n\t\tthis.updateEnabled();\n\t\tthis.updateClass();\n\t\tthis.updateChecked();\n\t}\n\n\tprivate onChange(): void {\n\t\tthis._action.checked = !!this.toggle && this.toggle.checked;\n\t\tthis.actionRunner.run(this._action, this._context);\n\t}\n\n\tprotected override updateEnabled(): void {\n\t\tif (this.isEnabled()) {\n\t\t\tthis.toggle.enable();\n\t\t} else {\n\t\t\tthis.toggle.disable();\n\t\t}\n\t\tif (this.action.enabled) {\n\t\t\tthis.element?.classList.remove('disabled');\n\t\t} else {\n\t\t\tthis.element?.classList.add('disabled');\n\t\t}\n\t}\n\n\tprotected override updateChecked(): void {\n\t\tthis.toggle.checked = !!this._action.checked;\n\t}\n\n\tprotected override updateClass(): void {\n\t\tif (this.cssClass) {\n\t\t\tthis.toggle.domNode.classList.remove(...this.cssClass.split(' '));\n\t\t}\n\t\tthis.cssClass = this.getClass();\n\t\tif (this.cssClass) {\n\t\t\tthis.toggle.domNode.classList.add(...this.cssClass.split(' '));\n\t\t}\n\t}\n\n\toverride focus(): void {\n\t\tthis.toggle.domNode.tabIndex = 0;\n\t\tthis.toggle.focus();\n\t}\n\n\toverride blur(): void {\n\t\tthis.toggle.domNode.tabIndex = -1;\n\t\tthis.toggle.domNode.blur();\n\t}\n\n\toverride setFocusable(focusable: boolean): void {\n\t\tthis.toggle.domNode.tabIndex = focusable ? 0 : -1;\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 { 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}\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\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\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\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 * 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';\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\tstatic readonly OPTION_CHANGE: string = 'optionChange';\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 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\tpublic readonly onInput: Event = this._onInput.event;\n\n\tprivate readonly _onKeyUp = this._register(new Emitter());\n\tpublic readonly onKeyUp: Event = this._onKeyUp.event;\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\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\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\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\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 isImeSessionInProgress(): boolean {\n\t\treturn this.imeSessionInProgress;\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 clear(): void {\n\t\tthis.clearValidation();\n\t\tthis.setValue('');\n\t\tthis.focus();\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 onSearchSubmit(): void {\n\t\tthis.inputBox.addToHistory();\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\tpublic focusOnRegex(): void {\n\t\tthis.regex?.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\tprivate clearValidation(): 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, IMessage as InputBoxMessage } 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';\n\n\nexport interface IReplaceInputOptions {\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 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\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\tstatic readonly OPTION_CHANGE: string = 'optionChange';\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\tpublic readonly onMouseDown: Event = this._onMouseDown.event;\n\n\tprivate readonly _onInput = this._register(new Emitter());\n\tpublic readonly onInput: Event = this._onInput.event;\n\n\tprivate readonly _onKeyUp = this._register(new Emitter());\n\tpublic readonly onKeyUp: Event = this._onKeyUp.event;\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 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 clear(): void {\n\t\tthis.clearValidation();\n\t\tthis.setValue('');\n\t\tthis.focus();\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 onSearchSubmit(): void {\n\t\tthis.inputBox.addToHistory();\n\t}\n\n\tprotected applyStyles(): void {\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\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\tprivate clearValidation(): void {\n\t\tthis.inputBox?.hideMessage();\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 { 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/iconLabel/iconHoverDelegate';\nimport { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate';\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 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(getDefaultHoverDelegate('element', true));\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\tset context(context: unknown) {\n\t\tthis.actionBar.context = context;\n\t\tthis.toggleMenuActionViewItem?.setActionContext(context);\n\t\tfor (const actionViewItem of this.submenuActionViewItems) {\n\t\t\tactionViewItem.setActionContext(context);\n\t\t}\n\t}\n\n\tgetElement(): HTMLElement {\n\t\treturn this.element;\n\t}\n\n\tfocus(): void {\n\t\tthis.actionBar.focus();\n\t}\n\n\tgetItemsWidth(): number {\n\t\tlet itemsWidth = 0;\n\t\tfor (let i = 0; i < this.actionBar.length(); i++) {\n\t\t\titemsWidth += this.actionBar.getWidth(i);\n\t\t}\n\t\treturn itemsWidth;\n\t}\n\n\tgetItemAction(indexOrElement: number | HTMLElement) {\n\t\treturn this.actionBar.getAction(indexOrElement);\n\t}\n\n\tgetItemWidth(index: number): number {\n\t\treturn this.actionBar.getWidth(index);\n\t}\n\n\tgetItemsLength(): number {\n\t\treturn this.actionBar.length();\n\t}\n\n\tsetAriaLabel(label: string): void {\n\t\tthis.actionBar.setAriaLabel(label);\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\tisEmpty(): boolean {\n\t\treturn this.actionBar.isEmpty();\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, isActiveElement, 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, ITreeNavigator, ITreeNode, ITreeRenderer, TreeDragOverBubble, TreeError, TreeFilterResult, TreeMouseEventTarget, TreeVisibility } from 'vs/base/browser/ui/tree/tree';\nimport { Action } from 'vs/base/common/actions';\nimport { distinct, equals, firstOrDefault, 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';\n\nclass TreeElementsDragAndDropData extends ElementsDragAndDropData {\n\n\toverride set context(context: TContext | undefined) {\n\t\tthis.data.context = context;\n\t}\n\n\toverride get context(): TContext | undefined {\n\t\treturn this.data.context;\n\t}\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 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 interface IAbstractTreeViewState {\n\treadonly focus: Iterable;\n\treadonly selection: Iterable;\n\treadonly expanded: { [id: string]: 1 | 0 };\n\treadonly scrollTop: number;\n}\n\nexport class AbstractTreeViewState implements IAbstractTreeViewState {\n\tpublic readonly focus: Set;\n\tpublic readonly selection: Set;\n\tpublic readonly expanded: { [id: string]: 1 | 0 };\n\tpublic scrollTop: number;\n\n\tpublic static lift(state: IAbstractTreeViewState) {\n\t\treturn state instanceof AbstractTreeViewState ? state : new AbstractTreeViewState(state);\n\t}\n\n\tpublic static empty(scrollTop = 0) {\n\t\treturn new AbstractTreeViewState({\n\t\t\tfocus: [],\n\t\t\tselection: [],\n\t\t\texpanded: Object.create(null),\n\t\t\tscrollTop,\n\t\t});\n\t}\n\n\tprotected constructor(state: IAbstractTreeViewState) {\n\t\tthis.focus = new Set(state.focus);\n\t\tthis.selection = new Set(state.selection);\n\t\tif (state.expanded instanceof Array) { // old format\n\t\t\tthis.expanded = Object.create(null);\n\t\t\tfor (const id of state.expanded as string[]) {\n\t\t\t\tthis.expanded[id] = 1;\n\t\t\t}\n\t\t} else {\n\t\t\tthis.expanded = state.expanded;\n\t\t}\n\t\tthis.expanded = state.expanded;\n\t\tthis.scrollTop = state.scrollTop;\n\t}\n\n\tpublic toJSON(): IAbstractTreeViewState {\n\t\treturn {\n\t\t\tfocus: Array.from(this.focus),\n\t\t\tselection: Array.from(this.selection),\n\t\t\texpanded: this.expanded,\n\t\t\tscrollTop: this.scrollTop,\n\t\t};\n\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\tset pattern(pattern: string) {\n\t\tthis._pattern = pattern;\n\t\tthis._lowercasePattern = pattern.toLowerCase();\n\t}\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}\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\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\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\tget value(): string {\n\t\treturn this.findInput.inputBox.value;\n\t}\n\n\tset value(value: string) {\n\t\tthis.findInput.inputBox.value = value;\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 onDidDisable = this._onDidDisable.event;\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\tthis.modeToggle = this._register(new ModeToggle({ ...styles.toggleStyles, isChecked: mode === TreeFindMode.Filter }));\n\t\tthis.matchTypeToggle = this._register(new FuzzyToggle({ ...styles.toggleStyles, isChecked: matchType === TreeFindMatchType.Fuzzy }));\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\tgetHistory(): string[] {\n\t\treturn this.findInput.inputBox.getHistory();\n\t}\n\n\tfocus() {\n\t\tthis.findInput.focus();\n\t}\n\n\tselect() {\n\t\tthis.findInput.select();\n\n\t\t// Reposition to last in history\n\t\tthis.findInput.inputBox.addToHistory(true);\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\tprivate previousPattern = '';\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\treadonly onDidChangePattern = this._onDidChangePattern.event;\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\topen(): void {\n\t\tif (this.widget) {\n\t\t\tthis.widget.focus();\n\t\t\tthis.widget.select();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.widget = new FindWidget(this.view.getHTMLElement(), this.tree, this.contextViewProvider, this.mode, this.matchType, { ...this.options, history: this._history });\n\t\tthis.enabledDisposables.add(this.widget);\n\n\t\tthis.widget.onDidChangeValue(this.onDidChangeValue, this, this.enabledDisposables);\n\t\tthis.widget.onDidChangeMode(mode => this.mode = mode, undefined, this.enabledDisposables);\n\t\tthis.widget.onDidChangeMatchType(matchType => this.matchType = matchType, undefined, this.enabledDisposables);\n\t\tthis.widget.onDidDisable(this.close, this, this.enabledDisposables);\n\n\t\tthis.widget.layout(this.width);\n\t\tthis.widget.focus();\n\n\t\tthis.widget.value = this.previousPattern;\n\t\tthis.widget.select();\n\n\t\tthis._onDidChangeOpenState.fire(true);\n\t}\n\n\tclose(): void {\n\t\tif (!this.widget) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._history = this.widget.getHistory();\n\t\tthis.widget = undefined;\n\n\t\tthis.enabledDisposables.clear();\n\n\t\tthis.previousPattern = this.pattern;\n\t\tthis.onDidChangeValue('');\n\t\tthis.tree.domFocus();\n\n\t\tthis._onDidChangeOpenState.fire(false);\n\t}\n\n\tprivate onDidChangeValue(pattern: string): void {\n\t\tthis._pattern = pattern;\n\t\tthis._onDidChangePattern.fire(pattern);\n\n\t\tthis.filter.pattern = pattern;\n\t\tthis.tree.refilter();\n\n\t\tif (pattern) {\n\t\t\tthis.tree.focusNext(0, true, undefined, node => !FuzzyScore.isDefault(node.filterData as any as FuzzyScore));\n\t\t}\n\n\t\tconst focus = this.tree.getFocus();\n\n\t\tif (focus.length > 0) {\n\t\t\tconst element = focus[0];\n\n\t\t\tif (this.tree.getRelativeTop(element) === null) {\n\t\t\t\tthis.tree.reveal(element, 0.5);\n\t\t\t}\n\t\t}\n\n\t\tthis.render();\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\tget count(): number {\n\t\treturn this._widget.count;\n\t}\n\n\tgetNode(node: ITreeNode): StickyScrollNode | undefined {\n\t\treturn this._widget.getNode(node);\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\tgetFocus(): T | undefined {\n\t\treturn this._widget.getFocus();\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 _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\tget count(): number {\n\t\treturn this._previousState?.count ?? 0;\n\t}\n\n\tgetNode(node: ITreeNode): StickyScrollNode | undefined {\n\t\treturn this._previousState?.stickyNodes.find(stickyNode => stickyNode.node === node);\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\t\tstickyElement.style.height = `${stickyNode.height}px`;\n\t\tstickyElement.style.lineHeight = `${stickyNode.height}px`;\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\tthis.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\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): void {\n\t\tif (!this.accessibilityProvider) {\n\t\t\treturn;\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\tif (ariaLabel) {\n\t\t\tcontainer.setAttribute('aria-label', ariaLabel);\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\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\tgetFocus(): T | undefined {\n\t\treturn this.stickyScrollFocus.getFocus();\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\tgetFocus(): T | undefined {\n\t\tif (!this.state || this.focusedIndex === -1) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn this.state.stickyNodes[this.focusedIndex].node.element;\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\telement.classList.toggle('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\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\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}\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 typeNavigationEnabled?: 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 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 (expandOnlyOnTwistieClick && 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 const enum AbstractTreePart {\n\tTree,\n\tStickyScroll,\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\n\tget onMouseClick(): Event> { return Event.map(this.view.onMouseClick, asTreeMouseEvent); }\n\tget onMouseDblClick(): Event> { return Event.filter(Event.map(this.view.onMouseDblClick, asTreeMouseEvent), e => e.target !== TreeMouseEventTarget.Filter); }\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 onTap(): Event> { return Event.map(this.view.onTap, asTreeMouseEvent); }\n\tget onPointer(): Event> { return Event.map(this.view.onPointer, asTreeMouseEvent); }\n\n\tget onKeyDown(): Event { return this.view.onKeyDown; }\n\tget onKeyUp(): Event { return this.view.onKeyUp; }\n\tget onKeyPress(): Event { return this.view.onKeyPress; }\n\n\tget onDidFocus(): Event { return this.view.onDidFocus; }\n\tget onDidBlur(): Event { return this.view.onDidBlur; }\n\n\tget onDidChangeModel(): Event { return Event.signal(this.model.onDidSplice); }\n\tget onDidChangeCollapseState(): Event> { return this.model.onDidChangeCollapseState; }\n\tget onDidChangeRenderNodeCount(): Event> { return this.model.onDidChangeRenderNodeCount; }\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 onDidChangeFindPattern(): Event { return this.findController ? this.findController.onDidChangePattern : Event.None; }\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\treadonly onDidUpdateOptions: Event> = this._onDidUpdateOptions.event;\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\tupdateWidth(element: TRef): void {\n\t\tconst index = this.model.getListIndex(element);\n\n\t\tif (index === -1) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.view.updateWidth(index);\n\t}\n\n\t// Widget\n\n\tgetHTMLElement(): HTMLElement {\n\t\treturn this.view.getHTMLElement();\n\t}\n\n\tget contentHeight(): number {\n\t\treturn this.view.contentHeight;\n\t}\n\n\tget contentWidth(): number {\n\t\treturn this.view.contentWidth;\n\t}\n\n\tget onDidChangeContentHeight(): Event {\n\t\treturn this.view.onDidChangeContentHeight;\n\t}\n\n\tget onDidChangeContentWidth(): Event {\n\t\treturn this.view.onDidChangeContentWidth;\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 scrollLeft(): number {\n\t\treturn this.view.scrollLeft;\n\t}\n\n\tset scrollLeft(scrollLeft: number) {\n\t\tthis.view.scrollLeft = scrollLeft;\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 firstVisibleElement(): T | undefined {\n\t\tlet index = this.view.firstVisibleIndex;\n\n\t\tif (this.stickyScrollController) {\n\t\t\tindex += this.stickyScrollController.count;\n\t\t}\n\n\t\tif (index < 0 || index >= this.view.length) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst node = this.view.element(index);\n\t\treturn node.element;\n\t}\n\n\tget lastVisibleElement(): T {\n\t\tconst index = this.view.lastVisibleIndex;\n\t\tconst node = this.view.element(index);\n\t\treturn node.element;\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\tget selectionSize() {\n\t\treturn this.selection.getNodes().length;\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\tisDOMFocused(): boolean {\n\t\treturn isActiveElement(this.getHTMLElement());\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\tif (styles.listBackground) {\n\t\t\tcontent.push(`.monaco-list${suffix} .monaco-scrollable-element .monaco-tree-sticky-container { background-color: ${styles.listBackground}; }`);\n\t\t\tcontent.push(`.monaco-list${suffix} .monaco-scrollable-element .monaco-tree-sticky-container .monaco-tree-sticky-row { background-color: ${styles.listBackground}; }`);\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-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\texpandAll(): void {\n\t\tthis.model.setCollapsed(this.model.rootRef, false, true);\n\t}\n\n\tcollapseAll(): void {\n\t\tthis.model.setCollapsed(this.model.rootRef, true, true);\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\texpandTo(location: TRef): void {\n\t\tthis.model.expandTo(location);\n\t}\n\n\ttriggerTypeNavigation(): void {\n\t\tthis.view.triggerTypeNavigation();\n\t}\n\n\topenFind(): void {\n\t\tthis.findController?.open();\n\t}\n\n\tcloseFind(): void {\n\t\tthis.findController?.close();\n\t}\n\n\trefilter(): void {\n\t\tthis._onWillRefilter.fire(undefined);\n\t\tthis.model.refilter();\n\t}\n\n\tsetAnchor(element: TRef | undefined): void {\n\t\tif (typeof element === 'undefined') {\n\t\t\treturn this.view.setAnchor(undefined);\n\t\t}\n\n\t\tthis.eventBufferer.bufferEvents(() => {\n\t\t\tconst node = this.model.getNode(element);\n\t\t\tthis.anchor.set([node]);\n\n\t\t\tconst index = this.model.getListIndex(element);\n\n\t\t\tif (index > -1) {\n\t\t\t\tthis.view.setAnchor(index, true);\n\t\t\t}\n\t\t});\n\t}\n\n\tgetAnchor(): T | undefined {\n\t\treturn firstOrDefault(this.anchor.get(), undefined);\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 = (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 = (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 = (isKeyboardEvent(browserEvent) && browserEvent.altKey) ? undefined : this.focusNavigationFilter): Promise {\n\t\treturn this.view.focusNextPage(browserEvent, filter);\n\t}\n\n\tfocusPreviousPage(browserEvent?: UIEvent, filter = (isKeyboardEvent(browserEvent) && browserEvent.altKey) ? undefined : this.focusNavigationFilter): Promise {\n\t\treturn this.view.focusPreviousPage(browserEvent, filter, () => this.stickyScrollController?.height ?? 0);\n\t}\n\n\tfocusLast(browserEvent?: UIEvent, filter = (isKeyboardEvent(browserEvent) && browserEvent.altKey) ? undefined : this.focusNavigationFilter): void {\n\t\tthis.view.focusLast(browserEvent, filter);\n\t}\n\n\tfocusFirst(browserEvent?: UIEvent, filter = (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\tgetStickyScrollFocus(): T[] {\n\t\tconst focus = this.stickyScrollController?.getFocus();\n\t\treturn focus !== undefined ? [focus] : [];\n\t}\n\n\tgetFocusedPart(): AbstractTreePart {\n\t\treturn this.stickyScrollController?.focusedLast() ? AbstractTreePart.StickyScroll : AbstractTreePart.Tree;\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/**\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(location: TRef): number | null {\n\t\tconst index = this.model.getListIndex(location);\n\n\t\tif (index === -1) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst stickyScrollNode = this.stickyScrollController?.getNode(this.getNode(location));\n\t\treturn this.view.getRelativeTop(index, stickyScrollNode?.position ?? this.stickyScrollController?.height);\n\t}\n\n\tgetViewState(identityProvider = this.options.identityProvider): AbstractTreeViewState {\n\t\tif (!identityProvider) {\n\t\t\tthrow new TreeError(this._user, 'Can\\'t get tree view state without an identity provider');\n\t\t}\n\n\t\tconst getId = (element: T | null) => identityProvider.getId(element!).toString();\n\t\tconst state = AbstractTreeViewState.empty(this.scrollTop);\n\t\tfor (const focus of this.getFocus()) {\n\t\t\tstate.focus.add(getId(focus));\n\t\t}\n\t\tfor (const selection of this.getSelection()) {\n\t\t\tstate.selection.add(getId(selection));\n\t\t}\n\n\t\tconst root = this.model.getNode();\n\t\tconst queue = [root];\n\n\t\twhile (queue.length > 0) {\n\t\t\tconst node = queue.shift()!;\n\n\t\t\tif (node !== root && node.collapsible) {\n\t\t\t\tstate.expanded[getId(node.element)] = node.collapsed ? 0 : 1;\n\t\t\t}\n\n\t\t\tqueue.push(...node.children);\n\t\t}\n\n\t\treturn state;\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\tnavigate(start?: TRef): ITreeNavigator {\n\t\treturn new TreeNavigator(this.view, this.model, start);\n\t}\n\n\tdispose(): void {\n\t\tdispose(this.disposables);\n\t\tthis.stickyScrollController?.dispose();\n\t\tthis.view.dispose();\n\t}\n}\n\ninterface ITreeNavigatorView, TFilterData> {\n\treadonly length: number;\n\telement(index: number): ITreeNode;\n}\n\nclass TreeNavigator, TFilterData, TRef> implements ITreeNavigator {\n\n\tprivate index: number;\n\n\tconstructor(private view: ITreeNavigatorView, private model: ITreeModel, start?: TRef) {\n\t\tif (start) {\n\t\t\tthis.index = this.model.getListIndex(start);\n\t\t} else {\n\t\t\tthis.index = -1;\n\t\t}\n\t}\n\n\tcurrent(): T | null {\n\t\tif (this.index < 0 || this.index >= this.view.length) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this.view.element(this.index).element;\n\t}\n\n\tprevious(): T | null {\n\t\tthis.index--;\n\t\treturn this.current();\n\t}\n\n\tnext(): T | null {\n\t\tthis.index++;\n\t\treturn this.current();\n\t}\n\n\tfirst(): T | null {\n\t\tthis.index = 0;\n\t\treturn this.current();\n\t}\n\n\tlast(): T | null {\n\t\tthis.index = this.view.length - 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 { IIdentityProvider, IListVirtualDelegate } from 'vs/base/browser/ui/list/list';\nimport { AbstractTree, AbstractTreeViewState, 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, ITreeElement, ITreeModel, ITreeNode, ITreeRenderer, ITreeSorter, TreeError } from 'vs/base/browser/ui/tree/tree';\nimport { Iterable } from 'vs/base/common/iterator';\n\nexport interface IDataTreeOptions extends IAbstractTreeOptions {\n\treadonly sorter?: ITreeSorter;\n}\n\nexport class DataTree extends AbstractTree {\n\n\tprotected declare model: ObjectTreeModel;\n\tprivate input: TInput | undefined;\n\n\tprivate identityProvider: IIdentityProvider | undefined;\n\tprivate nodesByIdentity = new Map>();\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\t// Model\n\n\tgetInput(): TInput | undefined {\n\t\treturn this.input;\n\t}\n\n\tsetInput(input: TInput | undefined, viewState?: AbstractTreeViewState): void {\n\t\tif (viewState && !this.identityProvider) {\n\t\t\tthrow new TreeError(this.user, 'Can\\'t restore tree view state without an identity provider');\n\t\t}\n\n\t\tthis.input = input;\n\n\t\tif (!input) {\n\t\t\tthis.nodesByIdentity.clear();\n\t\t\tthis.model.setChildren(null, Iterable.empty());\n\t\t\treturn;\n\t\t}\n\n\t\tif (!viewState) {\n\t\t\tthis._refresh(input);\n\t\t\treturn;\n\t\t}\n\n\t\tconst focus: T[] = [];\n\t\tconst selection: T[] = [];\n\n\t\tconst isCollapsed = (element: T) => {\n\t\t\tconst id = this.identityProvider!.getId(element).toString();\n\t\t\treturn !viewState.expanded[id];\n\t\t};\n\n\t\tconst onDidCreateNode = (node: ITreeNode) => {\n\t\t\tconst id = this.identityProvider!.getId(node.element).toString();\n\n\t\t\tif (viewState.focus.has(id)) {\n\t\t\t\tfocus.push(node.element);\n\t\t\t}\n\n\t\t\tif (viewState.selection.has(id)) {\n\t\t\t\tselection.push(node.element);\n\t\t\t}\n\t\t};\n\n\t\tthis._refresh(input, isCollapsed, onDidCreateNode);\n\t\tthis.setFocus(focus);\n\t\tthis.setSelection(selection);\n\n\t\tif (viewState && typeof viewState.scrollTop === 'number') {\n\t\t\tthis.scrollTop = viewState.scrollTop;\n\t\t}\n\t}\n\n\tupdateChildren(element: TInput | T = this.input!): void {\n\t\tif (typeof this.input === 'undefined') {\n\t\t\tthrow new TreeError(this.user, 'Tree input not set');\n\t\t}\n\n\t\tlet isCollapsed: ((el: T) => boolean | undefined) | undefined;\n\n\t\tif (this.identityProvider) {\n\t\t\tisCollapsed = element => {\n\t\t\t\tconst id = this.identityProvider!.getId(element).toString();\n\t\t\t\tconst node = this.nodesByIdentity.get(id);\n\n\t\t\t\tif (!node) {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\n\t\t\t\treturn node.collapsed;\n\t\t\t};\n\t\t}\n\n\t\tthis._refresh(element, isCollapsed);\n\t}\n\n\tresort(element: T | TInput = this.input!, recursive = true): void {\n\t\tthis.model.resort((element === this.input ? null : element) as T, recursive);\n\t}\n\n\t// View\n\n\trefresh(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\t// Implementation\n\n\tprivate _refresh(element: TInput | T, isCollapsed?: (el: T) => boolean | undefined, onDidCreateNode?: (node: ITreeNode) => void): void {\n\t\tlet onDidDeleteNode: ((node: ITreeNode) => void) | undefined;\n\n\t\tif (this.identityProvider) {\n\t\t\tconst insertedElements = new Set();\n\n\t\t\tconst outerOnDidCreateNode = onDidCreateNode;\n\t\t\tonDidCreateNode = (node: ITreeNode) => {\n\t\t\t\tconst id = this.identityProvider!.getId(node.element).toString();\n\n\t\t\t\tinsertedElements.add(id);\n\t\t\t\tthis.nodesByIdentity.set(id, node);\n\n\t\t\t\touterOnDidCreateNode?.(node);\n\t\t\t};\n\n\t\t\tonDidDeleteNode = (node: ITreeNode) => {\n\t\t\t\tconst id = this.identityProvider!.getId(node.element).toString();\n\n\t\t\t\tif (!insertedElements.has(id)) {\n\t\t\t\t\tthis.nodesByIdentity.delete(id);\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\tthis.model.setChildren((element === this.input ? null : element) as T, this.iterate(element, isCollapsed).elements, { onDidCreateNode, onDidDeleteNode });\n\t}\n\n\tprivate iterate(element: TInput | T, isCollapsed?: (el: T) => boolean | undefined): { elements: Iterable>; size: number } {\n\t\tconst children = [...this.dataSource.getChildren(element)];\n\t\tconst elements = Iterable.map(children, element => {\n\t\t\tconst { elements: children, size } = this.iterate(element, isCollapsed);\n\t\t\tconst collapsible = this.dataSource.hasChildren ? this.dataSource.hasChildren(element) : undefined;\n\t\t\tconst collapsed = size === 0 ? undefined : (isCollapsed && isCollapsed(element));\n\n\t\t\treturn { element, children, collapsible, collapsed };\n\t\t});\n\n\t\treturn { elements, size: children.length };\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, ElementMapper, 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 * 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\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\tupdateElementHeight(element: T, height: number | undefined): void {\n\t\tthis.model.updateElementHeight(element, height);\n\t}\n\n\tresort(element: T | null, recursive = true): void {\n\t\tthis.model.resort(element, recursive);\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\n\t\tif (!this.modelProvider().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 (const stickyNode of stickyNodes) {\n\t\t\tconst compressedNode = this.modelProvider().getCompressedTreeNode(stickyNode.node.element);\n\n\t\t\tif (compressedNode.element) {\n\t\t\t\tif (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 = { ...lastStickyNode.node, children: [], element: compressedElement } as ITreeNode, TFilterData>;\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 compressionEnabled?: boolean;\n\treadonly elementMapper?: ElementMapper;\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, AbstractTreePart } 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, ITreeContextMenuEvent, 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\nfunction asTreeContextMenuEvent(e: ITreeContextMenuEvent | null>): ITreeContextMenuEvent {\n\treturn {\n\t\tbrowserEvent: e.browserEvent,\n\t\telement: e.element && e.element.element as T,\n\t\tanchor: e.anchor,\n\t\tisStickyScroll: e.isStickyScroll\n\t};\n}\n\nclass AsyncDataTreeElementsDragAndDropData extends ElementsDragAndDropData {\n\n\toverride set context(context: TContext | undefined) {\n\t\tthis.data.context = context;\n\t}\n\n\toverride get context(): TContext | undefined {\n\t\treturn this.data.context;\n\t}\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\n\tget onKeyDown(): Event { return this.tree.onKeyDown; }\n\tget onMouseClick(): Event> { return Event.map(this.tree.onMouseClick, asTreeMouseEvent); }\n\tget onMouseDblClick(): Event> { return Event.map(this.tree.onMouseDblClick, asTreeMouseEvent); }\n\tget onContextMenu(): Event> { return Event.map(this.tree.onContextMenu, asTreeContextMenuEvent); }\n\tget onTap(): Event> { return Event.map(this.tree.onTap, asTreeMouseEvent); }\n\tget onPointer(): Event> { return Event.map(this.tree.onPointer, asTreeMouseEvent); }\n\tget onDidFocus(): Event { return this.tree.onDidFocus; }\n\tget onDidBlur(): Event { return this.tree.onDidBlur; }\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 onDidUpdateOptions(): Event { return this.tree.onDidUpdateOptions; }\n\n\tget onDidChangeFindOpenState(): Event { return this.tree.onDidChangeFindOpenState; }\n\tget onDidChangeStickyScrollFocused(): Event { return this.tree.onDidChangeStickyScrollFocused; }\n\n\tget findMode(): TreeFindMode { return this.tree.findMode; }\n\tset findMode(mode: TreeFindMode) { this.tree.findMode = mode; }\n\treadonly onDidChangeFindMode: Event;\n\n\tget findMatchType(): TreeFindMatchType { return this.tree.findMatchType; }\n\tset findMatchType(matchType: TreeFindMatchType) { this.tree.findMatchType = matchType; }\n\treadonly onDidChangeFindMatchType: Event;\n\n\tget expandOnlyOnTwistieClick(): boolean | ((e: T) => boolean) {\n\t\tif (typeof this.tree.expandOnlyOnTwistieClick === 'boolean') {\n\t\t\treturn this.tree.expandOnlyOnTwistieClick;\n\t\t}\n\n\t\tconst fn = this.tree.expandOnlyOnTwistieClick;\n\t\treturn element => fn(this.nodes.get((element === this.root.element ? null : element) as T) || null);\n\t}\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\tget options(): IAsyncDataTreeOptions {\n\t\treturn this.tree.options as IAsyncDataTreeOptions;\n\t}\n\n\t// Widget\n\n\tgetHTMLElement(): HTMLElement {\n\t\treturn this.tree.getHTMLElement();\n\t}\n\n\tget contentHeight(): number {\n\t\treturn this.tree.contentHeight;\n\t}\n\n\tget contentWidth(): number {\n\t\treturn this.tree.contentWidth;\n\t}\n\n\tget onDidChangeContentHeight(): Event {\n\t\treturn this.tree.onDidChangeContentHeight;\n\t}\n\n\tget onDidChangeContentWidth(): Event {\n\t\treturn this.tree.onDidChangeContentWidth;\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 scrollLeft(): number {\n\t\treturn this.tree.scrollLeft;\n\t}\n\n\tset scrollLeft(scrollLeft: number) {\n\t\tthis.tree.scrollLeft = scrollLeft;\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\tget lastVisibleElement(): T {\n\t\treturn this.tree.lastVisibleElement!.element as T;\n\t}\n\n\tget ariaLabel(): string {\n\t\treturn this.tree.ariaLabel;\n\t}\n\n\tset ariaLabel(value: string) {\n\t\tthis.tree.ariaLabel = value;\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 = viewState && { viewState, focus: [], selection: [] } as IAsyncDataTreeViewStateContext;\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\tasync updateChildren(element: TInput | T = this.root.element, recursive = true, rerender = false, options?: IAsyncDataTreeUpdateChildrenOptions): Promise {\n\t\tawait this._updateChildren(element, recursive, rerender, undefined, options);\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\tresort(element: TInput | T = this.root.element, recursive = true): void {\n\t\tthis.tree.resort(this.getDataNode(element), recursive);\n\t}\n\n\thasElement(element: TInput | T): boolean {\n\t\treturn this.tree.hasElement(this.getDataNode(element));\n\t}\n\n\thasNode(element: TInput | T): boolean {\n\t\treturn element === this.root.element || this.nodes.has(element as 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\tupdateElementHeight(element: T, height: number | undefined): void {\n\t\tconst node = this.getDataNode(element);\n\t\tthis.tree.updateElementHeight(node, height);\n\t}\n\n\tupdateWidth(element: T): void {\n\t\tconst node = this.getDataNode(element);\n\t\tthis.tree.updateWidth(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\ttoggleCollapsed(element: T, recursive: boolean = false): boolean {\n\t\treturn this.tree.toggleCollapsed(this.getDataNode(element), recursive);\n\t}\n\n\texpandAll(): void {\n\t\tthis.tree.expandAll();\n\t}\n\n\tasync expandTo(element: T): Promise {\n\t\tif (!this.dataSource.getParent) {\n\t\t\tthrow new Error('Can\\'t expand to element without getParent method');\n\t\t}\n\n\t\tconst elements: T[] = [];\n\n\t\twhile (!this.hasNode(element)) {\n\t\t\telement = this.dataSource.getParent(element) as T;\n\n\t\t\tif (element !== this.root.element) {\n\t\t\t\telements.push(element);\n\t\t\t}\n\t\t}\n\n\t\tfor (const element of Iterable.reverse(elements)) {\n\t\t\tawait this.expand(element);\n\t\t}\n\n\t\tthis.tree.expandTo(this.getDataNode(element));\n\t}\n\n\tcollapseAll(): void {\n\t\tthis.tree.collapseAll();\n\t}\n\n\tisCollapsible(element: T): boolean {\n\t\treturn this.tree.isCollapsible(this.getDataNode(element));\n\t}\n\n\tisCollapsed(element: TInput | T): boolean {\n\t\treturn this.tree.isCollapsed(this.getDataNode(element));\n\t}\n\n\ttriggerTypeNavigation(): void {\n\t\tthis.tree.triggerTypeNavigation();\n\t}\n\n\topenFind(): void {\n\t\tthis.tree.openFind();\n\t}\n\n\tcloseFind(): void {\n\t\tthis.tree.closeFind();\n\t}\n\n\trefilter(): void {\n\t\tthis.tree.refilter();\n\t}\n\n\tsetAnchor(element: T | undefined): void {\n\t\tthis.tree.setAnchor(typeof element === 'undefined' ? undefined : this.getDataNode(element));\n\t}\n\n\tgetAnchor(): T | undefined {\n\t\tconst node = this.tree.getAnchor();\n\t\treturn node?.element as T;\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\tfocusNext(n = 1, loop = false, browserEvent?: UIEvent): void {\n\t\tthis.tree.focusNext(n, loop, browserEvent);\n\t}\n\n\tfocusPrevious(n = 1, loop = false, browserEvent?: UIEvent): void {\n\t\tthis.tree.focusPrevious(n, loop, browserEvent);\n\t}\n\n\tfocusNextPage(browserEvent?: UIEvent): Promise {\n\t\treturn this.tree.focusNextPage(browserEvent);\n\t}\n\n\tfocusPreviousPage(browserEvent?: UIEvent): Promise {\n\t\treturn this.tree.focusPreviousPage(browserEvent);\n\t}\n\n\tfocusLast(browserEvent?: UIEvent): void {\n\t\tthis.tree.focusLast(browserEvent);\n\t}\n\n\tfocusFirst(browserEvent?: UIEvent): void {\n\t\tthis.tree.focusFirst(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\tgetStickyScrollFocus(): T[] {\n\t\tconst nodes = this.tree.getStickyScrollFocus();\n\t\treturn nodes.map(n => n!.element as T);\n\t}\n\n\tgetFocusedPart(): AbstractTreePart {\n\t\treturn this.tree.getFocusedPart();\n\t}\n\n\treveal(element: T, relativeTop?: number): void {\n\t\tthis.tree.reveal(this.getDataNode(element), relativeTop);\n\t}\n\n\tgetRelativeTop(element: T): number | null {\n\t\treturn this.tree.getRelativeTop(this.getDataNode(element));\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\t// view state\n\n\tgetViewState(): IAsyncDataTreeViewState {\n\t\tif (!this.identityProvider) {\n\t\t\tthrow new TreeError(this.user, 'Can\\'t get tree view state without an identity provider');\n\t\t}\n\n\t\tconst getId = (element: T) => this.identityProvider!.getId(element).toString();\n\t\tconst focus = this.getFocus().map(getId);\n\t\tconst selection = this.getSelection().map(getId);\n\n\t\tconst expanded: string[] = [];\n\t\tconst root = this.tree.getNode();\n\t\tconst stack = [root];\n\n\t\twhile (stack.length > 0) {\n\t\t\tconst node = stack.pop()!;\n\n\t\t\tif (node !== root && node.collapsible && !node.collapsed) {\n\t\t\t\texpanded.push(getId(node.element!.element as T));\n\t\t\t}\n\n\t\t\tstack.push(...node.children);\n\t\t}\n\n\t\treturn { focus, selection, expanded, scrollTop: this.scrollTop };\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 compressionEnabled?: boolean;\n\treadonly keyboardNavigationLabelProvider?: ICompressibleKeyboardNavigationLabelProvider;\n}\n\nexport interface ICompressibleAsyncDataTreeOptionsUpdate extends IAsyncDataTreeOptionsUpdate {\n\treadonly compressionEnabled?: boolean;\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\toverride getViewState(): IAsyncDataTreeViewState {\n\t\tif (!this.identityProvider) {\n\t\t\tthrow new TreeError(this.user, 'Can\\'t get tree view state without an identity provider');\n\t\t}\n\n\t\tconst getId = (element: T) => this.identityProvider!.getId(element).toString();\n\t\tconst focus = this.getFocus().map(getId);\n\t\tconst selection = this.getSelection().map(getId);\n\n\t\tconst expanded: string[] = [];\n\t\tconst root = this.tree.getCompressedTreeNode();\n\t\tconst stack = [root];\n\n\t\twhile (stack.length > 0) {\n\t\t\tconst node = stack.pop()!;\n\n\t\t\tif (node !== root && node.collapsible && !node.collapsed) {\n\t\t\t\tfor (const asyncNode of node.element!.elements) {\n\t\t\t\t\texpanded.push(getId(asyncNode.element as T));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstack.push(...node.children);\n\t\t}\n\n\t\treturn { focus, selection, expanded, scrollTop: this.scrollTop };\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 { firstOrDefault } from 'vs/base/common/arrays';\nimport { hasDriveLetter, toSlashes } from 'vs/base/common/extpath';\nimport { posix, sep, win32 } from 'vs/base/common/path';\nimport { isMacintosh, isWindows, OperatingSystem, OS } from 'vs/base/common/platform';\nimport { extUri, extUriIgnorePathCase } from 'vs/base/common/resources';\nimport { rtrim, startsWithIgnoreCase } from 'vs/base/common/strings';\nimport { URI } from 'vs/base/common/uri';\n\nexport interface IPathLabelFormatting {\n\n\t/**\n\t * The OS the path label is from to produce a label\n\t * that matches OS expectations.\n\t */\n\treadonly os: OperatingSystem;\n\n\t/**\n\t * Whether to add a `~` when the path is in the\n\t * user home directory.\n\t *\n\t * Note: this only applies to Linux, macOS but not\n\t * Windows.\n\t */\n\treadonly tildify?: IUserHomeProvider;\n\n\t/**\n\t * Whether to convert to a relative path if the path\n\t * is within any of the opened workspace folders.\n\t */\n\treadonly relative?: IRelativePathProvider;\n}\n\nexport interface IRelativePathProvider {\n\n\t/**\n\t * Whether to not add a prefix when in multi-root workspace.\n\t */\n\treadonly noPrefix?: boolean;\n\n\tgetWorkspace(): { folders: { uri: URI; name?: string }[] };\n\tgetWorkspaceFolder(resource: URI): { uri: URI; name?: string } | null;\n}\n\nexport interface IUserHomeProvider {\n\tuserHome: URI;\n}\n\nexport function getPathLabel(resource: URI, formatting: IPathLabelFormatting): string {\n\tconst { os, tildify: tildifier, relative: relatifier } = formatting;\n\n\t// return early with a relative path if we can resolve one\n\tif (relatifier) {\n\t\tconst relativePath = getRelativePathLabel(resource, relatifier, os);\n\t\tif (typeof relativePath === 'string') {\n\t\t\treturn relativePath;\n\t\t}\n\t}\n\n\t// otherwise try to resolve a absolute path label and\n\t// apply target OS standard path separators if target\n\t// OS differs from actual OS we are running in\n\tlet absolutePath = resource.fsPath;\n\tif (os === OperatingSystem.Windows && !isWindows) {\n\t\tabsolutePath = absolutePath.replace(/\\//g, '\\\\');\n\t} else if (os !== OperatingSystem.Windows && isWindows) {\n\t\tabsolutePath = absolutePath.replace(/\\\\/g, '/');\n\t}\n\n\t// macOS/Linux: tildify with provided user home directory\n\tif (os !== OperatingSystem.Windows && tildifier?.userHome) {\n\t\tconst userHome = tildifier.userHome.fsPath;\n\n\t\t// This is a bit of a hack, but in order to figure out if the\n\t\t// resource is in the user home, we need to make sure to convert it\n\t\t// to a user home resource. We cannot assume that the resource is\n\t\t// already a user home resource.\n\t\tlet userHomeCandidate: string;\n\t\tif (resource.scheme !== tildifier.userHome.scheme && resource.path[0] === posix.sep && resource.path[1] !== posix.sep) {\n\t\t\tuserHomeCandidate = tildifier.userHome.with({ path: resource.path }).fsPath;\n\t\t} else {\n\t\t\tuserHomeCandidate = absolutePath;\n\t\t}\n\n\t\tabsolutePath = tildify(userHomeCandidate, userHome, os);\n\t}\n\n\t// normalize\n\tconst pathLib = os === OperatingSystem.Windows ? win32 : posix;\n\treturn pathLib.normalize(normalizeDriveLetter(absolutePath, os === OperatingSystem.Windows));\n}\n\nfunction getRelativePathLabel(resource: URI, relativePathProvider: IRelativePathProvider, os: OperatingSystem): string | undefined {\n\tconst pathLib = os === OperatingSystem.Windows ? win32 : posix;\n\tconst extUriLib = os === OperatingSystem.Linux ? extUri : extUriIgnorePathCase;\n\n\tconst workspace = relativePathProvider.getWorkspace();\n\tconst firstFolder = firstOrDefault(workspace.folders);\n\tif (!firstFolder) {\n\t\treturn undefined;\n\t}\n\n\t// This is a bit of a hack, but in order to figure out the folder\n\t// the resource belongs to, we need to make sure to convert it\n\t// to a workspace resource. We cannot assume that the resource is\n\t// already matching the workspace.\n\tif (resource.scheme !== firstFolder.uri.scheme && resource.path[0] === posix.sep && resource.path[1] !== posix.sep) {\n\t\tresource = firstFolder.uri.with({ path: resource.path });\n\t}\n\n\tconst folder = relativePathProvider.getWorkspaceFolder(resource);\n\tif (!folder) {\n\t\treturn undefined;\n\t}\n\n\tlet relativePathLabel: string | undefined = undefined;\n\tif (extUriLib.isEqual(folder.uri, resource)) {\n\t\trelativePathLabel = ''; // no label if paths are identical\n\t} else {\n\t\trelativePathLabel = extUriLib.relativePath(folder.uri, resource) ?? '';\n\t}\n\n\t// normalize\n\tif (relativePathLabel) {\n\t\trelativePathLabel = pathLib.normalize(relativePathLabel);\n\t}\n\n\t// always show root basename if there are multiple folders\n\tif (workspace.folders.length > 1 && !relativePathProvider.noPrefix) {\n\t\tconst rootName = folder.name ? folder.name : extUriLib.basenameOrAuthority(folder.uri);\n\t\trelativePathLabel = relativePathLabel ? `${rootName} • ${relativePathLabel}` : rootName;\n\t}\n\n\treturn relativePathLabel;\n}\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);\nexport function tildify(path: string, userHome: string, os = OS): string {\n\tif (os === OperatingSystem.Windows || !path || !userHome) {\n\t\treturn path; // unsupported on Windows\n\t}\n\n\tlet normalizedUserHome = normalizedUserHomeCached.original === userHome ? normalizedUserHomeCached.normalized : undefined;\n\tif (!normalizedUserHome) {\n\t\tnormalizedUserHome = userHome;\n\t\tif (isWindows) {\n\t\t\tnormalizedUserHome = toSlashes(normalizedUserHome); // make sure that the path is POSIX normalized on Windows\n\t\t}\n\t\tnormalizedUserHome = `${rtrim(normalizedUserHome, posix.sep)}${posix.sep}`;\n\t\tnormalizedUserHomeCached = { original: userHome, normalized: normalizedUserHome };\n\t}\n\n\tlet normalizedPath = path;\n\tif (isWindows) {\n\t\tnormalizedPath = toSlashes(normalizedPath); // make sure that the path is POSIX normalized on Windows\n\t}\n\n\t// Linux: case sensitive, macOS: case insensitive\n\tif (os === OperatingSystem.Linux ? normalizedPath.startsWith(normalizedUserHome) : startsWithIgnoreCase(normalizedPath, normalizedUserHome)) {\n\t\treturn `~/${normalizedPath.substr(normalizedUserHome.length)}`;\n\t}\n\n\treturn path;\n}\n\nexport function untildify(path: string, userHome: string): string {\n\treturn path.replace(/^~($|\\/|\\\\)/, `${userHome}$1`);\n}\n\n/**\n * Shortens the paths but keeps them easy to distinguish.\n * Replaces not important parts with ellipsis.\n * Every shorten path matches only one original path and vice versa.\n *\n * Algorithm for shortening paths is as follows:\n * 1. For every path in list, find unique substring of that path.\n * 2. Unique substring along with ellipsis is shortened path of that path.\n * 3. To find unique substring of path, consider every segment of length from 1 to path.length of path from end of string\n * and if present segment is not substring to any other paths then present segment is unique path,\n * else check if it is not present as suffix of any other path and present segment is suffix of path itself,\n * if it is true take present segment as unique path.\n * 4. Apply ellipsis to unique segment according to whether segment is present at start/in-between/end of path.\n *\n * Example 1\n * 1. consider 2 paths i.e. ['a\\\\b\\\\c\\\\d', 'a\\\\f\\\\b\\\\c\\\\d']\n * 2. find unique path of first path,\n * \ta. 'd' is present in path2 and is suffix of path2, hence not unique of present path.\n * \tb. 'c' is present in path2 and 'c' is not suffix of present path, similarly for 'b' and 'a' also.\n * \tc. 'd\\\\c' is suffix of path2.\n * d. 'b\\\\c' is not suffix of present path.\n * e. 'a\\\\b' is not present in path2, hence unique path is 'a\\\\b...'.\n * 3. for path2, 'f' is not present in path1 hence unique is '...\\\\f\\\\...'.\n *\n * Example 2\n * 1. consider 2 paths i.e. ['a\\\\b', 'a\\\\b\\\\c'].\n * \ta. Even if 'b' is present in path2, as 'b' is suffix of path1 and is not suffix of path2, unique path will be '...\\\\b'.\n * 2. for path2, 'c' is not present in path1 hence unique path is '..\\\\c'.\n */\nconst ellipsis = '\\u2026';\nconst unc = '\\\\\\\\';\nconst home = '~';\nexport function shorten(paths: string[], pathSeparator: string = sep): string[] {\n\tconst shortenedPaths: string[] = new Array(paths.length);\n\n\t// for every path\n\tlet match = false;\n\tfor (let pathIndex = 0; pathIndex < paths.length; pathIndex++) {\n\t\tconst originalPath = paths[pathIndex];\n\n\t\tif (originalPath === '') {\n\t\t\tshortenedPaths[pathIndex] = `.${pathSeparator}`;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (!originalPath) {\n\t\t\tshortenedPaths[pathIndex] = originalPath;\n\t\t\tcontinue;\n\t\t}\n\n\t\tmatch = true;\n\n\t\t// trim for now and concatenate unc path (e.g. \\\\network) or root path (/etc, ~/etc) later\n\t\tlet prefix = '';\n\t\tlet trimmedPath = originalPath;\n\t\tif (trimmedPath.indexOf(unc) === 0) {\n\t\t\tprefix = trimmedPath.substr(0, trimmedPath.indexOf(unc) + unc.length);\n\t\t\ttrimmedPath = trimmedPath.substr(trimmedPath.indexOf(unc) + unc.length);\n\t\t} else if (trimmedPath.indexOf(pathSeparator) === 0) {\n\t\t\tprefix = trimmedPath.substr(0, trimmedPath.indexOf(pathSeparator) + pathSeparator.length);\n\t\t\ttrimmedPath = trimmedPath.substr(trimmedPath.indexOf(pathSeparator) + pathSeparator.length);\n\t\t} else if (trimmedPath.indexOf(home) === 0) {\n\t\t\tprefix = trimmedPath.substr(0, trimmedPath.indexOf(home) + home.length);\n\t\t\ttrimmedPath = trimmedPath.substr(trimmedPath.indexOf(home) + home.length);\n\t\t}\n\n\t\t// pick the first shortest subpath found\n\t\tconst segments: string[] = trimmedPath.split(pathSeparator);\n\t\tfor (let subpathLength = 1; match && subpathLength <= segments.length; subpathLength++) {\n\t\t\tfor (let start = segments.length - subpathLength; match && start >= 0; start--) {\n\t\t\t\tmatch = false;\n\t\t\t\tlet subpath = segments.slice(start, start + subpathLength).join(pathSeparator);\n\n\t\t\t\t// that is unique to any other path\n\t\t\t\tfor (let otherPathIndex = 0; !match && otherPathIndex < paths.length; otherPathIndex++) {\n\n\t\t\t\t\t// suffix subpath treated specially as we consider no match 'x' and 'x/...'\n\t\t\t\t\tif (otherPathIndex !== pathIndex && paths[otherPathIndex] && paths[otherPathIndex].indexOf(subpath) > -1) {\n\t\t\t\t\t\tconst isSubpathEnding: boolean = (start + subpathLength === segments.length);\n\n\t\t\t\t\t\t// Adding separator as prefix for subpath, such that 'endsWith(src, trgt)' considers subpath as directory name instead of plain string.\n\t\t\t\t\t\t// prefix is not added when either subpath is root directory or path[otherPathIndex] does not have multiple directories.\n\t\t\t\t\t\tconst subpathWithSep: string = (start > 0 && paths[otherPathIndex].indexOf(pathSeparator) > -1) ? pathSeparator + subpath : subpath;\n\t\t\t\t\t\tconst isOtherPathEnding: boolean = paths[otherPathIndex].endsWith(subpathWithSep);\n\n\t\t\t\t\t\tmatch = !isSubpathEnding || isOtherPathEnding;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// found unique subpath\n\t\t\t\tif (!match) {\n\t\t\t\t\tlet result = '';\n\n\t\t\t\t\t// preserve disk drive or root prefix\n\t\t\t\t\tif (segments[0].endsWith(':') || prefix !== '') {\n\t\t\t\t\t\tif (start === 1) {\n\t\t\t\t\t\t\t// extend subpath to include disk drive prefix\n\t\t\t\t\t\t\tstart = 0;\n\t\t\t\t\t\t\tsubpathLength++;\n\t\t\t\t\t\t\tsubpath = segments[0] + pathSeparator + subpath;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (start > 0) {\n\t\t\t\t\t\t\tresult = segments[0] + pathSeparator;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tresult = prefix + result;\n\t\t\t\t\t}\n\n\t\t\t\t\t// add ellipsis at the beginning if needed\n\t\t\t\t\tif (start > 0) {\n\t\t\t\t\t\tresult = result + ellipsis + pathSeparator;\n\t\t\t\t\t}\n\n\t\t\t\t\tresult = result + subpath;\n\n\t\t\t\t\t// add ellipsis at the end if needed\n\t\t\t\t\tif (start + subpathLength < segments.length) {\n\t\t\t\t\t\tresult = result + pathSeparator + ellipsis;\n\t\t\t\t\t}\n\n\t\t\t\t\tshortenedPaths[pathIndex] = result;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (match) {\n\t\t\tshortenedPaths[pathIndex] = originalPath; // use original path if no unique subpaths found\n\t\t}\n\t}\n\n\treturn shortenedPaths;\n}\n\nexport interface ISeparator {\n\tlabel: string;\n}\n\nenum Type {\n\tTEXT,\n\tVARIABLE,\n\tSEPARATOR\n}\n\ninterface ISegment {\n\tvalue: string;\n\ttype: Type;\n}\n\n/**\n * Helper to insert values for specific template variables into the string. E.g. \"this $(is) a $(template)\" can be\n * passed to this function together with an object that maps \"is\" and \"template\" to strings to have them replaced.\n * @param value string to which template is applied\n * @param values the values of the templates to use\n */\nexport function template(template: string, values: { [key: string]: string | ISeparator | undefined | null } = Object.create(null)): string {\n\tconst segments: ISegment[] = [];\n\n\tlet inVariable = false;\n\tlet curVal = '';\n\tfor (const char of template) {\n\t\t// Beginning of variable\n\t\tif (char === '$' || (inVariable && char === '{')) {\n\t\t\tif (curVal) {\n\t\t\t\tsegments.push({ value: curVal, type: Type.TEXT });\n\t\t\t}\n\n\t\t\tcurVal = '';\n\t\t\tinVariable = true;\n\t\t}\n\n\t\t// End of variable\n\t\telse if (char === '}' && inVariable) {\n\t\t\tconst resolved = values[curVal];\n\n\t\t\t// Variable\n\t\t\tif (typeof resolved === 'string') {\n\t\t\t\tif (resolved.length) {\n\t\t\t\t\tsegments.push({ value: resolved, type: Type.VARIABLE });\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Separator\n\t\t\telse if (resolved) {\n\t\t\t\tconst prevSegment = segments[segments.length - 1];\n\t\t\t\tif (!prevSegment || prevSegment.type !== Type.SEPARATOR) {\n\t\t\t\t\tsegments.push({ value: resolved.label, type: Type.SEPARATOR }); // prevent duplicate separators\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tcurVal = '';\n\t\t\tinVariable = false;\n\t\t}\n\n\t\t// Text or Variable Name\n\t\telse {\n\t\t\tcurVal += char;\n\t\t}\n\t}\n\n\t// Tail\n\tif (curVal && !inVariable) {\n\t\tsegments.push({ value: curVal, type: Type.TEXT });\n\t}\n\n\treturn segments.filter((segment, index) => {\n\n\t\t// Only keep separator if we have values to the left and right\n\t\tif (segment.type === Type.SEPARATOR) {\n\t\t\tconst left = segments[index - 1];\n\t\t\tconst right = segments[index + 1];\n\n\t\t\treturn [left, right].every(segment => segment && (segment.type === Type.VARIABLE || segment.type === Type.TEXT) && segment.value.length > 0);\n\t\t}\n\n\t\t// accept any TEXT and VARIABLE\n\t\treturn true;\n\t}).map(segment => segment.value).join('');\n}\n\n/**\n * Handles mnemonics for menu items. Depending on OS:\n * - Windows: Supported via & character (replace && with &)\n * - Linux: Supported via & character (replace && with &)\n * - macOS: Unsupported (replace && with empty string)\n */\nexport function mnemonicMenuLabel(label: string, forceDisableMnemonics?: boolean): string {\n\tif (isMacintosh || forceDisableMnemonics) {\n\t\treturn label.replace(/\\(&&\\w\\)|&&/g, '').replace(/&/g, isMacintosh ? '&' : '&&');\n\t}\n\n\treturn label.replace(/&&|&/g, m => m === '&' ? '&&' : '&');\n}\n\n/**\n * Handles mnemonics for buttons. Depending on OS:\n * - Windows: Supported via & character (replace && with & and & with && for escaping)\n * - Linux: Supported via _ character (replace && with _)\n * - macOS: Unsupported (replace && with empty string)\n */\nexport function mnemonicButtonLabel(label: string, forceDisableMnemonics?: boolean): string {\n\tif (isMacintosh || forceDisableMnemonics) {\n\t\treturn label.replace(/\\(&&\\w\\)|&&/g, '');\n\t}\n\n\tif (isWindows) {\n\t\treturn label.replace(/&&|&/g, m => m === '&' ? '&&' : '&');\n\t}\n\n\treturn label.replace(/&&/g, '_');\n}\n\nexport function unmnemonicLabel(label: string): string {\n\treturn label.replace(/&/g, '&&');\n}\n\n/**\n * Splits a recent label in name and parent path, supporting both '/' and '\\' and workspace suffixes.\n * If the location is remote, the remote name is included in the name part.\n */\nexport function splitRecentLabel(recentLabel: string): { name: string; parentPath: string } {\n\tif (recentLabel.endsWith(']')) {\n\t\t// label with workspace suffix\n\t\tconst lastIndexOfSquareBracket = recentLabel.lastIndexOf(' [', recentLabel.length - 2);\n\t\tif (lastIndexOfSquareBracket !== -1) {\n\t\t\tconst split = splitName(recentLabel.substring(0, lastIndexOfSquareBracket));\n\t\t\tconst remoteNameWithSpace = recentLabel.substring(lastIndexOfSquareBracket);\n\t\t\treturn { name: split.name + remoteNameWithSpace, parentPath: split.parentPath };\n\t\t}\n\t}\n\treturn splitName(recentLabel);\n}\n\nfunction splitName(fullPath: string): { name: string; parentPath: string } {\n\tconst p = fullPath.indexOf('/') !== -1 ? posix : win32;\n\tconst name = p.basename(fullPath);\n\tconst parentPath = p.dirname(fullPath);\n\tif (name.length) {\n\t\treturn { name, parentPath };\n\t}\n\t// only the root segment\n\treturn { name: parentPath, parentPath: '' };\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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, clearNode, EventHelper, EventType, getWindow, hide, isActiveElement, isAncestor, show } from 'vs/base/browser/dom';\nimport { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';\nimport { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';\nimport { ButtonBar, ButtonWithDescription, IButtonStyles } from 'vs/base/browser/ui/button/button';\nimport { ICheckboxStyles, Checkbox } from 'vs/base/browser/ui/toggle/toggle';\nimport { IInputBoxStyles, InputBox } from 'vs/base/browser/ui/inputbox/inputBox';\nimport { Action } from 'vs/base/common/actions';\nimport { Codicon } from 'vs/base/common/codicons';\nimport { ThemeIcon } from 'vs/base/common/themables';\nimport { KeyCode, KeyMod } from 'vs/base/common/keyCodes';\nimport { mnemonicButtonLabel } from 'vs/base/common/labels';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { isLinux, isMacintosh, isWindows } from 'vs/base/common/platform';\nimport 'vs/css!./dialog';\nimport * as nls from 'vs/nls';\n\nexport interface IDialogInputOptions {\n\treadonly placeholder?: string;\n\treadonly type?: 'text' | 'password';\n\treadonly value?: string;\n}\n\nexport interface IDialogOptions {\n\treadonly cancelId?: number;\n\treadonly detail?: string;\n\treadonly checkboxLabel?: string;\n\treadonly checkboxChecked?: boolean;\n\treadonly type?: 'none' | 'info' | 'error' | 'question' | 'warning' | 'pending';\n\treadonly inputs?: IDialogInputOptions[];\n\treadonly keyEventProcessor?: (event: StandardKeyboardEvent) => void;\n\treadonly renderBody?: (container: HTMLElement) => void;\n\treadonly icon?: ThemeIcon;\n\treadonly buttonDetails?: string[];\n\treadonly disableCloseAction?: boolean;\n\treadonly disableDefaultAction?: boolean;\n\treadonly buttonStyles: IButtonStyles;\n\treadonly checkboxStyles: ICheckboxStyles;\n\treadonly inputBoxStyles: IInputBoxStyles;\n\treadonly dialogStyles: IDialogStyles;\n}\n\nexport interface IDialogResult {\n\treadonly button: number;\n\treadonly checkboxChecked?: boolean;\n\treadonly values?: string[];\n}\n\nexport interface IDialogStyles {\n\treadonly dialogForeground: string | undefined;\n\treadonly dialogBackground: string | undefined;\n\treadonly dialogShadow: string | undefined;\n\treadonly dialogBorder: string | undefined;\n\treadonly errorIconForeground: string | undefined;\n\treadonly warningIconForeground: string | undefined;\n\treadonly infoIconForeground: string | undefined;\n\treadonly textLinkForeground: string | undefined;\n}\n\ninterface ButtonMapEntry {\n\treadonly label: string;\n\treadonly index: number;\n}\n\nexport class Dialog extends Disposable {\n\tprivate readonly element: HTMLElement;\n\tprivate readonly shadowElement: HTMLElement;\n\tprivate modalElement: HTMLElement | undefined;\n\tprivate readonly buttonsContainer: HTMLElement;\n\tprivate readonly messageDetailElement: HTMLElement;\n\tprivate readonly messageContainer: HTMLElement;\n\tprivate readonly iconElement: HTMLElement;\n\tprivate readonly checkbox: Checkbox | undefined;\n\tprivate readonly toolbarContainer: HTMLElement;\n\tprivate buttonBar: ButtonBar | undefined;\n\tprivate focusToReturn: HTMLElement | undefined;\n\tprivate readonly inputs: InputBox[];\n\tprivate readonly buttons: string[];\n\tprivate readonly buttonStyles: IButtonStyles;\n\n\tconstructor(private container: HTMLElement, private message: string, buttons: string[] | undefined, private readonly options: IDialogOptions) {\n\t\tsuper();\n\n\t\tthis.modalElement = this.container.appendChild($(`.monaco-dialog-modal-block.dimmed`));\n\t\tthis.shadowElement = this.modalElement.appendChild($('.dialog-shadow'));\n\t\tthis.element = this.shadowElement.appendChild($('.monaco-dialog-box'));\n\t\tthis.element.setAttribute('role', 'dialog');\n\t\tthis.element.tabIndex = -1;\n\t\thide(this.element);\n\n\t\tthis.buttonStyles = options.buttonStyles;\n\n\t\tif (Array.isArray(buttons) && buttons.length > 0) {\n\t\t\tthis.buttons = buttons;\n\t\t} else if (!this.options.disableDefaultAction) {\n\t\t\tthis.buttons = [nls.localize('ok', \"OK\")];\n\t\t} else {\n\t\t\tthis.buttons = [];\n\t\t}\n\t\tconst buttonsRowElement = this.element.appendChild($('.dialog-buttons-row'));\n\t\tthis.buttonsContainer = buttonsRowElement.appendChild($('.dialog-buttons'));\n\n\t\tconst messageRowElement = this.element.appendChild($('.dialog-message-row'));\n\t\tthis.iconElement = messageRowElement.appendChild($('#monaco-dialog-icon.dialog-icon'));\n\t\tthis.iconElement.setAttribute('aria-label', this.getIconAriaLabel());\n\t\tthis.messageContainer = messageRowElement.appendChild($('.dialog-message-container'));\n\n\t\tif (this.options.detail || this.options.renderBody) {\n\t\t\tconst messageElement = this.messageContainer.appendChild($('.dialog-message'));\n\t\t\tconst messageTextElement = messageElement.appendChild($('#monaco-dialog-message-text.dialog-message-text'));\n\t\t\tmessageTextElement.innerText = this.message;\n\t\t}\n\n\t\tthis.messageDetailElement = this.messageContainer.appendChild($('#monaco-dialog-message-detail.dialog-message-detail'));\n\t\tif (this.options.detail || !this.options.renderBody) {\n\t\t\tthis.messageDetailElement.innerText = this.options.detail ? this.options.detail : message;\n\t\t} else {\n\t\t\tthis.messageDetailElement.style.display = 'none';\n\t\t}\n\n\t\tif (this.options.renderBody) {\n\t\t\tconst customBody = this.messageContainer.appendChild($('#monaco-dialog-message-body.dialog-message-body'));\n\t\t\tthis.options.renderBody(customBody);\n\n\t\t\tfor (const el of this.messageContainer.querySelectorAll('a')) {\n\t\t\t\tel.tabIndex = 0;\n\t\t\t}\n\t\t}\n\n\t\tif (this.options.inputs) {\n\t\t\tthis.inputs = this.options.inputs.map(input => {\n\t\t\t\tconst inputRowElement = this.messageContainer.appendChild($('.dialog-message-input'));\n\n\t\t\t\tconst inputBox = this._register(new InputBox(inputRowElement, undefined, {\n\t\t\t\t\tplaceholder: input.placeholder,\n\t\t\t\t\ttype: input.type ?? 'text',\n\t\t\t\t\tinputBoxStyles: options.inputBoxStyles\n\t\t\t\t}));\n\n\t\t\t\tif (input.value) {\n\t\t\t\t\tinputBox.value = input.value;\n\t\t\t\t}\n\n\t\t\t\treturn inputBox;\n\t\t\t});\n\t\t} else {\n\t\t\tthis.inputs = [];\n\t\t}\n\n\t\tif (this.options.checkboxLabel) {\n\t\t\tconst checkboxRowElement = this.messageContainer.appendChild($('.dialog-checkbox-row'));\n\n\t\t\tconst checkbox = this.checkbox = this._register(\n\t\t\t\tnew Checkbox(this.options.checkboxLabel, !!this.options.checkboxChecked, options.checkboxStyles)\n\t\t\t);\n\n\t\t\tcheckboxRowElement.appendChild(checkbox.domNode);\n\n\t\t\tconst checkboxMessageElement = checkboxRowElement.appendChild($('.dialog-checkbox-message'));\n\t\t\tcheckboxMessageElement.innerText = this.options.checkboxLabel;\n\t\t\tthis._register(addDisposableListener(checkboxMessageElement, EventType.CLICK, () => checkbox.checked = !checkbox.checked));\n\t\t}\n\n\t\tconst toolbarRowElement = this.element.appendChild($('.dialog-toolbar-row'));\n\t\tthis.toolbarContainer = toolbarRowElement.appendChild($('.dialog-toolbar'));\n\n\t\tthis.applyStyles();\n\t}\n\n\tprivate getIconAriaLabel(): string {\n\t\tlet typeLabel = nls.localize('dialogInfoMessage', 'Info');\n\t\tswitch (this.options.type) {\n\t\t\tcase 'error':\n\t\t\t\ttypeLabel = nls.localize('dialogErrorMessage', 'Error');\n\t\t\t\tbreak;\n\t\t\tcase 'warning':\n\t\t\t\ttypeLabel = nls.localize('dialogWarningMessage', 'Warning');\n\t\t\t\tbreak;\n\t\t\tcase 'pending':\n\t\t\t\ttypeLabel = nls.localize('dialogPendingMessage', 'In Progress');\n\t\t\t\tbreak;\n\t\t\tcase 'none':\n\t\t\tcase 'info':\n\t\t\tcase 'question':\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\n\t\treturn typeLabel;\n\t}\n\n\tupdateMessage(message: string): void {\n\t\tthis.messageDetailElement.innerText = message;\n\t}\n\n\tasync show(): Promise {\n\t\tthis.focusToReturn = this.container.ownerDocument.activeElement as HTMLElement;\n\n\t\treturn new Promise((resolve) => {\n\t\t\tclearNode(this.buttonsContainer);\n\n\t\t\tconst buttonBar = this.buttonBar = this._register(new ButtonBar(this.buttonsContainer));\n\t\t\tconst buttonMap = this.rearrangeButtons(this.buttons, this.options.cancelId);\n\n\t\t\t// Handle button clicks\n\t\t\tbuttonMap.forEach((entry, index) => {\n\t\t\t\tconst primary = buttonMap[index].index === 0;\n\t\t\t\tconst button = this.options.buttonDetails ? this._register(buttonBar.addButtonWithDescription({ title: true, secondary: !primary, ...this.buttonStyles })) : this._register(buttonBar.addButton({ title: true, secondary: !primary, ...this.buttonStyles }));\n\t\t\t\tbutton.label = mnemonicButtonLabel(buttonMap[index].label, true);\n\t\t\t\tif (button instanceof ButtonWithDescription) {\n\t\t\t\t\tbutton.description = this.options.buttonDetails![buttonMap[index].index];\n\t\t\t\t}\n\t\t\t\tthis._register(button.onDidClick(e => {\n\t\t\t\t\tif (e) {\n\t\t\t\t\t\tEventHelper.stop(e);\n\t\t\t\t\t}\n\n\t\t\t\t\tresolve({\n\t\t\t\t\t\tbutton: buttonMap[index].index,\n\t\t\t\t\t\tcheckboxChecked: this.checkbox ? this.checkbox.checked : undefined,\n\t\t\t\t\t\tvalues: this.inputs.length > 0 ? this.inputs.map(input => input.value) : undefined\n\t\t\t\t\t});\n\t\t\t\t}));\n\t\t\t});\n\n\t\t\t// Handle keyboard events globally: Tab, Arrow-Left/Right\n\t\t\tconst window = getWindow(this.container);\n\t\t\tthis._register(addDisposableListener(window, 'keydown', e => {\n\t\t\t\tconst evt = new StandardKeyboardEvent(e);\n\n\t\t\t\tif (evt.equals(KeyMod.Alt)) {\n\t\t\t\t\tevt.preventDefault();\n\t\t\t\t}\n\n\t\t\t\tif (evt.equals(KeyCode.Enter)) {\n\n\t\t\t\t\t// Enter in input field should OK the dialog\n\t\t\t\t\tif (this.inputs.some(input => input.hasFocus())) {\n\t\t\t\t\t\tEventHelper.stop(e);\n\n\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\tbutton: buttonMap.find(button => button.index !== this.options.cancelId)?.index ?? 0,\n\t\t\t\t\t\t\tcheckboxChecked: this.checkbox ? this.checkbox.checked : undefined,\n\t\t\t\t\t\t\tvalues: this.inputs.length > 0 ? this.inputs.map(input => input.value) : undefined\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\treturn; // leave default handling\n\t\t\t\t}\n\n\t\t\t\tif (evt.equals(KeyCode.Space)) {\n\t\t\t\t\treturn; // leave default handling\n\t\t\t\t}\n\n\t\t\t\tlet eventHandled = false;\n\n\t\t\t\t// Focus: Next / Previous\n\t\t\t\tif (evt.equals(KeyCode.Tab) || evt.equals(KeyCode.RightArrow) || evt.equals(KeyMod.Shift | KeyCode.Tab) || evt.equals(KeyCode.LeftArrow)) {\n\n\t\t\t\t\t// Build a list of focusable elements in their visual order\n\t\t\t\t\tconst focusableElements: { focus: () => void }[] = [];\n\t\t\t\t\tlet focusedIndex = -1;\n\n\t\t\t\t\tif (this.messageContainer) {\n\t\t\t\t\t\tconst links = this.messageContainer.querySelectorAll('a');\n\t\t\t\t\t\tfor (const link of links) {\n\t\t\t\t\t\t\tfocusableElements.push(link);\n\t\t\t\t\t\t\tif (isActiveElement(link)) {\n\t\t\t\t\t\t\t\tfocusedIndex = focusableElements.length - 1;\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\tfor (const input of this.inputs) {\n\t\t\t\t\t\tfocusableElements.push(input);\n\t\t\t\t\t\tif (input.hasFocus()) {\n\t\t\t\t\t\t\tfocusedIndex = focusableElements.length - 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (this.checkbox) {\n\t\t\t\t\t\tfocusableElements.push(this.checkbox);\n\t\t\t\t\t\tif (this.checkbox.hasFocus()) {\n\t\t\t\t\t\t\tfocusedIndex = focusableElements.length - 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (this.buttonBar) {\n\t\t\t\t\t\tfor (const button of this.buttonBar.buttons) {\n\t\t\t\t\t\t\tfocusableElements.push(button);\n\t\t\t\t\t\t\tif (button.hasFocus()) {\n\t\t\t\t\t\t\t\tfocusedIndex = focusableElements.length - 1;\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// Focus next element (with wrapping)\n\t\t\t\t\tif (evt.equals(KeyCode.Tab) || evt.equals(KeyCode.RightArrow)) {\n\t\t\t\t\t\tif (focusedIndex === -1) {\n\t\t\t\t\t\t\tfocusedIndex = 0; // default to focus first element if none have focus\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst newFocusedIndex = (focusedIndex + 1) % focusableElements.length;\n\t\t\t\t\t\tfocusableElements[newFocusedIndex].focus();\n\t\t\t\t\t}\n\n\t\t\t\t\t// Focus previous element (with wrapping)\n\t\t\t\t\telse {\n\t\t\t\t\t\tif (focusedIndex === -1) {\n\t\t\t\t\t\t\tfocusedIndex = focusableElements.length; // default to focus last element if none have focus\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tlet newFocusedIndex = focusedIndex - 1;\n\t\t\t\t\t\tif (newFocusedIndex === -1) {\n\t\t\t\t\t\t\tnewFocusedIndex = focusableElements.length - 1;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tfocusableElements[newFocusedIndex].focus();\n\t\t\t\t\t}\n\n\t\t\t\t\teventHandled = true;\n\t\t\t\t}\n\n\t\t\t\tif (eventHandled) {\n\t\t\t\t\tEventHelper.stop(e, true);\n\t\t\t\t} else if (this.options.keyEventProcessor) {\n\t\t\t\t\tthis.options.keyEventProcessor(evt);\n\t\t\t\t}\n\t\t\t}, true));\n\n\t\t\tthis._register(addDisposableListener(window, 'keyup', e => {\n\t\t\t\tEventHelper.stop(e, true);\n\t\t\t\tconst evt = new StandardKeyboardEvent(e);\n\n\t\t\t\tif (!this.options.disableCloseAction && evt.equals(KeyCode.Escape)) {\n\t\t\t\t\tresolve({\n\t\t\t\t\t\tbutton: this.options.cancelId || 0,\n\t\t\t\t\t\tcheckboxChecked: this.checkbox ? this.checkbox.checked : undefined\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}, true));\n\n\t\t\t// Detect focus out\n\t\t\tthis._register(addDisposableListener(this.element, 'focusout', e => {\n\t\t\t\tif (!!e.relatedTarget && !!this.element) {\n\t\t\t\t\tif (!isAncestor(e.relatedTarget as HTMLElement, this.element)) {\n\t\t\t\t\t\tthis.focusToReturn = e.relatedTarget as HTMLElement;\n\n\t\t\t\t\t\tif (e.target) {\n\t\t\t\t\t\t\t(e.target as HTMLElement).focus();\n\t\t\t\t\t\t\tEventHelper.stop(e, true);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}, false));\n\n\t\t\tconst spinModifierClassName = 'codicon-modifier-spin';\n\n\t\t\tthis.iconElement.classList.remove(...ThemeIcon.asClassNameArray(Codicon.dialogError), ...ThemeIcon.asClassNameArray(Codicon.dialogWarning), ...ThemeIcon.asClassNameArray(Codicon.dialogInfo), ...ThemeIcon.asClassNameArray(Codicon.loading), spinModifierClassName);\n\n\t\t\tif (this.options.icon) {\n\t\t\t\tthis.iconElement.classList.add(...ThemeIcon.asClassNameArray(this.options.icon));\n\t\t\t} else {\n\t\t\t\tswitch (this.options.type) {\n\t\t\t\t\tcase 'error':\n\t\t\t\t\t\tthis.iconElement.classList.add(...ThemeIcon.asClassNameArray(Codicon.dialogError));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'warning':\n\t\t\t\t\t\tthis.iconElement.classList.add(...ThemeIcon.asClassNameArray(Codicon.dialogWarning));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'pending':\n\t\t\t\t\t\tthis.iconElement.classList.add(...ThemeIcon.asClassNameArray(Codicon.loading), spinModifierClassName);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'none':\n\t\t\t\t\t\tthis.iconElement.classList.add('no-codicon');\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'info':\n\t\t\t\t\tcase 'question':\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tthis.iconElement.classList.add(...ThemeIcon.asClassNameArray(Codicon.dialogInfo));\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\n\t\t\tif (!this.options.disableCloseAction) {\n\t\t\t\tconst actionBar = this._register(new ActionBar(this.toolbarContainer, {}));\n\n\t\t\t\tconst action = this._register(new Action('dialog.close', nls.localize('dialogClose', \"Close Dialog\"), ThemeIcon.asClassName(Codicon.dialogClose), true, async () => {\n\t\t\t\t\tresolve({\n\t\t\t\t\t\tbutton: this.options.cancelId || 0,\n\t\t\t\t\t\tcheckboxChecked: this.checkbox ? this.checkbox.checked : undefined\n\t\t\t\t\t});\n\t\t\t\t}));\n\n\t\t\t\tactionBar.push(action, { icon: true, label: false });\n\t\t\t}\n\n\t\t\tthis.applyStyles();\n\n\t\t\tthis.element.setAttribute('aria-modal', 'true');\n\t\t\tthis.element.setAttribute('aria-labelledby', 'monaco-dialog-icon monaco-dialog-message-text');\n\t\t\tthis.element.setAttribute('aria-describedby', 'monaco-dialog-icon monaco-dialog-message-text monaco-dialog-message-detail monaco-dialog-message-body');\n\t\t\tshow(this.element);\n\n\t\t\t// Focus first element (input or button)\n\t\t\tif (this.inputs.length > 0) {\n\t\t\t\tthis.inputs[0].focus();\n\t\t\t\tthis.inputs[0].select();\n\t\t\t} else {\n\t\t\t\tbuttonMap.forEach((value, index) => {\n\t\t\t\t\tif (value.index === 0) {\n\t\t\t\t\t\tbuttonBar.buttons[index].focus();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate applyStyles() {\n\t\tconst style = this.options.dialogStyles;\n\n\t\tconst fgColor = style.dialogForeground;\n\t\tconst bgColor = style.dialogBackground;\n\t\tconst shadowColor = style.dialogShadow ? `0 0px 8px ${style.dialogShadow}` : '';\n\t\tconst border = style.dialogBorder ? `1px solid ${style.dialogBorder}` : '';\n\t\tconst linkFgColor = style.textLinkForeground;\n\n\t\tthis.shadowElement.style.boxShadow = shadowColor;\n\n\t\tthis.element.style.color = fgColor ?? '';\n\t\tthis.element.style.backgroundColor = bgColor ?? '';\n\t\tthis.element.style.border = border;\n\n\t\t// TODO fix\n\t\t// if (fgColor && bgColor) {\n\t\t// \tconst messageDetailColor = fgColor.transparent(.9);\n\t\t// \tthis.messageDetailElement.style.mixBlendMode = messageDetailColor.makeOpaque(bgColor).toString();\n\t\t// }\n\n\t\tif (linkFgColor) {\n\t\t\tfor (const el of this.messageContainer.getElementsByTagName('a')) {\n\t\t\t\tel.style.color = linkFgColor;\n\t\t\t}\n\t\t}\n\n\t\tlet color;\n\t\tswitch (this.options.type) {\n\t\t\tcase 'error':\n\t\t\t\tcolor = style.errorIconForeground;\n\t\t\t\tbreak;\n\t\t\tcase 'warning':\n\t\t\t\tcolor = style.warningIconForeground;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tcolor = style.infoIconForeground;\n\t\t\t\tbreak;\n\t\t}\n\t\tif (color) {\n\t\t\tthis.iconElement.style.color = color;\n\t\t}\n\t}\n\n\toverride dispose(): void {\n\t\tsuper.dispose();\n\n\t\tif (this.modalElement) {\n\t\t\tthis.modalElement.remove();\n\t\t\tthis.modalElement = undefined;\n\t\t}\n\n\t\tif (this.focusToReturn && isAncestor(this.focusToReturn, this.container.ownerDocument.body)) {\n\t\t\tthis.focusToReturn.focus();\n\t\t\tthis.focusToReturn = undefined;\n\t\t}\n\t}\n\n\tprivate rearrangeButtons(buttons: Array, cancelId: number | undefined): ButtonMapEntry[] {\n\n\t\t// Maps each button to its current label and old index\n\t\t// so that when we move them around it's not a problem\n\t\tconst buttonMap: ButtonMapEntry[] = buttons.map((label, index) => ({ label, index }));\n\n\t\tif (buttons.length < 2) {\n\t\t\treturn buttonMap; // only need to rearrange if there are 2+ buttons\n\t\t}\n\n\t\tif (isMacintosh || isLinux) {\n\n\t\t\t// Linux: the GNOME HIG (https://developer.gnome.org/hig/patterns/feedback/dialogs.html?highlight=dialog)\n\t\t\t// recommend the following:\n\t\t\t// \"Always ensure that the cancel button appears first, before the affirmative button. In left-to-right\n\t\t\t// locales, this is on the left. This button order ensures that users become aware of, and are reminded\n\t\t\t// of, the ability to cancel prior to encountering the affirmative button.\"\n\n\t\t\t// macOS: the HIG (https://developer.apple.com/design/human-interface-guidelines/components/presentation/alerts)\n\t\t\t// recommend the following:\n\t\t\t// \"Place buttons where people expect. In general, place the button people are most likely to choose on the trailing side in a\n\t\t\t// row of buttons or at the top in a stack of buttons. Always place the default button on the trailing side of a row or at the\n\t\t\t// top of a stack. Cancel buttons are typically on the leading side of a row or at the bottom of a stack.\"\n\n\t\t\tif (typeof cancelId === 'number' && buttonMap[cancelId]) {\n\t\t\t\tconst cancelButton = buttonMap.splice(cancelId, 1)[0];\n\t\t\t\tbuttonMap.splice(1, 0, cancelButton);\n\t\t\t}\n\n\t\t\tbuttonMap.reverse();\n\t\t} else if (isWindows) {\n\n\t\t\t// Windows: the HIG (https://learn.microsoft.com/en-us/windows/win32/uxguide/win-dialog-box)\n\t\t\t// recommend the following:\n\t\t\t// \"One of the following sets of concise commands: Yes/No, Yes/No/Cancel, [Do it]/Cancel,\n\t\t\t// [Do it]/[Don't do it], [Do it]/[Don't do it]/Cancel.\"\n\n\t\t\tif (typeof cancelId === 'number' && buttonMap[cancelId]) {\n\t\t\t\tconst cancelButton = buttonMap.splice(cancelId, 1)[0];\n\t\t\t\tbuttonMap.push(cancelButton);\n\t\t\t}\n\t\t}\n\n\t\treturn buttonMap;\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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';\nimport { PathIterator } from 'vs/base/common/ternarySearchTree';\nimport * as paths from 'vs/base/common/path';\nimport { extUri as defaultExtUri, IExtUri } from 'vs/base/common/resources';\nimport { URI } from 'vs/base/common/uri';\n\nexport interface IResourceNode {\n\treadonly uri: URI;\n\treadonly relativePath: string;\n\treadonly name: string;\n\treadonly element: T | undefined;\n\treadonly children: Iterable>;\n\treadonly childrenCount: number;\n\treadonly parent: IResourceNode | undefined;\n\treadonly context: C;\n\tget(childName: string): IResourceNode | undefined;\n}\n\nclass Node implements IResourceNode {\n\n\tprivate _children = new Map>();\n\n\tget childrenCount(): number {\n\t\treturn this._children.size;\n\t}\n\n\tget children(): Iterable> {\n\t\treturn this._children.values();\n\t}\n\n\t@memoize\n\tget name(): string {\n\t\treturn paths.posix.basename(this.relativePath);\n\t}\n\n\tconstructor(\n\t\treadonly uri: URI,\n\t\treadonly relativePath: string,\n\t\treadonly context: C,\n\t\tpublic element: T | undefined = undefined,\n\t\treadonly parent: IResourceNode | undefined = undefined\n\t) { }\n\n\tget(path: string): Node | undefined {\n\t\treturn this._children.get(path);\n\t}\n\n\tset(path: string, child: Node): void {\n\t\tthis._children.set(path, child);\n\t}\n\n\tdelete(path: string): void {\n\t\tthis._children.delete(path);\n\t}\n\n\tclear(): void {\n\t\tthis._children.clear();\n\t}\n}\n\nfunction collect(node: IResourceNode, result: T[]): T[] {\n\tif (typeof node.element !== 'undefined') {\n\t\tresult.push(node.element);\n\t}\n\n\tfor (const child of node.children) {\n\t\tcollect(child, result);\n\t}\n\n\treturn result;\n}\n\nexport class ResourceTree, C> {\n\n\treadonly root: Node;\n\n\tstatic getRoot(node: IResourceNode): IResourceNode {\n\t\twhile (node.parent) {\n\t\t\tnode = node.parent;\n\t\t}\n\n\t\treturn node;\n\t}\n\n\tstatic collect(node: IResourceNode): T[] {\n\t\treturn collect(node, []);\n\t}\n\n\tstatic isResourceNode(obj: any): obj is IResourceNode {\n\t\treturn obj instanceof Node;\n\t}\n\n\tconstructor(context: C, rootURI: URI = URI.file('/'), private extUri: IExtUri = defaultExtUri) {\n\t\tthis.root = new Node(rootURI, '', context);\n\t}\n\n\tadd(uri: URI, element: T): void {\n\t\tconst key = this.extUri.relativePath(this.root.uri, uri) || uri.path;\n\t\tconst iterator = new PathIterator(false).reset(key);\n\t\tlet node = this.root;\n\t\tlet path = '';\n\n\t\twhile (true) {\n\t\t\tconst name = iterator.value();\n\t\t\tpath = path + '/' + name;\n\n\t\t\tlet child = node.get(name);\n\n\t\t\tif (!child) {\n\t\t\t\tchild = new Node(\n\t\t\t\t\tthis.extUri.joinPath(this.root.uri, path),\n\t\t\t\t\tpath,\n\t\t\t\t\tthis.root.context,\n\t\t\t\t\titerator.hasNext() ? undefined : element,\n\t\t\t\t\tnode\n\t\t\t\t);\n\n\t\t\t\tnode.set(name, child);\n\t\t\t} else if (!iterator.hasNext()) {\n\t\t\t\tchild.element = element;\n\t\t\t}\n\n\t\t\tnode = child;\n\n\t\t\tif (!iterator.hasNext()) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\titerator.next();\n\t\t}\n\t}\n\n\tdelete(uri: URI): T | undefined {\n\t\tconst key = this.extUri.relativePath(this.root.uri, uri) || uri.path;\n\t\tconst iterator = new PathIterator(false).reset(key);\n\t\treturn this._delete(this.root, iterator);\n\t}\n\n\tprivate _delete(node: Node, iterator: PathIterator): T | undefined {\n\t\tconst name = iterator.value();\n\t\tconst child = node.get(name);\n\n\t\tif (!child) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (iterator.hasNext()) {\n\t\t\tconst result = this._delete(child, iterator.next());\n\n\t\t\tif (typeof result !== 'undefined' && child.childrenCount === 0) {\n\t\t\t\tnode.delete(name);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\tnode.delete(name);\n\t\treturn child.element;\n\t}\n\n\tclear(): void {\n\t\tthis.root.clear();\n\t}\n\n\tgetNode(uri: URI): IResourceNode | undefined {\n\t\tconst key = this.extUri.relativePath(this.root.uri, uri) || uri.path;\n\t\tconst iterator = new PathIterator(false).reset(key);\n\t\tlet node = this.root;\n\n\t\twhile (true) {\n\t\t\tconst name = iterator.value();\n\t\t\tconst child = node.get(name);\n\n\t\t\tif (!child || !iterator.hasNext()) {\n\t\t\t\treturn child;\n\t\t\t}\n\n\t\t\tnode = child;\n\t\t\titerator.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 { VSBuffer } from 'vs/base/common/buffer';\nimport { MarshalledObject } from 'vs/base/common/marshalling';\nimport { MarshalledId } from 'vs/base/common/marshallingIds';\nimport { URI, UriComponents } from 'vs/base/common/uri';\n\nexport interface IURITransformer {\n\ttransformIncoming(uri: UriComponents): UriComponents;\n\ttransformOutgoing(uri: UriComponents): UriComponents;\n\ttransformOutgoingURI(uri: URI): URI;\n\ttransformOutgoingScheme(scheme: string): string;\n}\n\nexport interface UriParts {\n\tscheme: string;\n\tauthority?: string;\n\tpath?: string;\n\tquery?: string;\n\tfragment?: string;\n}\n\nexport interface IRawURITransformer {\n\ttransformIncoming(uri: UriParts): UriParts;\n\ttransformOutgoing(uri: UriParts): UriParts;\n\ttransformOutgoingScheme(scheme: string): string;\n}\n\nfunction toJSON(uri: URI): UriComponents {\n\treturn uri.toJSON();\n}\n\nexport class URITransformer implements IURITransformer {\n\n\tprivate readonly _uriTransformer: IRawURITransformer;\n\n\tconstructor(uriTransformer: IRawURITransformer) {\n\t\tthis._uriTransformer = uriTransformer;\n\t}\n\n\tpublic transformIncoming(uri: UriComponents): UriComponents {\n\t\tconst result = this._uriTransformer.transformIncoming(uri);\n\t\treturn (result === uri ? uri : toJSON(URI.from(result)));\n\t}\n\n\tpublic transformOutgoing(uri: UriComponents): UriComponents {\n\t\tconst result = this._uriTransformer.transformOutgoing(uri);\n\t\treturn (result === uri ? uri : toJSON(URI.from(result)));\n\t}\n\n\tpublic transformOutgoingURI(uri: URI): URI {\n\t\tconst result = this._uriTransformer.transformOutgoing(uri);\n\t\treturn (result === uri ? uri : URI.from(result));\n\t}\n\n\tpublic transformOutgoingScheme(scheme: string): string {\n\t\treturn this._uriTransformer.transformOutgoingScheme(scheme);\n\t}\n}\n\nexport const DefaultURITransformer: IURITransformer = new class {\n\ttransformIncoming(uri: UriComponents) {\n\t\treturn uri;\n\t}\n\n\ttransformOutgoing(uri: UriComponents): UriComponents {\n\t\treturn uri;\n\t}\n\n\ttransformOutgoingURI(uri: URI): URI {\n\t\treturn uri;\n\t}\n\n\ttransformOutgoingScheme(scheme: string): string {\n\t\treturn scheme;\n\t}\n};\n\nfunction _transformOutgoingURIs(obj: any, transformer: IURITransformer, depth: number): any {\n\n\tif (!obj || depth > 200) {\n\t\treturn null;\n\t}\n\n\tif (typeof obj === 'object') {\n\t\tif (obj instanceof URI) {\n\t\t\treturn transformer.transformOutgoing(obj);\n\t\t}\n\n\t\t// walk object (or array)\n\t\tfor (const key in obj) {\n\t\t\tif (Object.hasOwnProperty.call(obj, key)) {\n\t\t\t\tconst r = _transformOutgoingURIs(obj[key], transformer, depth + 1);\n\t\t\t\tif (r !== null) {\n\t\t\t\t\tobj[key] = r;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn null;\n}\n\nexport function transformOutgoingURIs(obj: T, transformer: IURITransformer): T {\n\tconst result = _transformOutgoingURIs(obj, transformer, 0);\n\tif (result === null) {\n\t\t// no change\n\t\treturn obj;\n\t}\n\treturn result;\n}\n\n\nfunction _transformIncomingURIs(obj: any, transformer: IURITransformer, revive: boolean, depth: number): any {\n\n\tif (!obj || depth > 200) {\n\t\treturn null;\n\t}\n\n\tif (typeof obj === 'object') {\n\n\t\tif ((obj).$mid === MarshalledId.Uri) {\n\t\t\treturn revive ? URI.revive(transformer.transformIncoming(obj)) : transformer.transformIncoming(obj);\n\t\t}\n\n\t\tif (obj instanceof VSBuffer) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// walk object (or array)\n\t\tfor (const key in obj) {\n\t\t\tif (Object.hasOwnProperty.call(obj, key)) {\n\t\t\t\tconst r = _transformIncomingURIs(obj[key], transformer, revive, depth + 1);\n\t\t\t\tif (r !== null) {\n\t\t\t\t\tobj[key] = r;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn null;\n}\n\nexport function transformIncomingURIs(obj: T, transformer: IURITransformer): T {\n\tconst result = _transformIncomingURIs(obj, transformer, false, 0);\n\tif (result === null) {\n\t\t// no change\n\t\treturn obj;\n\t}\n\treturn result;\n}\n\nexport function transformAndReviveIncomingURIs(obj: T, transformer: IURITransformer): T {\n\tconst result = _transformIncomingURIs(obj, transformer, true, 0);\n\tif (result === null) {\n\t\t// no change\n\t\treturn obj;\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 { 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\nexport function createBlobWorker(blobUrl: string, options?: WorkerOptions): Worker {\n\tif (!blobUrl.startsWith('blob:')) {\n\t\tthrow new URIError('Not a blob-url: ' + blobUrl);\n\t}\n\treturn new Worker(ttPolicy ? ttPolicy.createScriptURL(blobUrl) as unknown as string : blobUrl, options);\n}\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 { getRandomElement } from 'vs/base/common/arrays';\nimport { CancelablePromise, createCancelablePromise, timeout } from 'vs/base/common/async';\nimport { VSBuffer } from 'vs/base/common/buffer';\nimport { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';\nimport { memoize } from 'vs/base/common/decorators';\nimport { CancellationError, ErrorNoTelemetry } from 'vs/base/common/errors';\nimport { Emitter, Event, EventMultiplexer, Relay } from 'vs/base/common/event';\nimport { combinedDisposable, DisposableStore, dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle';\nimport { revive } from 'vs/base/common/marshalling';\nimport * as strings from 'vs/base/common/strings';\nimport { isFunction, isUndefinedOrNull } from 'vs/base/common/types';\n\n/**\n * An `IChannel` is an abstraction over a collection of commands.\n * You can `call` several commands on a channel, each taking at\n * most one single argument. A `call` always returns a promise\n * with at most one single return value.\n */\nexport interface IChannel {\n\tcall(command: string, arg?: any, cancellationToken?: CancellationToken): Promise;\n\tlisten(event: string, arg?: any): Event;\n}\n\n/**\n * An `IServerChannel` is the counter part to `IChannel`,\n * on the server-side. You should implement this interface\n * if you'd like to handle remote promises or events.\n */\nexport interface IServerChannel {\n\tcall(ctx: TContext, command: string, arg?: any, cancellationToken?: CancellationToken): Promise;\n\tlisten(ctx: TContext, event: string, arg?: any): Event;\n}\n\nconst enum RequestType {\n\tPromise = 100,\n\tPromiseCancel = 101,\n\tEventListen = 102,\n\tEventDispose = 103\n}\n\nfunction requestTypeToStr(type: RequestType): string {\n\tswitch (type) {\n\t\tcase RequestType.Promise:\n\t\t\treturn 'req';\n\t\tcase RequestType.PromiseCancel:\n\t\t\treturn 'cancel';\n\t\tcase RequestType.EventListen:\n\t\t\treturn 'subscribe';\n\t\tcase RequestType.EventDispose:\n\t\t\treturn 'unsubscribe';\n\t}\n}\n\ntype IRawPromiseRequest = { type: RequestType.Promise; id: number; channelName: string; name: string; arg: any };\ntype IRawPromiseCancelRequest = { type: RequestType.PromiseCancel; id: number };\ntype IRawEventListenRequest = { type: RequestType.EventListen; id: number; channelName: string; name: string; arg: any };\ntype IRawEventDisposeRequest = { type: RequestType.EventDispose; id: number };\ntype IRawRequest = IRawPromiseRequest | IRawPromiseCancelRequest | IRawEventListenRequest | IRawEventDisposeRequest;\n\nconst enum ResponseType {\n\tInitialize = 200,\n\tPromiseSuccess = 201,\n\tPromiseError = 202,\n\tPromiseErrorObj = 203,\n\tEventFire = 204\n}\n\nfunction responseTypeToStr(type: ResponseType): string {\n\tswitch (type) {\n\t\tcase ResponseType.Initialize:\n\t\t\treturn `init`;\n\t\tcase ResponseType.PromiseSuccess:\n\t\t\treturn `reply:`;\n\t\tcase ResponseType.PromiseError:\n\t\tcase ResponseType.PromiseErrorObj:\n\t\t\treturn `replyErr:`;\n\t\tcase ResponseType.EventFire:\n\t\t\treturn `event:`;\n\t}\n}\n\ntype IRawInitializeResponse = { type: ResponseType.Initialize };\ntype IRawPromiseSuccessResponse = { type: ResponseType.PromiseSuccess; id: number; data: any };\ntype IRawPromiseErrorResponse = { type: ResponseType.PromiseError; id: number; data: { message: string; name: string; stack: string[] | undefined } };\ntype IRawPromiseErrorObjResponse = { type: ResponseType.PromiseErrorObj; id: number; data: any };\ntype IRawEventFireResponse = { type: ResponseType.EventFire; id: number; data: any };\ntype IRawResponse = IRawInitializeResponse | IRawPromiseSuccessResponse | IRawPromiseErrorResponse | IRawPromiseErrorObjResponse | IRawEventFireResponse;\n\ninterface IHandler {\n\t(response: IRawResponse): void;\n}\n\nexport interface IMessagePassingProtocol {\n\tsend(buffer: VSBuffer): void;\n\tonMessage: Event;\n\t/**\n\t * Wait for the write buffer (if applicable) to become empty.\n\t */\n\tdrain?(): Promise;\n}\n\nenum State {\n\tUninitialized,\n\tIdle\n}\n\n/**\n * An `IChannelServer` hosts a collection of channels. You are\n * able to register channels onto it, provided a channel name.\n */\nexport interface IChannelServer {\n\tregisterChannel(channelName: string, channel: IServerChannel): void;\n}\n\n/**\n * An `IChannelClient` has access to a collection of channels. You\n * are able to get those channels, given their channel name.\n */\nexport interface IChannelClient {\n\tgetChannel(channelName: string): T;\n}\n\nexport interface Client {\n\treadonly ctx: TContext;\n}\n\nexport interface IConnectionHub {\n\treadonly connections: Connection[];\n\treadonly onDidAddConnection: Event>;\n\treadonly onDidRemoveConnection: Event>;\n}\n\n/**\n * An `IClientRouter` is responsible for routing calls to specific\n * channels, in scenarios in which there are multiple possible\n * channels (each from a separate client) to pick from.\n */\nexport interface IClientRouter {\n\trouteCall(hub: IConnectionHub, command: string, arg?: any, cancellationToken?: CancellationToken): Promise>;\n\trouteEvent(hub: IConnectionHub, event: string, arg?: any): Promise>;\n}\n\n/**\n * Similar to the `IChannelClient`, you can get channels from this\n * collection of channels. The difference being that in the\n * `IRoutingChannelClient`, there are multiple clients providing\n * the same channel. You'll need to pass in an `IClientRouter` in\n * order to pick the right one.\n */\nexport interface IRoutingChannelClient {\n\tgetChannel(channelName: string, router?: IClientRouter): T;\n}\n\ninterface IReader {\n\tread(bytes: number): VSBuffer;\n}\n\ninterface IWriter {\n\twrite(buffer: VSBuffer): void;\n}\n\n\n/**\n * @see https://en.wikipedia.org/wiki/Variable-length_quantity\n */\nfunction readIntVQL(reader: IReader) {\n\tlet value = 0;\n\tfor (let n = 0; ; n += 7) {\n\t\tconst next = reader.read(1);\n\t\tvalue |= (next.buffer[0] & 0b01111111) << n;\n\t\tif (!(next.buffer[0] & 0b10000000)) {\n\t\t\treturn value;\n\t\t}\n\t}\n}\n\nconst vqlZero = createOneByteBuffer(0);\n\n/**\n * @see https://en.wikipedia.org/wiki/Variable-length_quantity\n */\nfunction writeInt32VQL(writer: IWriter, value: number) {\n\tif (value === 0) {\n\t\twriter.write(vqlZero);\n\t\treturn;\n\t}\n\n\tlet len = 0;\n\tfor (let v2 = value; v2 !== 0; v2 = v2 >>> 7) {\n\t\tlen++;\n\t}\n\n\tconst scratch = VSBuffer.alloc(len);\n\tfor (let i = 0; value !== 0; i++) {\n\t\tscratch.buffer[i] = value & 0b01111111;\n\t\tvalue = value >>> 7;\n\t\tif (value > 0) {\n\t\t\tscratch.buffer[i] |= 0b10000000;\n\t\t}\n\t}\n\n\twriter.write(scratch);\n}\n\nexport class BufferReader implements IReader {\n\n\tprivate pos = 0;\n\n\tconstructor(private buffer: VSBuffer) { }\n\n\tread(bytes: number): VSBuffer {\n\t\tconst result = this.buffer.slice(this.pos, this.pos + bytes);\n\t\tthis.pos += result.byteLength;\n\t\treturn result;\n\t}\n}\n\nexport class BufferWriter implements IWriter {\n\n\tprivate buffers: VSBuffer[] = [];\n\n\tget buffer(): VSBuffer {\n\t\treturn VSBuffer.concat(this.buffers);\n\t}\n\n\twrite(buffer: VSBuffer): void {\n\t\tthis.buffers.push(buffer);\n\t}\n}\n\nenum DataType {\n\tUndefined = 0,\n\tString = 1,\n\tBuffer = 2,\n\tVSBuffer = 3,\n\tArray = 4,\n\tObject = 5,\n\tInt = 6\n}\n\nfunction createOneByteBuffer(value: number): VSBuffer {\n\tconst result = VSBuffer.alloc(1);\n\tresult.writeUInt8(value, 0);\n\treturn result;\n}\n\nconst BufferPresets = {\n\tUndefined: createOneByteBuffer(DataType.Undefined),\n\tString: createOneByteBuffer(DataType.String),\n\tBuffer: createOneByteBuffer(DataType.Buffer),\n\tVSBuffer: createOneByteBuffer(DataType.VSBuffer),\n\tArray: createOneByteBuffer(DataType.Array),\n\tObject: createOneByteBuffer(DataType.Object),\n\tUint: createOneByteBuffer(DataType.Int),\n};\n\ndeclare const Buffer: any;\nconst hasBuffer = (typeof Buffer !== 'undefined');\n\nexport function serialize(writer: IWriter, data: any): void {\n\tif (typeof data === 'undefined') {\n\t\twriter.write(BufferPresets.Undefined);\n\t} else if (typeof data === 'string') {\n\t\tconst buffer = VSBuffer.fromString(data);\n\t\twriter.write(BufferPresets.String);\n\t\twriteInt32VQL(writer, buffer.byteLength);\n\t\twriter.write(buffer);\n\t} else if (hasBuffer && Buffer.isBuffer(data)) {\n\t\tconst buffer = VSBuffer.wrap(data);\n\t\twriter.write(BufferPresets.Buffer);\n\t\twriteInt32VQL(writer, buffer.byteLength);\n\t\twriter.write(buffer);\n\t} else if (data instanceof VSBuffer) {\n\t\twriter.write(BufferPresets.VSBuffer);\n\t\twriteInt32VQL(writer, data.byteLength);\n\t\twriter.write(data);\n\t} else if (Array.isArray(data)) {\n\t\twriter.write(BufferPresets.Array);\n\t\twriteInt32VQL(writer, data.length);\n\n\t\tfor (const el of data) {\n\t\t\tserialize(writer, el);\n\t\t}\n\t} else if (typeof data === 'number' && (data | 0) === data) {\n\t\t// write a vql if it's a number that we can do bitwise operations on\n\t\twriter.write(BufferPresets.Uint);\n\t\twriteInt32VQL(writer, data);\n\t} else {\n\t\tconst buffer = VSBuffer.fromString(JSON.stringify(data));\n\t\twriter.write(BufferPresets.Object);\n\t\twriteInt32VQL(writer, buffer.byteLength);\n\t\twriter.write(buffer);\n\t}\n}\n\nexport function deserialize(reader: IReader): any {\n\tconst type = reader.read(1).readUInt8(0);\n\n\tswitch (type) {\n\t\tcase DataType.Undefined: return undefined;\n\t\tcase DataType.String: return reader.read(readIntVQL(reader)).toString();\n\t\tcase DataType.Buffer: return reader.read(readIntVQL(reader)).buffer;\n\t\tcase DataType.VSBuffer: return reader.read(readIntVQL(reader));\n\t\tcase DataType.Array: {\n\t\t\tconst length = readIntVQL(reader);\n\t\t\tconst result: any[] = [];\n\n\t\t\tfor (let i = 0; i < length; i++) {\n\t\t\t\tresult.push(deserialize(reader));\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t\tcase DataType.Object: return JSON.parse(reader.read(readIntVQL(reader)).toString());\n\t\tcase DataType.Int: return readIntVQL(reader);\n\t}\n}\n\ninterface PendingRequest {\n\trequest: IRawPromiseRequest | IRawEventListenRequest;\n\ttimeoutTimer: any;\n}\n\nexport class ChannelServer implements IChannelServer, IDisposable {\n\n\tprivate channels = new Map>();\n\tprivate activeRequests = new Map();\n\tprivate protocolListener: IDisposable | null;\n\n\t// Requests might come in for channels which are not yet registered.\n\t// They will timeout after `timeoutDelay`.\n\tprivate pendingRequests = new Map();\n\n\tconstructor(private protocol: IMessagePassingProtocol, private ctx: TContext, private logger: IIPCLogger | null = null, private timeoutDelay: number = 1000) {\n\t\tthis.protocolListener = this.protocol.onMessage(msg => this.onRawMessage(msg));\n\t\tthis.sendResponse({ type: ResponseType.Initialize });\n\t}\n\n\tregisterChannel(channelName: string, channel: IServerChannel): void {\n\t\tthis.channels.set(channelName, channel);\n\n\t\t// https://github.com/microsoft/vscode/issues/72531\n\t\tsetTimeout(() => this.flushPendingRequests(channelName), 0);\n\t}\n\n\tprivate sendResponse(response: IRawResponse): void {\n\t\tswitch (response.type) {\n\t\t\tcase ResponseType.Initialize: {\n\t\t\t\tconst msgLength = this.send([response.type]);\n\t\t\t\tthis.logger?.logOutgoing(msgLength, 0, RequestInitiator.OtherSide, responseTypeToStr(response.type));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tcase ResponseType.PromiseSuccess:\n\t\t\tcase ResponseType.PromiseError:\n\t\t\tcase ResponseType.EventFire:\n\t\t\tcase ResponseType.PromiseErrorObj: {\n\t\t\t\tconst msgLength = this.send([response.type, response.id], response.data);\n\t\t\t\tthis.logger?.logOutgoing(msgLength, response.id, RequestInitiator.OtherSide, responseTypeToStr(response.type), response.data);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate send(header: any, body: any = undefined): number {\n\t\tconst writer = new BufferWriter();\n\t\tserialize(writer, header);\n\t\tserialize(writer, body);\n\t\treturn this.sendBuffer(writer.buffer);\n\t}\n\n\tprivate sendBuffer(message: VSBuffer): number {\n\t\ttry {\n\t\t\tthis.protocol.send(message);\n\t\t\treturn message.byteLength;\n\t\t} catch (err) {\n\t\t\t// noop\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tprivate onRawMessage(message: VSBuffer): void {\n\t\tconst reader = new BufferReader(message);\n\t\tconst header = deserialize(reader);\n\t\tconst body = deserialize(reader);\n\t\tconst type = header[0] as RequestType;\n\n\t\tswitch (type) {\n\t\t\tcase RequestType.Promise:\n\t\t\t\tthis.logger?.logIncoming(message.byteLength, header[1], RequestInitiator.OtherSide, `${requestTypeToStr(type)}: ${header[2]}.${header[3]}`, body);\n\t\t\t\treturn this.onPromise({ type, id: header[1], channelName: header[2], name: header[3], arg: body });\n\t\t\tcase RequestType.EventListen:\n\t\t\t\tthis.logger?.logIncoming(message.byteLength, header[1], RequestInitiator.OtherSide, `${requestTypeToStr(type)}: ${header[2]}.${header[3]}`, body);\n\t\t\t\treturn this.onEventListen({ type, id: header[1], channelName: header[2], name: header[3], arg: body });\n\t\t\tcase RequestType.PromiseCancel:\n\t\t\t\tthis.logger?.logIncoming(message.byteLength, header[1], RequestInitiator.OtherSide, `${requestTypeToStr(type)}`);\n\t\t\t\treturn this.disposeActiveRequest({ type, id: header[1] });\n\t\t\tcase RequestType.EventDispose:\n\t\t\t\tthis.logger?.logIncoming(message.byteLength, header[1], RequestInitiator.OtherSide, `${requestTypeToStr(type)}`);\n\t\t\t\treturn this.disposeActiveRequest({ type, id: header[1] });\n\t\t}\n\t}\n\n\tprivate onPromise(request: IRawPromiseRequest): void {\n\t\tconst channel = this.channels.get(request.channelName);\n\n\t\tif (!channel) {\n\t\t\tthis.collectPendingRequest(request);\n\t\t\treturn;\n\t\t}\n\n\t\tconst cancellationTokenSource = new CancellationTokenSource();\n\t\tlet promise: Promise;\n\n\t\ttry {\n\t\t\tpromise = channel.call(this.ctx, request.name, request.arg, cancellationTokenSource.token);\n\t\t} catch (err) {\n\t\t\tpromise = Promise.reject(err);\n\t\t}\n\n\t\tconst id = request.id;\n\n\t\tpromise.then(data => {\n\t\t\tthis.sendResponse({ id, data, type: ResponseType.PromiseSuccess });\n\t\t}, err => {\n\t\t\tif (err instanceof Error) {\n\t\t\t\tthis.sendResponse({\n\t\t\t\t\tid, data: {\n\t\t\t\t\t\tmessage: err.message,\n\t\t\t\t\t\tname: err.name,\n\t\t\t\t\t\tstack: err.stack ? (err.stack.split ? err.stack.split('\\n') : err.stack) : undefined\n\t\t\t\t\t}, type: ResponseType.PromiseError\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tthis.sendResponse({ id, data: err, type: ResponseType.PromiseErrorObj });\n\t\t\t}\n\t\t}).finally(() => {\n\t\t\tdisposable.dispose();\n\t\t\tthis.activeRequests.delete(request.id);\n\t\t});\n\n\t\tconst disposable = toDisposable(() => cancellationTokenSource.cancel());\n\t\tthis.activeRequests.set(request.id, disposable);\n\t}\n\n\tprivate onEventListen(request: IRawEventListenRequest): void {\n\t\tconst channel = this.channels.get(request.channelName);\n\n\t\tif (!channel) {\n\t\t\tthis.collectPendingRequest(request);\n\t\t\treturn;\n\t\t}\n\n\t\tconst id = request.id;\n\t\tconst event = channel.listen(this.ctx, request.name, request.arg);\n\t\tconst disposable = event(data => this.sendResponse({ id, data, type: ResponseType.EventFire }));\n\n\t\tthis.activeRequests.set(request.id, disposable);\n\t}\n\n\tprivate disposeActiveRequest(request: IRawRequest): void {\n\t\tconst disposable = this.activeRequests.get(request.id);\n\n\t\tif (disposable) {\n\t\t\tdisposable.dispose();\n\t\t\tthis.activeRequests.delete(request.id);\n\t\t}\n\t}\n\n\tprivate collectPendingRequest(request: IRawPromiseRequest | IRawEventListenRequest): void {\n\t\tlet pendingRequests = this.pendingRequests.get(request.channelName);\n\n\t\tif (!pendingRequests) {\n\t\t\tpendingRequests = [];\n\t\t\tthis.pendingRequests.set(request.channelName, pendingRequests);\n\t\t}\n\n\t\tconst timer = setTimeout(() => {\n\t\t\tconsole.error(`Unknown channel: ${request.channelName}`);\n\n\t\t\tif (request.type === RequestType.Promise) {\n\t\t\t\tthis.sendResponse({\n\t\t\t\t\tid: request.id,\n\t\t\t\t\tdata: { name: 'Unknown channel', message: `Channel name '${request.channelName}' timed out after ${this.timeoutDelay}ms`, stack: undefined },\n\t\t\t\t\ttype: ResponseType.PromiseError\n\t\t\t\t});\n\t\t\t}\n\t\t}, this.timeoutDelay);\n\n\t\tpendingRequests.push({ request, timeoutTimer: timer });\n\t}\n\n\tprivate flushPendingRequests(channelName: string): void {\n\t\tconst requests = this.pendingRequests.get(channelName);\n\n\t\tif (requests) {\n\t\t\tfor (const request of requests) {\n\t\t\t\tclearTimeout(request.timeoutTimer);\n\n\t\t\t\tswitch (request.request.type) {\n\t\t\t\t\tcase RequestType.Promise: this.onPromise(request.request); break;\n\t\t\t\t\tcase RequestType.EventListen: this.onEventListen(request.request); break;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.pendingRequests.delete(channelName);\n\t\t}\n\t}\n\n\tpublic dispose(): void {\n\t\tif (this.protocolListener) {\n\t\t\tthis.protocolListener.dispose();\n\t\t\tthis.protocolListener = null;\n\t\t}\n\t\tdispose(this.activeRequests.values());\n\t\tthis.activeRequests.clear();\n\t}\n}\n\nexport const enum RequestInitiator {\n\tLocalSide = 0,\n\tOtherSide = 1\n}\n\nexport interface IIPCLogger {\n\tlogIncoming(msgLength: number, requestId: number, initiator: RequestInitiator, str: string, data?: any): void;\n\tlogOutgoing(msgLength: number, requestId: number, initiator: RequestInitiator, str: string, data?: any): void;\n}\n\nexport class ChannelClient implements IChannelClient, IDisposable {\n\n\tprivate isDisposed: boolean = false;\n\tprivate state: State = State.Uninitialized;\n\tprivate activeRequests = new Set();\n\tprivate handlers = new Map();\n\tprivate lastRequestId: number = 0;\n\tprivate protocolListener: IDisposable | null;\n\tprivate logger: IIPCLogger | null;\n\n\tprivate readonly _onDidInitialize = new Emitter();\n\treadonly onDidInitialize = this._onDidInitialize.event;\n\n\tconstructor(private protocol: IMessagePassingProtocol, logger: IIPCLogger | null = null) {\n\t\tthis.protocolListener = this.protocol.onMessage(msg => this.onBuffer(msg));\n\t\tthis.logger = logger;\n\t}\n\n\tgetChannel(channelName: string): T {\n\t\tconst that = this;\n\n\t\treturn {\n\t\t\tcall(command: string, arg?: any, cancellationToken?: CancellationToken) {\n\t\t\t\tif (that.isDisposed) {\n\t\t\t\t\treturn Promise.reject(new CancellationError());\n\t\t\t\t}\n\t\t\t\treturn that.requestPromise(channelName, command, arg, cancellationToken);\n\t\t\t},\n\t\t\tlisten(event: string, arg: any) {\n\t\t\t\tif (that.isDisposed) {\n\t\t\t\t\treturn Event.None;\n\t\t\t\t}\n\t\t\t\treturn that.requestEvent(channelName, event, arg);\n\t\t\t}\n\t\t} as T;\n\t}\n\n\tprivate requestPromise(channelName: string, name: string, arg?: any, cancellationToken = CancellationToken.None): Promise {\n\t\tconst id = this.lastRequestId++;\n\t\tconst type = RequestType.Promise;\n\t\tconst request: IRawRequest = { id, type, channelName, name, arg };\n\n\t\tif (cancellationToken.isCancellationRequested) {\n\t\t\treturn Promise.reject(new CancellationError());\n\t\t}\n\n\t\tlet disposable: IDisposable;\n\n\t\tconst result = new Promise((c, e) => {\n\t\t\tif (cancellationToken.isCancellationRequested) {\n\t\t\t\treturn e(new CancellationError());\n\t\t\t}\n\n\t\t\tconst doRequest = () => {\n\t\t\t\tconst handler: IHandler = response => {\n\t\t\t\t\tswitch (response.type) {\n\t\t\t\t\t\tcase ResponseType.PromiseSuccess:\n\t\t\t\t\t\t\tthis.handlers.delete(id);\n\t\t\t\t\t\t\tc(response.data);\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase ResponseType.PromiseError: {\n\t\t\t\t\t\t\tthis.handlers.delete(id);\n\t\t\t\t\t\t\tconst error = new Error(response.data.message);\n\t\t\t\t\t\t\t(error).stack = Array.isArray(response.data.stack) ? response.data.stack.join('\\n') : response.data.stack;\n\t\t\t\t\t\t\terror.name = response.data.name;\n\t\t\t\t\t\t\te(error);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcase ResponseType.PromiseErrorObj:\n\t\t\t\t\t\t\tthis.handlers.delete(id);\n\t\t\t\t\t\t\te(response.data);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\tthis.handlers.set(id, handler);\n\t\t\t\tthis.sendRequest(request);\n\t\t\t};\n\n\t\t\tlet uninitializedPromise: CancelablePromise | null = null;\n\t\t\tif (this.state === State.Idle) {\n\t\t\t\tdoRequest();\n\t\t\t} else {\n\t\t\t\tuninitializedPromise = createCancelablePromise(_ => this.whenInitialized());\n\t\t\t\tuninitializedPromise.then(() => {\n\t\t\t\t\tuninitializedPromise = null;\n\t\t\t\t\tdoRequest();\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst cancel = () => {\n\t\t\t\tif (uninitializedPromise) {\n\t\t\t\t\tuninitializedPromise.cancel();\n\t\t\t\t\tuninitializedPromise = null;\n\t\t\t\t} else {\n\t\t\t\t\tthis.sendRequest({ id, type: RequestType.PromiseCancel });\n\t\t\t\t}\n\n\t\t\t\te(new CancellationError());\n\t\t\t};\n\n\t\t\tconst cancellationTokenListener = cancellationToken.onCancellationRequested(cancel);\n\t\t\tdisposable = combinedDisposable(toDisposable(cancel), cancellationTokenListener);\n\t\t\tthis.activeRequests.add(disposable);\n\t\t});\n\n\t\treturn result.finally(() => {\n\t\t\tdisposable.dispose();\n\t\t\tthis.activeRequests.delete(disposable);\n\t\t});\n\t}\n\n\tprivate requestEvent(channelName: string, name: string, arg?: any): Event {\n\t\tconst id = this.lastRequestId++;\n\t\tconst type = RequestType.EventListen;\n\t\tconst request: IRawRequest = { id, type, channelName, name, arg };\n\n\t\tlet uninitializedPromise: CancelablePromise | null = null;\n\n\t\tconst emitter = new Emitter({\n\t\t\tonWillAddFirstListener: () => {\n\t\t\t\tuninitializedPromise = createCancelablePromise(_ => this.whenInitialized());\n\t\t\t\tuninitializedPromise.then(() => {\n\t\t\t\t\tuninitializedPromise = null;\n\t\t\t\t\tthis.activeRequests.add(emitter);\n\t\t\t\t\tthis.sendRequest(request);\n\t\t\t\t});\n\t\t\t},\n\t\t\tonDidRemoveLastListener: () => {\n\t\t\t\tif (uninitializedPromise) {\n\t\t\t\t\tuninitializedPromise.cancel();\n\t\t\t\t\tuninitializedPromise = null;\n\t\t\t\t} else {\n\t\t\t\t\tthis.activeRequests.delete(emitter);\n\t\t\t\t\tthis.sendRequest({ id, type: RequestType.EventDispose });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tconst handler: IHandler = (res: IRawResponse) => emitter.fire((res as IRawEventFireResponse).data);\n\t\tthis.handlers.set(id, handler);\n\n\t\treturn emitter.event;\n\t}\n\n\tprivate sendRequest(request: IRawRequest): void {\n\t\tswitch (request.type) {\n\t\t\tcase RequestType.Promise:\n\t\t\tcase RequestType.EventListen: {\n\t\t\t\tconst msgLength = this.send([request.type, request.id, request.channelName, request.name], request.arg);\n\t\t\t\tthis.logger?.logOutgoing(msgLength, request.id, RequestInitiator.LocalSide, `${requestTypeToStr(request.type)}: ${request.channelName}.${request.name}`, request.arg);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tcase RequestType.PromiseCancel:\n\t\t\tcase RequestType.EventDispose: {\n\t\t\t\tconst msgLength = this.send([request.type, request.id]);\n\t\t\t\tthis.logger?.logOutgoing(msgLength, request.id, RequestInitiator.LocalSide, requestTypeToStr(request.type));\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate send(header: any, body: any = undefined): number {\n\t\tconst writer = new BufferWriter();\n\t\tserialize(writer, header);\n\t\tserialize(writer, body);\n\t\treturn this.sendBuffer(writer.buffer);\n\t}\n\n\tprivate sendBuffer(message: VSBuffer): number {\n\t\ttry {\n\t\t\tthis.protocol.send(message);\n\t\t\treturn message.byteLength;\n\t\t} catch (err) {\n\t\t\t// noop\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tprivate onBuffer(message: VSBuffer): void {\n\t\tconst reader = new BufferReader(message);\n\t\tconst header = deserialize(reader);\n\t\tconst body = deserialize(reader);\n\t\tconst type: ResponseType = header[0];\n\n\t\tswitch (type) {\n\t\t\tcase ResponseType.Initialize:\n\t\t\t\tthis.logger?.logIncoming(message.byteLength, 0, RequestInitiator.LocalSide, responseTypeToStr(type));\n\t\t\t\treturn this.onResponse({ type: header[0] });\n\n\t\t\tcase ResponseType.PromiseSuccess:\n\t\t\tcase ResponseType.PromiseError:\n\t\t\tcase ResponseType.EventFire:\n\t\t\tcase ResponseType.PromiseErrorObj:\n\t\t\t\tthis.logger?.logIncoming(message.byteLength, header[1], RequestInitiator.LocalSide, responseTypeToStr(type), body);\n\t\t\t\treturn this.onResponse({ type: header[0], id: header[1], data: body });\n\t\t}\n\t}\n\n\tprivate onResponse(response: IRawResponse): void {\n\t\tif (response.type === ResponseType.Initialize) {\n\t\t\tthis.state = State.Idle;\n\t\t\tthis._onDidInitialize.fire();\n\t\t\treturn;\n\t\t}\n\n\t\tconst handler = this.handlers.get(response.id);\n\n\t\thandler?.(response);\n\t}\n\n\t@memoize\n\tget onDidInitializePromise(): Promise {\n\t\treturn Event.toPromise(this.onDidInitialize);\n\t}\n\n\tprivate whenInitialized(): Promise {\n\t\tif (this.state === State.Idle) {\n\t\t\treturn Promise.resolve();\n\t\t} else {\n\t\t\treturn this.onDidInitializePromise;\n\t\t}\n\t}\n\n\tdispose(): void {\n\t\tthis.isDisposed = true;\n\t\tif (this.protocolListener) {\n\t\t\tthis.protocolListener.dispose();\n\t\t\tthis.protocolListener = null;\n\t\t}\n\t\tdispose(this.activeRequests.values());\n\t\tthis.activeRequests.clear();\n\t}\n}\n\nexport interface ClientConnectionEvent {\n\tprotocol: IMessagePassingProtocol;\n\tonDidClientDisconnect: Event;\n}\n\ninterface Connection extends Client {\n\treadonly channelServer: ChannelServer;\n\treadonly channelClient: ChannelClient;\n}\n\n/**\n * An `IPCServer` is both a channel server and a routing channel\n * client.\n *\n * As the owner of a protocol, you should extend both this\n * and the `IPCClient` classes to get IPC implementations\n * for your protocol.\n */\nexport class IPCServer implements IChannelServer, IRoutingChannelClient, IConnectionHub, IDisposable {\n\n\tprivate channels = new Map>();\n\tprivate _connections = new Set>();\n\n\tprivate readonly _onDidAddConnection = new Emitter>();\n\treadonly onDidAddConnection: Event> = this._onDidAddConnection.event;\n\n\tprivate readonly _onDidRemoveConnection = new Emitter>();\n\treadonly onDidRemoveConnection: Event> = this._onDidRemoveConnection.event;\n\n\tprivate readonly disposables = new DisposableStore();\n\n\tget connections(): Connection[] {\n\t\tconst result: Connection[] = [];\n\t\tthis._connections.forEach(ctx => result.push(ctx));\n\t\treturn result;\n\t}\n\n\tconstructor(onDidClientConnect: Event) {\n\t\tthis.disposables.add(onDidClientConnect(({ protocol, onDidClientDisconnect }) => {\n\t\t\tconst onFirstMessage = Event.once(protocol.onMessage);\n\n\t\t\tthis.disposables.add(onFirstMessage(msg => {\n\t\t\t\tconst reader = new BufferReader(msg);\n\t\t\t\tconst ctx = deserialize(reader) as TContext;\n\n\t\t\t\tconst channelServer = new ChannelServer(protocol, ctx);\n\t\t\t\tconst channelClient = new ChannelClient(protocol);\n\n\t\t\t\tthis.channels.forEach((channel, name) => channelServer.registerChannel(name, channel));\n\n\t\t\t\tconst connection: Connection = { channelServer, channelClient, ctx };\n\t\t\t\tthis._connections.add(connection);\n\t\t\t\tthis._onDidAddConnection.fire(connection);\n\n\t\t\t\tthis.disposables.add(onDidClientDisconnect(() => {\n\t\t\t\t\tchannelServer.dispose();\n\t\t\t\t\tchannelClient.dispose();\n\t\t\t\t\tthis._connections.delete(connection);\n\t\t\t\t\tthis._onDidRemoveConnection.fire(connection);\n\t\t\t\t}));\n\t\t\t}));\n\t\t}));\n\t}\n\n\t/**\n\t * Get a channel from a remote client. When passed a router,\n\t * one can specify which client it wants to call and listen to/from.\n\t * Otherwise, when calling without a router, a random client will\n\t * be selected and when listening without a router, every client\n\t * will be listened to.\n\t */\n\tgetChannel(channelName: string, router: IClientRouter): T;\n\tgetChannel(channelName: string, clientFilter: (client: Client) => boolean): T;\n\tgetChannel(channelName: string, routerOrClientFilter: IClientRouter | ((client: Client) => boolean)): T {\n\t\tconst that = this;\n\n\t\treturn {\n\t\t\tcall(command: string, arg?: any, cancellationToken?: CancellationToken): Promise {\n\t\t\t\tlet connectionPromise: Promise>;\n\n\t\t\t\tif (isFunction(routerOrClientFilter)) {\n\t\t\t\t\t// when no router is provided, we go random client picking\n\t\t\t\t\tconst connection = getRandomElement(that.connections.filter(routerOrClientFilter));\n\n\t\t\t\t\tconnectionPromise = connection\n\t\t\t\t\t\t// if we found a client, let's call on it\n\t\t\t\t\t\t? Promise.resolve(connection)\n\t\t\t\t\t\t// else, let's wait for a client to come along\n\t\t\t\t\t\t: Event.toPromise(Event.filter(that.onDidAddConnection, routerOrClientFilter));\n\t\t\t\t} else {\n\t\t\t\t\tconnectionPromise = routerOrClientFilter.routeCall(that, command, arg);\n\t\t\t\t}\n\n\t\t\t\tconst channelPromise = connectionPromise\n\t\t\t\t\t.then(connection => (connection as Connection).channelClient.getChannel(channelName));\n\n\t\t\t\treturn getDelayedChannel(channelPromise)\n\t\t\t\t\t.call(command, arg, cancellationToken);\n\t\t\t},\n\t\t\tlisten(event: string, arg: any): Event {\n\t\t\t\tif (isFunction(routerOrClientFilter)) {\n\t\t\t\t\treturn that.getMulticastEvent(channelName, routerOrClientFilter, event, arg);\n\t\t\t\t}\n\n\t\t\t\tconst channelPromise = routerOrClientFilter.routeEvent(that, event, arg)\n\t\t\t\t\t.then(connection => (connection as Connection).channelClient.getChannel(channelName));\n\n\t\t\t\treturn getDelayedChannel(channelPromise)\n\t\t\t\t\t.listen(event, arg);\n\t\t\t}\n\t\t} as T;\n\t}\n\n\tprivate getMulticastEvent(channelName: string, clientFilter: (client: Client) => boolean, eventName: string, arg: any): Event {\n\t\tconst that = this;\n\t\tlet disposables: DisposableStore | undefined;\n\n\t\t// Create an emitter which hooks up to all clients\n\t\t// as soon as first listener is added. It also\n\t\t// disconnects from all clients as soon as the last listener\n\t\t// is removed.\n\t\tconst emitter = new Emitter({\n\t\t\tonWillAddFirstListener: () => {\n\t\t\t\tdisposables = new DisposableStore();\n\n\t\t\t\t// The event multiplexer is useful since the active\n\t\t\t\t// client list is dynamic. We need to hook up and disconnection\n\t\t\t\t// to/from clients as they come and go.\n\t\t\t\tconst eventMultiplexer = new EventMultiplexer();\n\t\t\t\tconst map = new Map, IDisposable>();\n\n\t\t\t\tconst onDidAddConnection = (connection: Connection) => {\n\t\t\t\t\tconst channel = connection.channelClient.getChannel(channelName);\n\t\t\t\t\tconst event = channel.listen(eventName, arg);\n\t\t\t\t\tconst disposable = eventMultiplexer.add(event);\n\n\t\t\t\t\tmap.set(connection, disposable);\n\t\t\t\t};\n\n\t\t\t\tconst onDidRemoveConnection = (connection: Connection) => {\n\t\t\t\t\tconst disposable = map.get(connection);\n\n\t\t\t\t\tif (!disposable) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tdisposable.dispose();\n\t\t\t\t\tmap.delete(connection);\n\t\t\t\t};\n\n\t\t\t\tthat.connections.filter(clientFilter).forEach(onDidAddConnection);\n\t\t\t\tEvent.filter(that.onDidAddConnection, clientFilter)(onDidAddConnection, undefined, disposables);\n\t\t\t\tthat.onDidRemoveConnection(onDidRemoveConnection, undefined, disposables);\n\t\t\t\teventMultiplexer.event(emitter.fire, emitter, disposables);\n\n\t\t\t\tdisposables.add(eventMultiplexer);\n\t\t\t},\n\t\t\tonDidRemoveLastListener: () => {\n\t\t\t\tdisposables?.dispose();\n\t\t\t\tdisposables = undefined;\n\t\t\t}\n\t\t});\n\n\t\treturn emitter.event;\n\t}\n\n\tregisterChannel(channelName: string, channel: IServerChannel): void {\n\t\tthis.channels.set(channelName, channel);\n\n\t\tfor (const connection of this._connections) {\n\t\t\tconnection.channelServer.registerChannel(channelName, channel);\n\t\t}\n\t}\n\n\tdispose(): void {\n\t\tthis.disposables.dispose();\n\n\t\tfor (const connection of this._connections) {\n\t\t\tconnection.channelClient.dispose();\n\t\t\tconnection.channelServer.dispose();\n\t\t}\n\n\t\tthis._connections.clear();\n\t\tthis.channels.clear();\n\t\tthis._onDidAddConnection.dispose();\n\t\tthis._onDidRemoveConnection.dispose();\n\t}\n}\n\n/**\n * An `IPCClient` is both a channel client and a channel server.\n *\n * As the owner of a protocol, you should extend both this\n * and the `IPCServer` classes to get IPC implementations\n * for your protocol.\n */\nexport class IPCClient implements IChannelClient, IChannelServer, IDisposable {\n\n\tprivate channelClient: ChannelClient;\n\tprivate channelServer: ChannelServer;\n\n\tconstructor(protocol: IMessagePassingProtocol, ctx: TContext, ipcLogger: IIPCLogger | null = null) {\n\t\tconst writer = new BufferWriter();\n\t\tserialize(writer, ctx);\n\t\tprotocol.send(writer.buffer);\n\n\t\tthis.channelClient = new ChannelClient(protocol, ipcLogger);\n\t\tthis.channelServer = new ChannelServer(protocol, ctx, ipcLogger);\n\t}\n\n\tgetChannel(channelName: string): T {\n\t\treturn this.channelClient.getChannel(channelName) as T;\n\t}\n\n\tregisterChannel(channelName: string, channel: IServerChannel): void {\n\t\tthis.channelServer.registerChannel(channelName, channel);\n\t}\n\n\tdispose(): void {\n\t\tthis.channelClient.dispose();\n\t\tthis.channelServer.dispose();\n\t}\n}\n\nexport function getDelayedChannel(promise: Promise): T {\n\treturn {\n\t\tcall(command: string, arg?: any, cancellationToken?: CancellationToken): Promise {\n\t\t\treturn promise.then(c => c.call(command, arg, cancellationToken));\n\t\t},\n\n\t\tlisten(event: string, arg?: any): Event {\n\t\t\tconst relay = new Relay();\n\t\t\tpromise.then(c => relay.input = c.listen(event, arg));\n\t\t\treturn relay.event;\n\t\t}\n\t} as T;\n}\n\nexport function getNextTickChannel(channel: T): T {\n\tlet didTick = false;\n\n\treturn {\n\t\tcall(command: string, arg?: any, cancellationToken?: CancellationToken): Promise {\n\t\t\tif (didTick) {\n\t\t\t\treturn channel.call(command, arg, cancellationToken);\n\t\t\t}\n\n\t\t\treturn timeout(0)\n\t\t\t\t.then(() => didTick = true)\n\t\t\t\t.then(() => channel.call(command, arg, cancellationToken));\n\t\t},\n\t\tlisten(event: string, arg?: any): Event {\n\t\t\tif (didTick) {\n\t\t\t\treturn channel.listen(event, arg);\n\t\t\t}\n\n\t\t\tconst relay = new Relay();\n\n\t\t\ttimeout(0)\n\t\t\t\t.then(() => didTick = true)\n\t\t\t\t.then(() => relay.input = channel.listen(event, arg));\n\n\t\t\treturn relay.event;\n\t\t}\n\t} as T;\n}\n\nexport class StaticRouter implements IClientRouter {\n\n\tconstructor(private fn: (ctx: TContext) => boolean | Promise) { }\n\n\trouteCall(hub: IConnectionHub): Promise> {\n\t\treturn this.route(hub);\n\t}\n\n\trouteEvent(hub: IConnectionHub): Promise> {\n\t\treturn this.route(hub);\n\t}\n\n\tprivate async route(hub: IConnectionHub): Promise> {\n\t\tfor (const connection of hub.connections) {\n\t\t\tif (await Promise.resolve(this.fn(connection.ctx))) {\n\t\t\t\treturn Promise.resolve(connection);\n\t\t\t}\n\t\t}\n\n\t\tawait Event.toPromise(hub.onDidAddConnection);\n\t\treturn await this.route(hub);\n\t}\n}\n\n/**\n * Use ProxyChannels to automatically wrapping and unwrapping\n * services to/from IPC channels, instead of manually wrapping\n * each service method and event.\n *\n * Restrictions:\n * - If marshalling is enabled, only `URI` and `RegExp` is converted\n * automatically for you\n * - Events must follow the naming convention `onUpperCase`\n * - `CancellationToken` is currently not supported\n * - If a context is provided, you can use `AddFirstParameterToFunctions`\n * utility to signal this in the receiving side type\n */\nexport namespace ProxyChannel {\n\n\texport interface IProxyOptions {\n\n\t\t/**\n\t\t * Disables automatic marshalling of `URI`.\n\t\t * If marshalling is disabled, `UriComponents`\n\t\t * must be used instead.\n\t\t */\n\t\tdisableMarshalling?: boolean;\n\t}\n\n\texport interface ICreateServiceChannelOptions extends IProxyOptions { }\n\n\texport function fromService(service: unknown, disposables: DisposableStore, options?: ICreateServiceChannelOptions): IServerChannel {\n\t\tconst handler = service as { [key: string]: unknown };\n\t\tconst disableMarshalling = options && options.disableMarshalling;\n\n\t\t// Buffer any event that should be supported by\n\t\t// iterating over all property keys and finding them\n\t\tconst mapEventNameToEvent = new Map>();\n\t\tfor (const key in handler) {\n\t\t\tif (propertyIsEvent(key)) {\n\t\t\t\tmapEventNameToEvent.set(key, Event.buffer(handler[key] as Event, true, undefined, disposables));\n\t\t\t}\n\t\t}\n\n\t\treturn new class implements IServerChannel {\n\n\t\t\tlisten(_: unknown, event: string, arg: any): Event {\n\t\t\t\tconst eventImpl = mapEventNameToEvent.get(event);\n\t\t\t\tif (eventImpl) {\n\t\t\t\t\treturn eventImpl as Event;\n\t\t\t\t}\n\n\t\t\t\tif (propertyIsDynamicEvent(event)) {\n\t\t\t\t\tconst target = handler[event];\n\t\t\t\t\tif (typeof target === 'function') {\n\t\t\t\t\t\treturn target.call(handler, arg);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tthrow new ErrorNoTelemetry(`Event not found: ${event}`);\n\t\t\t}\n\n\t\t\tcall(_: unknown, command: string, args?: any[]): Promise {\n\t\t\t\tconst target = handler[command];\n\t\t\t\tif (typeof target === 'function') {\n\n\t\t\t\t\t// Revive unless marshalling disabled\n\t\t\t\t\tif (!disableMarshalling && Array.isArray(args)) {\n\t\t\t\t\t\tfor (let i = 0; i < args.length; i++) {\n\t\t\t\t\t\t\targs[i] = revive(args[i]);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tlet res = target.apply(handler, args);\n\t\t\t\t\tif (!(res instanceof Promise)) {\n\t\t\t\t\t\tres = Promise.resolve(res);\n\t\t\t\t\t}\n\t\t\t\t\treturn res;\n\t\t\t\t}\n\n\t\t\t\tthrow new ErrorNoTelemetry(`Method not found: ${command}`);\n\t\t\t}\n\t\t};\n\t}\n\n\texport interface ICreateProxyServiceOptions extends IProxyOptions {\n\n\t\t/**\n\t\t * If provided, will add the value of `context`\n\t\t * to each method call to the target.\n\t\t */\n\t\tcontext?: unknown;\n\n\t\t/**\n\t\t * If provided, will not proxy any of the properties\n\t\t * that are part of the Map but rather return that value.\n\t\t */\n\t\tproperties?: Map;\n\t}\n\n\texport function toService(channel: IChannel, options?: ICreateProxyServiceOptions): T {\n\t\tconst disableMarshalling = options && options.disableMarshalling;\n\n\t\treturn new Proxy({}, {\n\t\t\tget(_target: T, propKey: PropertyKey) {\n\t\t\t\tif (typeof propKey === 'string') {\n\n\t\t\t\t\t// Check for predefined values\n\t\t\t\t\tif (options?.properties?.has(propKey)) {\n\t\t\t\t\t\treturn options.properties.get(propKey);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Dynamic Event\n\t\t\t\t\tif (propertyIsDynamicEvent(propKey)) {\n\t\t\t\t\t\treturn function (arg: any) {\n\t\t\t\t\t\t\treturn channel.listen(propKey, arg);\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\t// Event\n\t\t\t\t\tif (propertyIsEvent(propKey)) {\n\t\t\t\t\t\treturn channel.listen(propKey);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Function\n\t\t\t\t\treturn async function (...args: any[]) {\n\n\t\t\t\t\t\t// Add context if any\n\t\t\t\t\t\tlet methodArgs: any[];\n\t\t\t\t\t\tif (options && !isUndefinedOrNull(options.context)) {\n\t\t\t\t\t\t\tmethodArgs = [options.context, ...args];\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tmethodArgs = args;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst result = await channel.call(propKey, methodArgs);\n\n\t\t\t\t\t\t// Revive unless marshalling disabled\n\t\t\t\t\t\tif (!disableMarshalling) {\n\t\t\t\t\t\t\treturn revive(result);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn result;\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tthrow new ErrorNoTelemetry(`Property not found: ${String(propKey)}`);\n\t\t\t}\n\t\t}) as T;\n\t}\n\n\tfunction propertyIsEvent(name: string): boolean {\n\t\t// Assume a property is an event if it has a form of \"onSomething\"\n\t\treturn name[0] === 'o' && name[1] === 'n' && strings.isUpperAsciiLetter(name.charCodeAt(2));\n\t}\n\n\tfunction propertyIsDynamicEvent(name: string): boolean {\n\t\t// Assume a property is a dynamic event (a method that returns an event) if it has a form of \"onDynamicSomething\"\n\t\treturn /^onDynamic/.test(name) && strings.isUpperAsciiLetter(name.charCodeAt(9));\n\t}\n}\n\nconst colorTables = [\n\t['#2977B1', '#FC802D', '#34A13A', '#D3282F', '#9366BA'],\n\t['#8B564C', '#E177C0', '#7F7F7F', '#BBBE3D', '#2EBECD']\n];\n\nfunction prettyWithoutArrays(data: any): any {\n\tif (Array.isArray(data)) {\n\t\treturn data;\n\t}\n\tif (data && typeof data === 'object' && typeof data.toString === 'function') {\n\t\tconst result = data.toString();\n\t\tif (result !== '[object Object]') {\n\t\t\treturn result;\n\t\t}\n\t}\n\treturn data;\n}\n\nfunction pretty(data: any): any {\n\tif (Array.isArray(data)) {\n\t\treturn data.map(prettyWithoutArrays);\n\t}\n\treturn prettyWithoutArrays(data);\n}\n\nfunction logWithColors(direction: string, totalLength: number, msgLength: number, req: number, initiator: RequestInitiator, str: string, data: any): void {\n\tdata = pretty(data);\n\n\tconst colorTable = colorTables[initiator];\n\tconst color = colorTable[req % colorTable.length];\n\tlet args = [`%c[${direction}]%c[${String(totalLength).padStart(7, ' ')}]%c[len: ${String(msgLength).padStart(5, ' ')}]%c${String(req).padStart(5, ' ')} - ${str}`, 'color: darkgreen', 'color: grey', 'color: grey', `color: ${color}`];\n\tif (/\\($/.test(str)) {\n\t\targs = args.concat(data);\n\t\targs.push(')');\n\t} else {\n\t\targs.push(data);\n\t}\n\tconsole.log.apply(console, args as [string, ...string[]]);\n}\n\nexport class IPCLogger implements IIPCLogger {\n\tprivate _totalIncoming = 0;\n\tprivate _totalOutgoing = 0;\n\n\tconstructor(\n\t\tprivate readonly _outgoingPrefix: string,\n\t\tprivate readonly _incomingPrefix: string,\n\t) { }\n\n\tpublic logOutgoing(msgLength: number, requestId: number, initiator: RequestInitiator, str: string, data?: any): void {\n\t\tthis._totalOutgoing += msgLength;\n\t\tlogWithColors(this._outgoingPrefix, this._totalOutgoing, msgLength, requestId, initiator, str, data);\n\t}\n\n\tpublic logIncoming(msgLength: number, requestId: number, initiator: RequestInitiator, str: string, data?: any): void {\n\t\tthis._totalIncoming += msgLength;\n\t\tlogWithColors(this._incomingPrefix, this._totalIncoming, msgLength, requestId, initiator, str, 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 { VSBuffer } from 'vs/base/common/buffer';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';\nimport { IIPCLogger, IMessagePassingProtocol, IPCClient } from 'vs/base/parts/ipc/common/ipc';\n\nexport const enum SocketDiagnosticsEventType {\n\tCreated = 'created',\n\tRead = 'read',\n\tWrite = 'write',\n\tOpen = 'open',\n\tError = 'error',\n\tClose = 'close',\n\n\tBrowserWebSocketBlobReceived = 'browserWebSocketBlobReceived',\n\n\tNodeEndReceived = 'nodeEndReceived',\n\tNodeEndSent = 'nodeEndSent',\n\tNodeDrainBegin = 'nodeDrainBegin',\n\tNodeDrainEnd = 'nodeDrainEnd',\n\n\tzlibInflateError = 'zlibInflateError',\n\tzlibInflateData = 'zlibInflateData',\n\tzlibInflateInitialWrite = 'zlibInflateInitialWrite',\n\tzlibInflateInitialFlushFired = 'zlibInflateInitialFlushFired',\n\tzlibInflateWrite = 'zlibInflateWrite',\n\tzlibInflateFlushFired = 'zlibInflateFlushFired',\n\tzlibDeflateError = 'zlibDeflateError',\n\tzlibDeflateData = 'zlibDeflateData',\n\tzlibDeflateWrite = 'zlibDeflateWrite',\n\tzlibDeflateFlushFired = 'zlibDeflateFlushFired',\n\n\tWebSocketNodeSocketWrite = 'webSocketNodeSocketWrite',\n\tWebSocketNodeSocketPeekedHeader = 'webSocketNodeSocketPeekedHeader',\n\tWebSocketNodeSocketReadHeader = 'webSocketNodeSocketReadHeader',\n\tWebSocketNodeSocketReadData = 'webSocketNodeSocketReadData',\n\tWebSocketNodeSocketUnmaskedData = 'webSocketNodeSocketUnmaskedData',\n\tWebSocketNodeSocketDrainBegin = 'webSocketNodeSocketDrainBegin',\n\tWebSocketNodeSocketDrainEnd = 'webSocketNodeSocketDrainEnd',\n\n\tProtocolHeaderRead = 'protocolHeaderRead',\n\tProtocolMessageRead = 'protocolMessageRead',\n\tProtocolHeaderWrite = 'protocolHeaderWrite',\n\tProtocolMessageWrite = 'protocolMessageWrite',\n\tProtocolWrite = 'protocolWrite',\n}\n\nexport namespace SocketDiagnostics {\n\n\texport const enableDiagnostics = false;\n\n\texport interface IRecord {\n\t\ttimestamp: number;\n\t\tid: string;\n\t\tlabel: string;\n\t\ttype: SocketDiagnosticsEventType;\n\t\tbuff?: VSBuffer;\n\t\tdata?: any;\n\t}\n\n\texport const records: IRecord[] = [];\n\tconst socketIds = new WeakMap();\n\tlet lastUsedSocketId = 0;\n\n\tfunction getSocketId(nativeObject: any, label: string): string {\n\t\tif (!socketIds.has(nativeObject)) {\n\t\t\tconst id = String(++lastUsedSocketId);\n\t\t\tsocketIds.set(nativeObject, id);\n\t\t}\n\t\treturn socketIds.get(nativeObject)!;\n\t}\n\n\texport function traceSocketEvent(nativeObject: any, socketDebugLabel: string, type: SocketDiagnosticsEventType, data?: VSBuffer | Uint8Array | ArrayBuffer | ArrayBufferView | any): void {\n\t\tif (!enableDiagnostics) {\n\t\t\treturn;\n\t\t}\n\t\tconst id = getSocketId(nativeObject, socketDebugLabel);\n\n\t\tif (data instanceof VSBuffer || data instanceof Uint8Array || data instanceof ArrayBuffer || ArrayBuffer.isView(data)) {\n\t\t\tconst copiedData = VSBuffer.alloc(data.byteLength);\n\t\t\tcopiedData.set(data);\n\t\t\trecords.push({ timestamp: Date.now(), id, label: socketDebugLabel, type, buff: copiedData });\n\t\t} else {\n\t\t\t// data is a custom object\n\t\t\trecords.push({ timestamp: Date.now(), id, label: socketDebugLabel, type, data: data });\n\t\t}\n\t}\n}\n\nexport const enum SocketCloseEventType {\n\tNodeSocketCloseEvent = 0,\n\tWebSocketCloseEvent = 1\n}\n\nexport interface NodeSocketCloseEvent {\n\t/**\n\t * The type of the event\n\t */\n\treadonly type: SocketCloseEventType.NodeSocketCloseEvent;\n\t/**\n\t * `true` if the socket had a transmission error.\n\t */\n\treadonly hadError: boolean;\n\t/**\n\t * Underlying error.\n\t */\n\treadonly error: Error | undefined;\n}\n\nexport interface WebSocketCloseEvent {\n\t/**\n\t * The type of the event\n\t */\n\treadonly type: SocketCloseEventType.WebSocketCloseEvent;\n\t/**\n\t * Returns the WebSocket connection close code provided by the server.\n\t */\n\treadonly code: number;\n\t/**\n\t * Returns the WebSocket connection close reason provided by the server.\n\t */\n\treadonly reason: string;\n\t/**\n\t * Returns true if the connection closed cleanly; false otherwise.\n\t */\n\treadonly wasClean: boolean;\n\t/**\n\t * Underlying event.\n\t */\n\treadonly event: any | undefined;\n}\n\nexport type SocketCloseEvent = NodeSocketCloseEvent | WebSocketCloseEvent | undefined;\n\nexport interface SocketTimeoutEvent {\n\treadonly unacknowledgedMsgCount: number;\n\treadonly timeSinceOldestUnacknowledgedMsg: number;\n\treadonly timeSinceLastReceivedSomeData: number;\n}\n\nexport interface ISocket extends IDisposable {\n\tonData(listener: (e: VSBuffer) => void): IDisposable;\n\tonClose(listener: (e: SocketCloseEvent) => void): IDisposable;\n\tonEnd(listener: () => void): IDisposable;\n\twrite(buffer: VSBuffer): void;\n\tend(): void;\n\tdrain(): Promise;\n\n\ttraceSocketEvent(type: SocketDiagnosticsEventType, data?: VSBuffer | Uint8Array | ArrayBuffer | ArrayBufferView | any): void;\n}\n\nlet emptyBuffer: VSBuffer | null = null;\nfunction getEmptyBuffer(): VSBuffer {\n\tif (!emptyBuffer) {\n\t\temptyBuffer = VSBuffer.alloc(0);\n\t}\n\treturn emptyBuffer;\n}\n\nexport class ChunkStream {\n\n\tprivate _chunks: VSBuffer[];\n\tprivate _totalLength: number;\n\n\tpublic get byteLength() {\n\t\treturn this._totalLength;\n\t}\n\n\tconstructor() {\n\t\tthis._chunks = [];\n\t\tthis._totalLength = 0;\n\t}\n\n\tpublic acceptChunk(buff: VSBuffer) {\n\t\tthis._chunks.push(buff);\n\t\tthis._totalLength += buff.byteLength;\n\t}\n\n\tpublic read(byteCount: number): VSBuffer {\n\t\treturn this._read(byteCount, true);\n\t}\n\n\tpublic peek(byteCount: number): VSBuffer {\n\t\treturn this._read(byteCount, false);\n\t}\n\n\tprivate _read(byteCount: number, advance: boolean): VSBuffer {\n\n\t\tif (byteCount === 0) {\n\t\t\treturn getEmptyBuffer();\n\t\t}\n\n\t\tif (byteCount > this._totalLength) {\n\t\t\tthrow new Error(`Cannot read so many bytes!`);\n\t\t}\n\n\t\tif (this._chunks[0].byteLength === byteCount) {\n\t\t\t// super fast path, precisely first chunk must be returned\n\t\t\tconst result = this._chunks[0];\n\t\t\tif (advance) {\n\t\t\t\tthis._chunks.shift();\n\t\t\t\tthis._totalLength -= byteCount;\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t\tif (this._chunks[0].byteLength > byteCount) {\n\t\t\t// fast path, the reading is entirely within the first chunk\n\t\t\tconst result = this._chunks[0].slice(0, byteCount);\n\t\t\tif (advance) {\n\t\t\t\tthis._chunks[0] = this._chunks[0].slice(byteCount);\n\t\t\t\tthis._totalLength -= byteCount;\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t\tconst result = VSBuffer.alloc(byteCount);\n\t\tlet resultOffset = 0;\n\t\tlet chunkIndex = 0;\n\t\twhile (byteCount > 0) {\n\t\t\tconst chunk = this._chunks[chunkIndex];\n\t\t\tif (chunk.byteLength > byteCount) {\n\t\t\t\t// this chunk will survive\n\t\t\t\tconst chunkPart = chunk.slice(0, byteCount);\n\t\t\t\tresult.set(chunkPart, resultOffset);\n\t\t\t\tresultOffset += byteCount;\n\n\t\t\t\tif (advance) {\n\t\t\t\t\tthis._chunks[chunkIndex] = chunk.slice(byteCount);\n\t\t\t\t\tthis._totalLength -= byteCount;\n\t\t\t\t}\n\n\t\t\t\tbyteCount -= byteCount;\n\t\t\t} else {\n\t\t\t\t// this chunk will be entirely read\n\t\t\t\tresult.set(chunk, resultOffset);\n\t\t\t\tresultOffset += chunk.byteLength;\n\n\t\t\t\tif (advance) {\n\t\t\t\t\tthis._chunks.shift();\n\t\t\t\t\tthis._totalLength -= chunk.byteLength;\n\t\t\t\t} else {\n\t\t\t\t\tchunkIndex++;\n\t\t\t\t}\n\n\t\t\t\tbyteCount -= chunk.byteLength;\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n}\n\nconst enum ProtocolMessageType {\n\tNone = 0,\n\tRegular = 1,\n\tControl = 2,\n\tAck = 3,\n\tDisconnect = 5,\n\tReplayRequest = 6,\n\tPause = 7,\n\tResume = 8,\n\tKeepAlive = 9\n}\n\nfunction protocolMessageTypeToString(messageType: ProtocolMessageType) {\n\tswitch (messageType) {\n\t\tcase ProtocolMessageType.None: return 'None';\n\t\tcase ProtocolMessageType.Regular: return 'Regular';\n\t\tcase ProtocolMessageType.Control: return 'Control';\n\t\tcase ProtocolMessageType.Ack: return 'Ack';\n\t\tcase ProtocolMessageType.Disconnect: return 'Disconnect';\n\t\tcase ProtocolMessageType.ReplayRequest: return 'ReplayRequest';\n\t\tcase ProtocolMessageType.Pause: return 'PauseWriting';\n\t\tcase ProtocolMessageType.Resume: return 'ResumeWriting';\n\t\tcase ProtocolMessageType.KeepAlive: return 'KeepAlive';\n\t}\n}\n\nexport const enum ProtocolConstants {\n\tHeaderLength = 13,\n\t/**\n\t * Send an Acknowledge message at most 2 seconds later...\n\t */\n\tAcknowledgeTime = 2000, // 2 seconds\n\t/**\n\t * If there is a sent message that has been unacknowledged for 20 seconds,\n\t * and we didn't see any incoming server data in the past 20 seconds,\n\t * then consider the connection has timed out.\n\t */\n\tTimeoutTime = 20000, // 20 seconds\n\t/**\n\t * If there is no reconnection within this time-frame, consider the connection permanently closed...\n\t */\n\tReconnectionGraceTime = 3 * 60 * 60 * 1000, // 3hrs\n\t/**\n\t * Maximal grace time between the first and the last reconnection...\n\t */\n\tReconnectionShortGraceTime = 5 * 60 * 1000, // 5min\n\t/**\n\t * Send a message every 5 seconds to avoid that the connection is closed by the OS.\n\t */\n\tKeepAliveSendTime = 5000, // 5 seconds\n}\n\nclass ProtocolMessage {\n\n\tpublic writtenTime: number;\n\n\tconstructor(\n\t\tpublic readonly type: ProtocolMessageType,\n\t\tpublic readonly id: number,\n\t\tpublic readonly ack: number,\n\t\tpublic readonly data: VSBuffer\n\t) {\n\t\tthis.writtenTime = 0;\n\t}\n\n\tpublic get size(): number {\n\t\treturn this.data.byteLength;\n\t}\n}\n\nclass ProtocolReader extends Disposable {\n\n\tprivate readonly _socket: ISocket;\n\tprivate _isDisposed: boolean;\n\tprivate readonly _incomingData: ChunkStream;\n\tpublic lastReadTime: number;\n\n\tprivate readonly _onMessage = this._register(new Emitter());\n\tpublic readonly onMessage: Event = this._onMessage.event;\n\n\tprivate readonly _state = {\n\t\treadHead: true,\n\t\treadLen: ProtocolConstants.HeaderLength,\n\t\tmessageType: ProtocolMessageType.None,\n\t\tid: 0,\n\t\tack: 0\n\t};\n\n\tconstructor(socket: ISocket) {\n\t\tsuper();\n\t\tthis._socket = socket;\n\t\tthis._isDisposed = false;\n\t\tthis._incomingData = new ChunkStream();\n\t\tthis._register(this._socket.onData(data => this.acceptChunk(data)));\n\t\tthis.lastReadTime = Date.now();\n\t}\n\n\tpublic acceptChunk(data: VSBuffer | null): void {\n\t\tif (!data || data.byteLength === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.lastReadTime = Date.now();\n\n\t\tthis._incomingData.acceptChunk(data);\n\n\t\twhile (this._incomingData.byteLength >= this._state.readLen) {\n\n\t\t\tconst buff = this._incomingData.read(this._state.readLen);\n\n\t\t\tif (this._state.readHead) {\n\t\t\t\t// buff is the header\n\n\t\t\t\t// save new state => next time will read the body\n\t\t\t\tthis._state.readHead = false;\n\t\t\t\tthis._state.readLen = buff.readUInt32BE(9);\n\t\t\t\tthis._state.messageType = buff.readUInt8(0);\n\t\t\t\tthis._state.id = buff.readUInt32BE(1);\n\t\t\t\tthis._state.ack = buff.readUInt32BE(5);\n\n\t\t\t\tthis._socket.traceSocketEvent(SocketDiagnosticsEventType.ProtocolHeaderRead, { messageType: protocolMessageTypeToString(this._state.messageType), id: this._state.id, ack: this._state.ack, messageSize: this._state.readLen });\n\n\t\t\t} else {\n\t\t\t\t// buff is the body\n\t\t\t\tconst messageType = this._state.messageType;\n\t\t\t\tconst id = this._state.id;\n\t\t\t\tconst ack = this._state.ack;\n\n\t\t\t\t// save new state => next time will read the header\n\t\t\t\tthis._state.readHead = true;\n\t\t\t\tthis._state.readLen = ProtocolConstants.HeaderLength;\n\t\t\t\tthis._state.messageType = ProtocolMessageType.None;\n\t\t\t\tthis._state.id = 0;\n\t\t\t\tthis._state.ack = 0;\n\n\t\t\t\tthis._socket.traceSocketEvent(SocketDiagnosticsEventType.ProtocolMessageRead, buff);\n\n\t\t\t\tthis._onMessage.fire(new ProtocolMessage(messageType, id, ack, buff));\n\n\t\t\t\tif (this._isDisposed) {\n\t\t\t\t\t// check if an event listener lead to our disposal\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic readEntireBuffer(): VSBuffer {\n\t\treturn this._incomingData.read(this._incomingData.byteLength);\n\t}\n\n\tpublic override dispose(): void {\n\t\tthis._isDisposed = true;\n\t\tsuper.dispose();\n\t}\n}\n\nclass ProtocolWriter {\n\n\tprivate _isDisposed: boolean;\n\tprivate _isPaused: boolean;\n\tprivate readonly _socket: ISocket;\n\tprivate _data: VSBuffer[];\n\tprivate _totalLength: number;\n\tpublic lastWriteTime: number;\n\n\tconstructor(socket: ISocket) {\n\t\tthis._isDisposed = false;\n\t\tthis._isPaused = false;\n\t\tthis._socket = socket;\n\t\tthis._data = [];\n\t\tthis._totalLength = 0;\n\t\tthis.lastWriteTime = 0;\n\t}\n\n\tpublic dispose(): void {\n\t\ttry {\n\t\t\tthis.flush();\n\t\t} catch (err) {\n\t\t\t// ignore error, since the socket could be already closed\n\t\t}\n\t\tthis._isDisposed = true;\n\t}\n\n\tpublic drain(): Promise {\n\t\tthis.flush();\n\t\treturn this._socket.drain();\n\t}\n\n\tpublic flush(): void {\n\t\t// flush\n\t\tthis._writeNow();\n\t}\n\n\tpublic pause(): void {\n\t\tthis._isPaused = true;\n\t}\n\n\tpublic resume(): void {\n\t\tthis._isPaused = false;\n\t\tthis._scheduleWriting();\n\t}\n\n\tpublic write(msg: ProtocolMessage) {\n\t\tif (this._isDisposed) {\n\t\t\t// ignore: there could be left-over promises which complete and then\n\t\t\t// decide to write a response, etc...\n\t\t\treturn;\n\t\t}\n\t\tmsg.writtenTime = Date.now();\n\t\tthis.lastWriteTime = Date.now();\n\t\tconst header = VSBuffer.alloc(ProtocolConstants.HeaderLength);\n\t\theader.writeUInt8(msg.type, 0);\n\t\theader.writeUInt32BE(msg.id, 1);\n\t\theader.writeUInt32BE(msg.ack, 5);\n\t\theader.writeUInt32BE(msg.data.byteLength, 9);\n\n\t\tthis._socket.traceSocketEvent(SocketDiagnosticsEventType.ProtocolHeaderWrite, { messageType: protocolMessageTypeToString(msg.type), id: msg.id, ack: msg.ack, messageSize: msg.data.byteLength });\n\t\tthis._socket.traceSocketEvent(SocketDiagnosticsEventType.ProtocolMessageWrite, msg.data);\n\n\t\tthis._writeSoon(header, msg.data);\n\t}\n\n\tprivate _bufferAdd(head: VSBuffer, body: VSBuffer): boolean {\n\t\tconst wasEmpty = this._totalLength === 0;\n\t\tthis._data.push(head, body);\n\t\tthis._totalLength += head.byteLength + body.byteLength;\n\t\treturn wasEmpty;\n\t}\n\n\tprivate _bufferTake(): VSBuffer {\n\t\tconst ret = VSBuffer.concat(this._data, this._totalLength);\n\t\tthis._data.length = 0;\n\t\tthis._totalLength = 0;\n\t\treturn ret;\n\t}\n\n\tprivate _writeSoon(header: VSBuffer, data: VSBuffer): void {\n\t\tif (this._bufferAdd(header, data)) {\n\t\t\tthis._scheduleWriting();\n\t\t}\n\t}\n\n\tprivate _writeNowTimeout: any = null;\n\tprivate _scheduleWriting(): void {\n\t\tif (this._writeNowTimeout) {\n\t\t\treturn;\n\t\t}\n\t\tthis._writeNowTimeout = setTimeout(() => {\n\t\t\tthis._writeNowTimeout = null;\n\t\t\tthis._writeNow();\n\t\t});\n\t}\n\n\tprivate _writeNow(): void {\n\t\tif (this._totalLength === 0) {\n\t\t\treturn;\n\t\t}\n\t\tif (this._isPaused) {\n\t\t\treturn;\n\t\t}\n\t\tconst data = this._bufferTake();\n\t\tthis._socket.traceSocketEvent(SocketDiagnosticsEventType.ProtocolWrite, { byteLength: data.byteLength });\n\t\tthis._socket.write(data);\n\t}\n}\n\n/**\n * A message has the following format:\n * ```\n * /-------------------------------|------\\\n * | HEADER | |\n * |-------------------------------| DATA |\n * | TYPE | ID | ACK | DATA_LENGTH | |\n * \\-------------------------------|------/\n * ```\n * The header is 9 bytes and consists of:\n * - TYPE is 1 byte (ProtocolMessageType) - the message type\n * - ID is 4 bytes (u32be) - the message id (can be 0 to indicate to be ignored)\n * - ACK is 4 bytes (u32be) - the acknowledged message id (can be 0 to indicate to be ignored)\n * - DATA_LENGTH is 4 bytes (u32be) - the length in bytes of DATA\n *\n * Only Regular messages are counted, other messages are not counted, nor acknowledged.\n */\nexport class Protocol extends Disposable implements IMessagePassingProtocol {\n\n\tprivate _socket: ISocket;\n\tprivate _socketWriter: ProtocolWriter;\n\tprivate _socketReader: ProtocolReader;\n\n\tprivate readonly _onMessage = new Emitter();\n\treadonly onMessage: Event = this._onMessage.event;\n\n\tprivate readonly _onDidDispose = new Emitter();\n\treadonly onDidDispose: Event = this._onDidDispose.event;\n\n\tconstructor(socket: ISocket) {\n\t\tsuper();\n\t\tthis._socket = socket;\n\t\tthis._socketWriter = this._register(new ProtocolWriter(this._socket));\n\t\tthis._socketReader = this._register(new ProtocolReader(this._socket));\n\n\t\tthis._register(this._socketReader.onMessage((msg) => {\n\t\t\tif (msg.type === ProtocolMessageType.Regular) {\n\t\t\t\tthis._onMessage.fire(msg.data);\n\t\t\t}\n\t\t}));\n\n\t\tthis._register(this._socket.onClose(() => this._onDidDispose.fire()));\n\t}\n\n\tdrain(): Promise {\n\t\treturn this._socketWriter.drain();\n\t}\n\n\tgetSocket(): ISocket {\n\t\treturn this._socket;\n\t}\n\n\tsendDisconnect(): void {\n\t\t// Nothing to do...\n\t}\n\n\tsend(buffer: VSBuffer): void {\n\t\tthis._socketWriter.write(new ProtocolMessage(ProtocolMessageType.Regular, 0, 0, buffer));\n\t}\n}\n\nexport class Client extends IPCClient {\n\n\tstatic fromSocket(socket: ISocket, id: TContext): Client {\n\t\treturn new Client(new Protocol(socket), id);\n\t}\n\n\tget onDidDispose(): Event { return this.protocol.onDidDispose; }\n\n\tconstructor(private protocol: Protocol | PersistentProtocol, id: TContext, ipcLogger: IIPCLogger | null = null) {\n\t\tsuper(protocol, id, ipcLogger);\n\t}\n\n\toverride dispose(): void {\n\t\tsuper.dispose();\n\t\tconst socket = this.protocol.getSocket();\n\t\tthis.protocol.sendDisconnect();\n\t\tthis.protocol.dispose();\n\t\tsocket.end();\n\t}\n}\n\n/**\n * Will ensure no messages are lost if there are no event listeners.\n */\nexport class BufferedEmitter {\n\tprivate _emitter: Emitter;\n\tpublic readonly event: Event;\n\n\tprivate _hasListeners = false;\n\tprivate _isDeliveringMessages = false;\n\tprivate _bufferedMessages: T[] = [];\n\n\tconstructor() {\n\t\tthis._emitter = new Emitter({\n\t\t\tonWillAddFirstListener: () => {\n\t\t\t\tthis._hasListeners = true;\n\t\t\t\t// it is important to deliver these messages after this call, but before\n\t\t\t\t// other messages have a chance to be received (to guarantee in order delivery)\n\t\t\t\t// that's why we're using here queueMicrotask and not other types of timeouts\n\t\t\t\tqueueMicrotask(() => this._deliverMessages());\n\t\t\t},\n\t\t\tonDidRemoveLastListener: () => {\n\t\t\t\tthis._hasListeners = false;\n\t\t\t}\n\t\t});\n\n\t\tthis.event = this._emitter.event;\n\t}\n\n\tprivate _deliverMessages(): void {\n\t\tif (this._isDeliveringMessages) {\n\t\t\treturn;\n\t\t}\n\t\tthis._isDeliveringMessages = true;\n\t\twhile (this._hasListeners && this._bufferedMessages.length > 0) {\n\t\t\tthis._emitter.fire(this._bufferedMessages.shift()!);\n\t\t}\n\t\tthis._isDeliveringMessages = false;\n\t}\n\n\tpublic fire(event: T): void {\n\t\tif (this._hasListeners) {\n\t\t\tif (this._bufferedMessages.length > 0) {\n\t\t\t\tthis._bufferedMessages.push(event);\n\t\t\t} else {\n\t\t\t\tthis._emitter.fire(event);\n\t\t\t}\n\t\t} else {\n\t\t\tthis._bufferedMessages.push(event);\n\t\t}\n\t}\n\n\tpublic flushBuffer(): void {\n\t\tthis._bufferedMessages = [];\n\t}\n}\n\nclass QueueElement {\n\tpublic readonly data: T;\n\tpublic next: QueueElement | null;\n\n\tconstructor(data: T) {\n\t\tthis.data = data;\n\t\tthis.next = null;\n\t}\n}\n\nclass Queue {\n\n\tprivate _first: QueueElement | null;\n\tprivate _last: QueueElement | null;\n\n\tconstructor() {\n\t\tthis._first = null;\n\t\tthis._last = null;\n\t}\n\n\tpublic length(): number {\n\t\tlet result = 0;\n\t\tlet current = this._first;\n\t\twhile (current) {\n\t\t\tcurrent = current.next;\n\t\t\tresult++;\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic peek(): T | null {\n\t\tif (!this._first) {\n\t\t\treturn null;\n\t\t}\n\t\treturn this._first.data;\n\t}\n\n\tpublic toArray(): T[] {\n\t\tconst result: T[] = [];\n\t\tlet resultLen = 0;\n\t\tlet it = this._first;\n\t\twhile (it) {\n\t\t\tresult[resultLen++] = it.data;\n\t\t\tit = it.next;\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic pop(): void {\n\t\tif (!this._first) {\n\t\t\treturn;\n\t\t}\n\t\tif (this._first === this._last) {\n\t\t\tthis._first = null;\n\t\t\tthis._last = null;\n\t\t\treturn;\n\t\t}\n\t\tthis._first = this._first.next;\n\t}\n\n\tpublic push(item: T): void {\n\t\tconst element = new QueueElement(item);\n\t\tif (!this._first) {\n\t\t\tthis._first = element;\n\t\t\tthis._last = element;\n\t\t\treturn;\n\t\t}\n\t\tthis._last!.next = element;\n\t\tthis._last = element;\n\t}\n}\n\nclass LoadEstimator {\n\n\tprivate static _HISTORY_LENGTH = 10;\n\tprivate static _INSTANCE: LoadEstimator | null = null;\n\tpublic static getInstance(): LoadEstimator {\n\t\tif (!LoadEstimator._INSTANCE) {\n\t\t\tLoadEstimator._INSTANCE = new LoadEstimator();\n\t\t}\n\t\treturn LoadEstimator._INSTANCE;\n\t}\n\n\tprivate lastRuns: number[];\n\n\tconstructor() {\n\t\tthis.lastRuns = [];\n\t\tconst now = Date.now();\n\t\tfor (let i = 0; i < LoadEstimator._HISTORY_LENGTH; i++) {\n\t\t\tthis.lastRuns[i] = now - 1000 * i;\n\t\t}\n\t\tsetInterval(() => {\n\t\t\tfor (let i = LoadEstimator._HISTORY_LENGTH; i >= 1; i--) {\n\t\t\t\tthis.lastRuns[i] = this.lastRuns[i - 1];\n\t\t\t}\n\t\t\tthis.lastRuns[0] = Date.now();\n\t\t}, 1000);\n\t}\n\n\t/**\n\t * returns an estimative number, from 0 (low load) to 1 (high load)\n\t */\n\tprivate load(): number {\n\t\tconst now = Date.now();\n\t\tconst historyLimit = (1 + LoadEstimator._HISTORY_LENGTH) * 1000;\n\t\tlet score = 0;\n\t\tfor (let i = 0; i < LoadEstimator._HISTORY_LENGTH; i++) {\n\t\t\tif (now - this.lastRuns[i] <= historyLimit) {\n\t\t\t\tscore++;\n\t\t\t}\n\t\t}\n\t\treturn 1 - score / LoadEstimator._HISTORY_LENGTH;\n\t}\n\n\tpublic hasHighLoad(): boolean {\n\t\treturn this.load() >= 0.5;\n\t}\n}\n\nexport interface ILoadEstimator {\n\thasHighLoad(): boolean;\n}\n\nexport interface PersistentProtocolOptions {\n\t/**\n\t * The socket to use.\n\t */\n\tsocket: ISocket;\n\t/**\n\t * The initial chunk of data that has already been received from the socket.\n\t */\n\tinitialChunk?: VSBuffer | null;\n\t/**\n\t * The CPU load estimator to use.\n\t */\n\tloadEstimator?: ILoadEstimator;\n\t/**\n\t * Whether to send keep alive messages. Defaults to true.\n\t */\n\tsendKeepAlive?: boolean;\n}\n\n/**\n * Same as Protocol, but will actually track messages and acks.\n * Moreover, it will ensure no messages are lost if there are no event listeners.\n */\nexport class PersistentProtocol implements IMessagePassingProtocol {\n\n\tprivate _isReconnecting: boolean;\n\n\tprivate _outgoingUnackMsg: Queue;\n\tprivate _outgoingMsgId: number;\n\tprivate _outgoingAckId: number;\n\tprivate _outgoingAckTimeout: any | null;\n\n\tprivate _incomingMsgId: number;\n\tprivate _incomingAckId: number;\n\tprivate _incomingMsgLastTime: number;\n\tprivate _incomingAckTimeout: any | null;\n\n\tprivate _keepAliveInterval: any | null;\n\n\tprivate _lastReplayRequestTime: number;\n\tprivate _lastSocketTimeoutTime: number;\n\n\tprivate _socket: ISocket;\n\tprivate _socketWriter: ProtocolWriter;\n\tprivate _socketReader: ProtocolReader;\n\tprivate _socketDisposables: DisposableStore;\n\n\tprivate readonly _loadEstimator: ILoadEstimator;\n\tprivate readonly _shouldSendKeepAlive: boolean;\n\n\tprivate readonly _onControlMessage = new BufferedEmitter();\n\treadonly onControlMessage: Event = this._onControlMessage.event;\n\n\tprivate readonly _onMessage = new BufferedEmitter();\n\treadonly onMessage: Event = this._onMessage.event;\n\n\tprivate readonly _onDidDispose = new BufferedEmitter();\n\treadonly onDidDispose: Event = this._onDidDispose.event;\n\n\tprivate readonly _onSocketClose = new BufferedEmitter();\n\treadonly onSocketClose: Event = this._onSocketClose.event;\n\n\tprivate readonly _onSocketTimeout = new BufferedEmitter();\n\treadonly onSocketTimeout: Event = this._onSocketTimeout.event;\n\n\tpublic get unacknowledgedCount(): number {\n\t\treturn this._outgoingMsgId - this._outgoingAckId;\n\t}\n\n\tconstructor(opts: PersistentProtocolOptions) {\n\t\tthis._loadEstimator = opts.loadEstimator ?? LoadEstimator.getInstance();\n\t\tthis._shouldSendKeepAlive = opts.sendKeepAlive ?? true;\n\t\tthis._isReconnecting = false;\n\t\tthis._outgoingUnackMsg = new Queue();\n\t\tthis._outgoingMsgId = 0;\n\t\tthis._outgoingAckId = 0;\n\t\tthis._outgoingAckTimeout = null;\n\n\t\tthis._incomingMsgId = 0;\n\t\tthis._incomingAckId = 0;\n\t\tthis._incomingMsgLastTime = 0;\n\t\tthis._incomingAckTimeout = null;\n\n\t\tthis._lastReplayRequestTime = 0;\n\t\tthis._lastSocketTimeoutTime = Date.now();\n\n\t\tthis._socketDisposables = new DisposableStore();\n\t\tthis._socket = opts.socket;\n\t\tthis._socketWriter = this._socketDisposables.add(new ProtocolWriter(this._socket));\n\t\tthis._socketReader = this._socketDisposables.add(new ProtocolReader(this._socket));\n\t\tthis._socketDisposables.add(this._socketReader.onMessage(msg => this._receiveMessage(msg)));\n\t\tthis._socketDisposables.add(this._socket.onClose(e => this._onSocketClose.fire(e)));\n\n\t\tif (opts.initialChunk) {\n\t\t\tthis._socketReader.acceptChunk(opts.initialChunk);\n\t\t}\n\n\t\tif (this._shouldSendKeepAlive) {\n\t\t\tthis._keepAliveInterval = setInterval(() => {\n\t\t\t\tthis._sendKeepAlive();\n\t\t\t}, ProtocolConstants.KeepAliveSendTime);\n\t\t} else {\n\t\t\tthis._keepAliveInterval = null;\n\t\t}\n\t}\n\n\tdispose(): void {\n\t\tif (this._outgoingAckTimeout) {\n\t\t\tclearTimeout(this._outgoingAckTimeout);\n\t\t\tthis._outgoingAckTimeout = null;\n\t\t}\n\t\tif (this._incomingAckTimeout) {\n\t\t\tclearTimeout(this._incomingAckTimeout);\n\t\t\tthis._incomingAckTimeout = null;\n\t\t}\n\t\tif (this._keepAliveInterval) {\n\t\t\tclearInterval(this._keepAliveInterval);\n\t\t\tthis._keepAliveInterval = null;\n\t\t}\n\t\tthis._socketDisposables.dispose();\n\t}\n\n\tdrain(): Promise {\n\t\treturn this._socketWriter.drain();\n\t}\n\n\tsendDisconnect(): void {\n\t\tconst msg = new ProtocolMessage(ProtocolMessageType.Disconnect, 0, 0, getEmptyBuffer());\n\t\tthis._socketWriter.write(msg);\n\t\tthis._socketWriter.flush();\n\t}\n\n\tsendPause(): void {\n\t\tconst msg = new ProtocolMessage(ProtocolMessageType.Pause, 0, 0, getEmptyBuffer());\n\t\tthis._socketWriter.write(msg);\n\t}\n\n\tsendResume(): void {\n\t\tconst msg = new ProtocolMessage(ProtocolMessageType.Resume, 0, 0, getEmptyBuffer());\n\t\tthis._socketWriter.write(msg);\n\t}\n\n\tpauseSocketWriting() {\n\t\tthis._socketWriter.pause();\n\t}\n\n\tpublic getSocket(): ISocket {\n\t\treturn this._socket;\n\t}\n\n\tpublic getMillisSinceLastIncomingData(): number {\n\t\treturn Date.now() - this._socketReader.lastReadTime;\n\t}\n\n\tpublic beginAcceptReconnection(socket: ISocket, initialDataChunk: VSBuffer | null): void {\n\t\tthis._isReconnecting = true;\n\n\t\tthis._socketDisposables.dispose();\n\t\tthis._socketDisposables = new DisposableStore();\n\t\tthis._onControlMessage.flushBuffer();\n\t\tthis._onSocketClose.flushBuffer();\n\t\tthis._onSocketTimeout.flushBuffer();\n\t\tthis._socket.dispose();\n\n\t\tthis._lastReplayRequestTime = 0;\n\t\tthis._lastSocketTimeoutTime = Date.now();\n\n\t\tthis._socket = socket;\n\t\tthis._socketWriter = this._socketDisposables.add(new ProtocolWriter(this._socket));\n\t\tthis._socketReader = this._socketDisposables.add(new ProtocolReader(this._socket));\n\t\tthis._socketDisposables.add(this._socketReader.onMessage(msg => this._receiveMessage(msg)));\n\t\tthis._socketDisposables.add(this._socket.onClose(e => this._onSocketClose.fire(e)));\n\n\t\tthis._socketReader.acceptChunk(initialDataChunk);\n\t}\n\n\tpublic endAcceptReconnection(): void {\n\t\tthis._isReconnecting = false;\n\n\t\t// After a reconnection, let the other party know (again) which messages have been received.\n\t\t// (perhaps the other party didn't receive a previous ACK)\n\t\tthis._incomingAckId = this._incomingMsgId;\n\t\tconst msg = new ProtocolMessage(ProtocolMessageType.Ack, 0, this._incomingAckId, getEmptyBuffer());\n\t\tthis._socketWriter.write(msg);\n\n\t\t// Send again all unacknowledged messages\n\t\tconst toSend = this._outgoingUnackMsg.toArray();\n\t\tfor (let i = 0, len = toSend.length; i < len; i++) {\n\t\t\tthis._socketWriter.write(toSend[i]);\n\t\t}\n\t\tthis._recvAckCheck();\n\t}\n\n\tpublic acceptDisconnect(): void {\n\t\tthis._onDidDispose.fire();\n\t}\n\n\tprivate _receiveMessage(msg: ProtocolMessage): void {\n\t\tif (msg.ack > this._outgoingAckId) {\n\t\t\tthis._outgoingAckId = msg.ack;\n\t\t\tdo {\n\t\t\t\tconst first = this._outgoingUnackMsg.peek();\n\t\t\t\tif (first && first.id <= msg.ack) {\n\t\t\t\t\t// this message has been confirmed, remove it\n\t\t\t\t\tthis._outgoingUnackMsg.pop();\n\t\t\t\t} else {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} while (true);\n\t\t}\n\n\t\tswitch (msg.type) {\n\t\t\tcase ProtocolMessageType.None: {\n\t\t\t\t// N/A\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ProtocolMessageType.Regular: {\n\t\t\t\tif (msg.id > this._incomingMsgId) {\n\t\t\t\t\tif (msg.id !== this._incomingMsgId + 1) {\n\t\t\t\t\t\t// in case we missed some messages we ask the other party to resend them\n\t\t\t\t\t\tconst now = Date.now();\n\t\t\t\t\t\tif (now - this._lastReplayRequestTime > 10000) {\n\t\t\t\t\t\t\t// send a replay request at most once every 10s\n\t\t\t\t\t\t\tthis._lastReplayRequestTime = now;\n\t\t\t\t\t\t\tthis._socketWriter.write(new ProtocolMessage(ProtocolMessageType.ReplayRequest, 0, 0, getEmptyBuffer()));\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis._incomingMsgId = msg.id;\n\t\t\t\t\t\tthis._incomingMsgLastTime = Date.now();\n\t\t\t\t\t\tthis._sendAckCheck();\n\t\t\t\t\t\tthis._onMessage.fire(msg.data);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ProtocolMessageType.Control: {\n\t\t\t\tthis._onControlMessage.fire(msg.data);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ProtocolMessageType.Ack: {\n\t\t\t\t// nothing to do, .ack is handled above already\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ProtocolMessageType.Disconnect: {\n\t\t\t\tthis._onDidDispose.fire();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ProtocolMessageType.ReplayRequest: {\n\t\t\t\t// Send again all unacknowledged messages\n\t\t\t\tconst toSend = this._outgoingUnackMsg.toArray();\n\t\t\t\tfor (let i = 0, len = toSend.length; i < len; i++) {\n\t\t\t\t\tthis._socketWriter.write(toSend[i]);\n\t\t\t\t}\n\t\t\t\tthis._recvAckCheck();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ProtocolMessageType.Pause: {\n\t\t\t\tthis._socketWriter.pause();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ProtocolMessageType.Resume: {\n\t\t\t\tthis._socketWriter.resume();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ProtocolMessageType.KeepAlive: {\n\t\t\t\t// nothing to do\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\treadEntireBuffer(): VSBuffer {\n\t\treturn this._socketReader.readEntireBuffer();\n\t}\n\n\tflush(): void {\n\t\tthis._socketWriter.flush();\n\t}\n\n\tsend(buffer: VSBuffer): void {\n\t\tconst myId = ++this._outgoingMsgId;\n\t\tthis._incomingAckId = this._incomingMsgId;\n\t\tconst msg = new ProtocolMessage(ProtocolMessageType.Regular, myId, this._incomingAckId, buffer);\n\t\tthis._outgoingUnackMsg.push(msg);\n\t\tif (!this._isReconnecting) {\n\t\t\tthis._socketWriter.write(msg);\n\t\t\tthis._recvAckCheck();\n\t\t}\n\t}\n\n\t/**\n\t * Send a message which will not be part of the regular acknowledge flow.\n\t * Use this for early control messages which are repeated in case of reconnection.\n\t */\n\tsendControl(buffer: VSBuffer): void {\n\t\tconst msg = new ProtocolMessage(ProtocolMessageType.Control, 0, 0, buffer);\n\t\tthis._socketWriter.write(msg);\n\t}\n\n\tprivate _sendAckCheck(): void {\n\t\tif (this._incomingMsgId <= this._incomingAckId) {\n\t\t\t// nothink to acknowledge\n\t\t\treturn;\n\t\t}\n\n\t\tif (this._incomingAckTimeout) {\n\t\t\t// there will be a check in the near future\n\t\t\treturn;\n\t\t}\n\n\t\tconst timeSinceLastIncomingMsg = Date.now() - this._incomingMsgLastTime;\n\t\tif (timeSinceLastIncomingMsg >= ProtocolConstants.AcknowledgeTime) {\n\t\t\t// sufficient time has passed since this message has been received,\n\t\t\t// and no message from our side needed to be sent in the meantime,\n\t\t\t// so we will send a message containing only an ack.\n\t\t\tthis._sendAck();\n\t\t\treturn;\n\t\t}\n\n\t\tthis._incomingAckTimeout = setTimeout(() => {\n\t\t\tthis._incomingAckTimeout = null;\n\t\t\tthis._sendAckCheck();\n\t\t}, ProtocolConstants.AcknowledgeTime - timeSinceLastIncomingMsg + 5);\n\t}\n\n\tprivate _recvAckCheck(): void {\n\t\tif (this._outgoingMsgId <= this._outgoingAckId) {\n\t\t\t// everything has been acknowledged\n\t\t\treturn;\n\t\t}\n\n\t\tif (this._outgoingAckTimeout) {\n\t\t\t// there will be a check in the near future\n\t\t\treturn;\n\t\t}\n\n\t\tif (this._isReconnecting) {\n\t\t\t// do not cause a timeout during reconnection,\n\t\t\t// because messages will not be actually written until `endAcceptReconnection`\n\t\t\treturn;\n\t\t}\n\n\t\tconst oldestUnacknowledgedMsg = this._outgoingUnackMsg.peek()!;\n\t\tconst timeSinceOldestUnacknowledgedMsg = Date.now() - oldestUnacknowledgedMsg.writtenTime;\n\t\tconst timeSinceLastReceivedSomeData = Date.now() - this._socketReader.lastReadTime;\n\t\tconst timeSinceLastTimeout = Date.now() - this._lastSocketTimeoutTime;\n\n\t\tif (\n\t\t\ttimeSinceOldestUnacknowledgedMsg >= ProtocolConstants.TimeoutTime\n\t\t\t&& timeSinceLastReceivedSomeData >= ProtocolConstants.TimeoutTime\n\t\t\t&& timeSinceLastTimeout >= ProtocolConstants.TimeoutTime\n\t\t) {\n\t\t\t// It's been a long time since our sent message was acknowledged\n\t\t\t// and a long time since we received some data\n\n\t\t\t// But this might be caused by the event loop being busy and failing to read messages\n\t\t\tif (!this._loadEstimator.hasHighLoad()) {\n\t\t\t\t// Trash the socket\n\t\t\t\tthis._lastSocketTimeoutTime = Date.now();\n\t\t\t\tthis._onSocketTimeout.fire({\n\t\t\t\t\tunacknowledgedMsgCount: this._outgoingUnackMsg.length(),\n\t\t\t\t\ttimeSinceOldestUnacknowledgedMsg,\n\t\t\t\t\ttimeSinceLastReceivedSomeData\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tconst minimumTimeUntilTimeout = Math.max(\n\t\t\tProtocolConstants.TimeoutTime - timeSinceOldestUnacknowledgedMsg,\n\t\t\tProtocolConstants.TimeoutTime - timeSinceLastReceivedSomeData,\n\t\t\tProtocolConstants.TimeoutTime - timeSinceLastTimeout,\n\t\t\t500\n\t\t);\n\n\t\tthis._outgoingAckTimeout = setTimeout(() => {\n\t\t\tthis._outgoingAckTimeout = null;\n\t\t\tthis._recvAckCheck();\n\t\t}, minimumTimeUntilTimeout);\n\t}\n\n\tprivate _sendAck(): void {\n\t\tif (this._incomingMsgId <= this._incomingAckId) {\n\t\t\t// nothink to acknowledge\n\t\t\treturn;\n\t\t}\n\n\t\tthis._incomingAckId = this._incomingMsgId;\n\t\tconst msg = new ProtocolMessage(ProtocolMessageType.Ack, 0, this._incomingAckId, getEmptyBuffer());\n\t\tthis._socketWriter.write(msg);\n\t}\n\n\tprivate _sendKeepAlive(): void {\n\t\tthis._incomingAckId = this._incomingMsgId;\n\t\tconst msg = new ProtocolMessage(ProtocolMessageType.KeepAlive, 0, this._incomingAckId, getEmptyBuffer());\n\t\tthis._socketWriter.write(msg);\n\t}\n}\n\n// (() => {\n// \tif (!SocketDiagnostics.enableDiagnostics) {\n// \t\treturn;\n// \t}\n// \tif (typeof require.__$__nodeRequire !== 'function') {\n// \t\tconsole.log(`Can only log socket diagnostics on native platforms.`);\n// \t\treturn;\n// \t}\n// \tconst type = (\n// \t\tprocess.argv.includes('--type=renderer')\n// \t\t\t? 'renderer'\n// \t\t\t: (process.argv.includes('--type=extensionHost')\n// \t\t\t\t? 'extensionHost'\n// \t\t\t\t: (process.argv.some(item => item.includes('server-main'))\n// \t\t\t\t\t? 'server'\n// \t\t\t\t\t: 'unknown'\n// \t\t\t\t)\n// \t\t\t)\n// \t);\n// \tsetTimeout(() => {\n// \t\tSocketDiagnostics.records.forEach(r => {\n// \t\t\tif (r.buff) {\n// \t\t\t\tr.data = Buffer.from(r.buff.buffer).toString('base64');\n// \t\t\t\tr.buff = undefined;\n// \t\t\t}\n// \t\t});\n\n// \t\tconst fs = require.__$__nodeRequire('fs');\n// \t\tconst path = require.__$__nodeRequire('path');\n// \t\tconst logPath = path.join(process.cwd(),`${type}-${process.pid}`);\n\n// \t\tconsole.log(`dumping socket diagnostics at ${logPath}`);\n// \t\tfs.writeFileSync(logPath, JSON.stringify(SocketDiagnostics.records));\n// \t}, 20000);\n// })();\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { parse, 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 function isStorageItemsChangeEvent(thing: unknown): thing is IStorageItemsChangeEvent {\n\tconst candidate = thing as IStorageItemsChangeEvent | undefined;\n\n\treturn candidate?.changed instanceof Map || candidate?.deleted instanceof Set;\n}\n\nexport interface IStorageDatabase {\n\n\treadonly onDidChangeItemsExternal: Event;\n\n\tgetItems(): Promise>;\n\tupdateItems(request: IUpdateRequest): Promise;\n\n\toptimize(): Promise;\n\n\tclose(recovery?: () => Map): 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\treadonly onDidChangeStorage: Event;\n\n\treadonly items: Map;\n\treadonly size: number;\n\n\tinit(): Promise;\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\tgetObject(key: string, fallbackValue: T): T;\n\tgetObject(key: string, fallbackValue?: T): T | undefined;\n\n\tset(key: string, value: StorageValue, external?: boolean): Promise;\n\tdelete(key: string, external?: boolean): Promise;\n\n\tflush(delay?: number): Promise;\n\twhenFlushed(): Promise;\n\n\toptimize(): Promise;\n\n\tclose(): 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 pendingClose: Promise | undefined = undefined;\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 items(): Map {\n\t\treturn this.cache;\n\t}\n\n\tget size(): number {\n\t\treturn this.cache.size;\n\t}\n\n\tasync init(): Promise {\n\t\tif (this.state !== StorageState.None) {\n\t\t\treturn; // either closed or already initialized\n\t\t}\n\n\t\tthis.state = StorageState.Initialized;\n\n\t\tif (this.options.hint === StorageHint.STORAGE_DOES_NOT_EXIST) {\n\t\t\t// return early if we know the storage file does not exist. this is a performance\n\t\t\t// optimization to not load all items of the underlying storage if we know that\n\t\t\t// there can be no items because the storage does not exist.\n\t\t\treturn;\n\t\t}\n\n\t\tthis.cache = await this.database.getItems();\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\tgetObject(key: string, fallbackValue: object): object;\n\tgetObject(key: string, fallbackValue?: object | undefined): object | undefined;\n\tgetObject(key: string, fallbackValue?: object): object | 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 parse(value);\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\tasync optimize(): 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// Await pending data to be flushed to the DB\n\t\t// before attempting to optimize the DB\n\t\tawait this.flush(0);\n\n\t\treturn this.database.optimize();\n\t}\n\n\tasync close(): Promise {\n\t\tif (!this.pendingClose) {\n\t\t\tthis.pendingClose = this.doClose();\n\t\t}\n\n\t\treturn this.pendingClose;\n\t}\n\n\tprivate async doClose(): Promise {\n\n\t\t// Update state\n\t\tthis.state = StorageState.Closed;\n\n\t\t// Trigger new flush to ensure data is persisted and then close\n\t\t// even if there is an error flushing. We must always ensure\n\t\t// the DB is closed to avoid corruption.\n\t\t//\n\t\t// Recovery: we pass our cache over as recovery option in case\n\t\t// the DB is not healthy.\n\t\ttry {\n\t\t\tawait this.doFlush(0 /* as soon as possible */);\n\t\t} catch (error) {\n\t\t\t// Ignore\n\t\t}\n\n\t\tawait this.database.close(() => this.cache);\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\tasync flush(delay?: number): Promise {\n\t\tif (!this.hasPending) {\n\t\t\treturn; // return early if nothing to do\n\t\t}\n\n\t\treturn this.doFlush(delay);\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\tasync whenFlushed(): Promise {\n\t\tif (!this.hasPending) {\n\t\t\treturn; // return early if nothing to do\n\t\t}\n\n\t\treturn new Promise(resolve => this.whenFlushedCallbacks.push(resolve));\n\t}\n\n\tisInMemory(): boolean {\n\t\treturn this.options.hint === StorageHint.STORAGE_IN_MEMORY;\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 getItems(): Promise> {\n\t\treturn this.items;\n\t}\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\tasync optimize(): Promise { }\n\tasync close(): 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 { 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 IRenderData {\n\tcoordinate: Coordinate;\n\tposition: ContentWidgetPositionPreference;\n}\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 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 { coordinate: new Coordinate(placement.aboveTop, placement.left), position: ContentWidgetPositionPreference.ABOVE };\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 { coordinate: new Coordinate(placement.belowTop, placement.left), position: ContentWidgetPositionPreference.BELOW };\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 { coordinate: this._prepareRenderWidgetAtExactPositionOverflowing(new Coordinate(anchor.top, anchor.left)), position: ContentWidgetPositionPreference.EXACT };\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn { coordinate: new Coordinate(anchor.top, anchor.left), position: ContentWidgetPositionPreference.EXACT };\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) {\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\t\t\t\tthis.domNode.setVisibility('hidden');\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, 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\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, preference: OverlayWidgetPositionPreference | IOverlayWidgetPositionCoordinates | null): boolean {\n\t\tconst widgetData = this._widgets[widget.getId()];\n\t\tif (widgetData.preference === preference) {\n\t\t\tthis._updateMaxMinWidth();\n\t\t\treturn false;\n\t\t}\n\n\t\twidgetData.preference = preference;\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): 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\tif (widgetData.preference === OverlayWidgetPositionPreference.TOP_RIGHT_CORNER) {\n\t\t\tdomNode.setTop(0);\n\t\t\tdomNode.setRight((2 * this._verticalScrollbarWidth) + this._minimapWidth);\n\t\t} else if (widgetData.preference === OverlayWidgetPositionPreference.BOTTOM_RIGHT_CORNER) {\n\t\t\tconst widgetHeight = domNode.domNode.clientHeight;\n\t\t\tdomNode.setTop((this._editorHeight - widgetHeight - 2 * this._horizontalScrollbarHeight));\n\t\t\tdomNode.setRight((2 * this._verticalScrollbarWidth) + this._minimapWidth);\n\t\t} else if (widgetData.preference === OverlayWidgetPositionPreference.TOP_CENTER) {\n\t\t\tdomNode.setTop(0);\n\t\t\tdomNode.domNode.style.right = '50%';\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\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]);\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\t/**\n\t * used by tests\n\t */\n\tpublic set(id: string, value: IEditorContribution) {\n\t\tthis._instances.set(id, value);\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, autorun, derived, observableValue } from 'vs/base/common/observable';\nimport { DiffEditorOptions } from '../diffEditorOptions';\n\nexport class DiffEditorSash extends Disposable {\n\tprivate readonly _sashRatio = observableValue(this, undefined);\n\n\tpublic readonly sashLeft = derived(this, reader => {\n\t\tconst ratio = this._sashRatio.read(reader) ?? this._options.splitViewDefaultRatio.read(reader);\n\t\treturn this._computeSashLeft(ratio, reader);\n\t});\n\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 _options: DiffEditorOptions,\n\t\tprivate readonly _domNode: HTMLElement,\n\t\tprivate readonly _dimensions: { height: IObservable; width: IObservable },\n\t\tprivate readonly _sashes: IObservable,\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\tconst contentWidth = this._dimensions.width.get();\n\t\t\tconst sashPosition = this._computeSashLeft((this._startSashPosition! + (e.currentX - e.startX)) / contentWidth, undefined);\n\t\t\tthis._sashRatio.set(sashPosition / contentWidth, undefined);\n\t\t}));\n\t\tthis._register(this._sash.onDidEnd(() => this._sash.layout()));\n\t\tthis._register(this._sash.onDidReset(() => this._sashRatio.set(undefined, undefined)));\n\n\t\tthis._register(autorun(reader => {\n\t\t\tconst sashes = this._sashes.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._options.enableSplitViewResizing.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\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","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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, observableFromEvent, 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 { LengthObj } from 'vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/length';\nimport { IConfigurationService } from 'vs/platform/configuration/common/configuration';\nimport { ContextKeyValue, RawContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';\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 observableConfigValue(key: string, defaultValue: T, configurationService: IConfigurationService): IObservable {\n\treturn observableFromEvent(\n\t\t(handleChange) => configurationService.onDidChangeConfiguration(e => {\n\t\t\tif (e.affectsConfiguration(key)) {\n\t\t\t\thandleChange(e);\n\t\t\t}\n\t\t}),\n\t\t() => configurationService.getValue(key) ?? defaultValue,\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 function deepMerge(source1: T, source2: Partial): T {\n\tconst result = {} as T;\n\tfor (const key in source1) {\n\t\tresult[key] = source1[key];\n\t}\n\tfor (const key in source2) {\n\t\tconst source2Value = source2[key];\n\t\tif (typeof result[key] === 'object' && source2Value && typeof source2Value === 'object') {\n\t\t\tresult[key] = deepMerge(result[key], source2Value);\n\t\t} else {\n\t\t\tresult[key] = source2Value as any;\n\t\t}\n\t}\n\treturn result;\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\tpaddingLeft: number | string;\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(addLength(innerMapping.modifiedRange.getEndPosition(), l));\n\t}\n}\n\nfunction lengthBetweenPositions(position1: Position, position2: Position): LengthObj {\n\tif (position1.lineNumber === position2.lineNumber) {\n\t\treturn new LengthObj(0, position2.column - position1.column);\n\t} else {\n\t\treturn new LengthObj(position2.lineNumber - position1.lineNumber, position2.column - 1);\n\t}\n}\n\nfunction addLength(position: Position, length: LengthObj): Position {\n\tif (length.lineCount === 0) {\n\t\treturn new Position(position.lineNumber, position.column + length.columnCount);\n\t} else {\n\t\treturn new Position(position.lineNumber + length.lineCount, length.columnCount + 1);\n\t}\n}\n\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\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 * 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, viewportData: ViewportData, sb: StringBuilder): boolean;\n\n\t/**\n\t * Layout the line.\n\t */\n\tlayoutLine(lineNumber: number, deltaTop: 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]);\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, 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, 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 { IEditorConfiguration } from 'vs/editor/common/config/editorConfiguration';\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._context.configuration, 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\t\tconst startLineNumber = this._visibleLines.getStartLineNumber();\n\t\tconst endLineNumber = this._visibleLines.getEndLineNumber();\n\t\tfor (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) {\n\t\t\tconst line = this._visibleLines.getVisibleLine(lineNumber);\n\t\t\tline.onConfigurationChanged(e);\n\t\t}\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 _configuration: IEditorConfiguration;\n\tprivate readonly _dynamicOverlays: DynamicViewOverlay[];\n\tprivate _domNode: FastDomNode | null;\n\tprivate _renderedContent: string | null;\n\tprivate _lineHeight: number;\n\n\tconstructor(configuration: IEditorConfiguration, dynamicOverlays: DynamicViewOverlay[]) {\n\t\tthis._configuration = configuration;\n\t\tthis._lineHeight = this._configuration.options.get(EditorOption.lineHeight);\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\tpublic onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): void {\n\t\tthis._lineHeight = this._configuration.options.get(EditorOption.lineHeight);\n\t}\n\n\tpublic renderLine(lineNumber: number, deltaTop: 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): void {\n\t\tif (this._domNode) {\n\t\t\tthis._domNode.setTop(deltaTop);\n\t\t\tthis._domNode.setHeight(this._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\nexport function targetsNotebooks(selector: LanguageSelector): boolean {\n\tif (typeof selector === 'string') {\n\t\treturn false;\n\t} else if (Array.isArray(selector)) {\n\t\treturn selector.some(targetsNotebooks);\n\t} else {\n\t\treturn !!(selector).notebookType;\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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, Event } 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\tpublic readonly onDidChangeContent: Event = this._onDidChangeContent.event;\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\n\t// #region TextBuffer\n\tpublic equals(other: ITextBuffer): boolean {\n\t\tif (!(other instanceof PieceTreeTextBuffer)) {\n\t\t\treturn false;\n\t\t}\n\t\tif (this._BOM !== other._BOM) {\n\t\t\treturn false;\n\t\t}\n\t\tif (this.getEOL() !== other.getEOL()) {\n\t\t\treturn false;\n\t\t}\n\t\treturn this._pieceTree.equal(other._pieceTree);\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 getCharCode(offset: number): number {\n\t\treturn this._pieceTree.getCharCode(offset);\n\t}\n\n\tpublic getLineLength(lineNumber: number): number {\n\t\treturn this._pieceTree.getLineLength(lineNumber);\n\t}\n\n\tpublic getLineMinColumn(lineNumber: number): number {\n\t\treturn 1;\n\t}\n\n\tpublic getLineMaxColumn(lineNumber: number): number {\n\t\treturn this.getLineLength(lineNumber) + 1;\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// #endregion\n\n\t// #region helper\n\t// testing purpose.\n\tpublic getPieceTree(): PieceTreeBase {\n\t\treturn this._pieceTree;\n\t}\n\n\tpublic static _getInverseEditRange(range: Range, text: string) {\n\t\tconst startLineNumber = range.startLineNumber;\n\t\tconst startColumn = range.startColumn;\n\t\tconst [eolCount, firstLineLength, lastLineLength] = countEOL(text);\n\t\tlet resultRange: Range;\n\n\t\tif (text.length > 0) {\n\t\t\t// the operation inserts something\n\t\t\tconst lineCount = eolCount + 1;\n\n\t\t\tif (lineCount === 1) {\n\t\t\t\t// single line insert\n\t\t\t\tresultRange = new Range(startLineNumber, startColumn, startLineNumber, startColumn + firstLineLength);\n\t\t\t} else {\n\t\t\t\t// multi line insert\n\t\t\t\tresultRange = new Range(startLineNumber, startColumn, startLineNumber + lineCount - 1, lastLineLength + 1);\n\t\t\t}\n\t\t} else {\n\t\t\t// There is nothing to insert\n\t\t\tresultRange = new Range(startLineNumber, startColumn, startLineNumber, startColumn);\n\t\t}\n\n\t\treturn resultRange;\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\tpublic getFirstLineText(lengthLimit: number): string {\n\t\treturn this._chunks[0].buffer.substr(0, lengthLimit).split(/\\r\\n|\\r|\\n/)[0];\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\nfunction fromLittleEndianBuffer(buff: VSBuffer): Uint32Array {\n\tconst uint8Arr = buff.buffer;\n\tif (!platform.isLittleEndian()) {\n\t\t// the byte order must be changed\n\t\treverseEndianness(uint8Arr);\n\t}\n\tif (uint8Arr.byteOffset % 4 === 0) {\n\t\treturn new Uint32Array(uint8Arr.buffer, uint8Arr.byteOffset, uint8Arr.length / 4);\n\t} else {\n\t\t// unaligned memory access doesn't work on all platforms\n\t\tconst data = new Uint8Array(uint8Arr.byteLength);\n\t\tdata.set(uint8Arr);\n\t\treturn new Uint32Array(data.buffer, data.byteOffset, data.length / 4);\n\t}\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\nexport function decodeSemanticTokensDto(_buff: VSBuffer): ISemanticTokensDto {\n\tconst src = fromLittleEndianBuffer(_buff);\n\tlet offset = 0;\n\tconst id = src[offset++];\n\tconst type: EncodedSemanticTokensType = src[offset++];\n\tif (type === EncodedSemanticTokensType.Full) {\n\t\tconst length = src[offset++];\n\t\tconst data = src.subarray(offset, offset + length); offset += length;\n\t\treturn {\n\t\t\tid: id,\n\t\t\ttype: 'full',\n\t\t\tdata: data\n\t\t};\n\t}\n\tconst deltaCount = src[offset++];\n\tconst deltas: { start: number; deleteCount: number; data?: Uint32Array }[] = [];\n\tfor (let i = 0; i < deltaCount; i++) {\n\t\tconst start = src[offset++];\n\t\tconst deleteCount = src[offset++];\n\t\tconst length = src[offset++];\n\t\tlet data: Uint32Array | undefined;\n\t\tif (length > 0) {\n\t\t\tdata = src.subarray(offset, offset + length); offset += length;\n\t\t}\n\t\tdeltas[i] = { start, deleteCount, data };\n\t}\n\treturn {\n\t\tid: id,\n\t\ttype: 'delta',\n\t\tdeltas: deltas\n\t};\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { 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 { 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 { SingleTextEdit } from 'vs/editor/contrib/inlineCompletions/browser/singleTextEdit';\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\tpublic toSingleTextEdit(): SingleTextEdit {\n\t\treturn new SingleTextEdit(this.range, this.insertText);\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 { 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/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 { findMaxIdxBy } 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 = findMaxIdxBy(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 { 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.shouldRenderRevertArrows.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.innerChanges,\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[],\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\tthis._widget.revertRangeMappings(this._diffs);\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 * 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 * 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\n/**\n * @internal\n */\nexport function cursorStyleToString(cursorStyle: TextEditorCursorStyle): 'line' | 'block' | 'underline' | 'line-thin' | 'block-outline' | 'underline-thin' {\n\tswitch (cursorStyle) {\n\t\tcase TextEditorCursorStyle.Line: return 'line';\n\t\tcase TextEditorCursorStyle.Block: return 'block';\n\t\tcase TextEditorCursorStyle.Underline: return 'underline';\n\t\tcase TextEditorCursorStyle.LineThin: return 'line-thin';\n\t\tcase TextEditorCursorStyle.BlockOutline: return 'block-outline';\n\t\tcase TextEditorCursorStyle.UnderlineThin: return 'underline-thin';\n\t}\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 IEditorLayoutComputerInput {\n\treadonly outerWidth: number;\n\treadonly outerHeight: number;\n\treadonly isDominatedByLongLines: boolean;\n\treadonly lineHeight: number;\n\treadonly lineNumbersDigitCount: number;\n\treadonly typicalHalfwidthCharacterWidth: number;\n\treadonly maxDigitWidth: number;\n\treadonly pixelRatio: number;\n\treadonly glyphMargin: boolean;\n\treadonly lineDecorationsWidth: string | number;\n\treadonly folding: boolean;\n\treadonly minimap: Readonly>;\n\treadonly scrollbar: InternalEditorScrollbarOptions;\n\treadonly lineNumbers: InternalEditorRenderLineNumbersOptions;\n\treadonly lineNumbersMinChars: number;\n\treadonly scrollBeyondLastLine: boolean;\n\treadonly wordWrap: 'wordWrapColumn' | 'on' | 'off' | 'bounded';\n\treadonly wordWrapColumn: number;\n\treadonly wordWrapMinified: boolean;\n\treadonly accessibilitySupport: AccessibilitySupport;\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.OnCode };\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}\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};\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}\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};\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 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\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 `#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', \"Inserting and deleting whitespace follows 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\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 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\n\tprivate _lastRenderedContent: string;\n\tprivate _renderData: ViewCursorRenderData | null;\n\n\tconstructor(context: ViewContext) {\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\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 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 ${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 { IObservable, ISettableObservable, derived, 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';\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\tconstructor(\n\t\toptions: Readonly,\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))\n\t);\n\tpublic readonly readOnly = derived(this, reader => this._options.read(reader).readOnly);\n\n\tpublic readonly shouldRenderRevertArrows = 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\treturn true;\n\t});\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};\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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, EditorOptions, 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\tpublic static createFromRawSettings(opts: { fontFamily?: string; fontWeight?: string; fontSize?: number; fontLigatures?: boolean | string; fontVariations?: boolean | string; lineHeight?: number; letterSpacing?: number }, pixelRatio: number, ignoreEditorZoom: boolean = false): BareFontInfo {\n\t\tconst fontFamily = EditorOptions.fontFamily.validate(opts.fontFamily);\n\t\tconst fontWeight = EditorOptions.fontWeight.validate(opts.fontWeight);\n\t\tconst fontSize = EditorOptions.fontSize.validate(opts.fontSize);\n\t\tconst fontFeatureSettings = EditorOptions.fontLigatures2.validate(opts.fontLigatures);\n\t\tconst fontVariationSettings = EditorOptions.fontVariations.validate(opts.fontVariations);\n\t\tconst lineHeight = EditorOptions.lineHeight.validate(opts.lineHeight);\n\t\tconst letterSpacing = EditorOptions.letterSpacing.validate(opts.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, SERIALIZED_FONT_INFO_VERSION } from 'vs/editor/common/config/fontInfo';\n\n/**\n * Serializable font information.\n */\nexport interface ISerializedFontInfo {\n\treadonly version: number;\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\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\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 * Serialized currently cached font information.\n\t */\n\tpublic serializeFontInfo(targetWindow: Window): ISerializedFontInfo[] {\n\t\t// Only save trusted font info (that has been measured in this running instance)\n\t\tconst cache = this._ensureCache(targetWindow);\n\t\treturn cache.getValues().filter(item => item.isTrusted);\n\t}\n\n\t/**\n\t * Restore previously serialized font informations.\n\t */\n\tpublic restoreFontInfo(targetWindow: Window, savedFontInfos: ISerializedFontInfo[]): void {\n\t\t// Take all the saved font info and insert them in the cache without the trusted flag.\n\t\t// The reason for this is that a font might have been installed on the OS in the meantime.\n\t\tfor (const savedFontInfo of savedFontInfos) {\n\t\t\tif (savedFontInfo.version !== SERIALIZED_FONT_INFO_VERSION) {\n\t\t\t\t// cannot use older version\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst fontInfo = new FontInfo(savedFontInfo, false);\n\t\t\tthis._writeToCache(targetWindow, fontInfo, fontInfo);\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","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { 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 { 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 { EditOperation, 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 * 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';\nimport { LanguageFilter } from 'vs/editor/common/languageSelector';\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\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 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): ProviderResult;\n}\n\n/**\n * An evaluatable expression represents additional information for an expression in a document. Evaluatable expressions are\n * evaluated by a debugger or runtime and their result is rendered in a tooltip-like widget.\n * @internal\n */\nexport interface EvaluatableExpression {\n\t/**\n\t * The range to which this expression applies.\n\t */\n\trange: IRange;\n\t/**\n\t * This expression overrides the expression extracted from the range.\n\t */\n\texpression?: string;\n}\n\n\n/**\n * The evaluatable expression provider interface defines the contract between extensions and\n * the debug hover.\n * @internal\n */\nexport interface EvaluatableExpressionProvider {\n\t/**\n\t * Provide a hover for the given position 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\tprovideEvaluatableExpression(model: model.ITextModel, position: Position, token: CancellationToken): ProviderResult;\n}\n\n/**\n * A value-object that contains contextual information when requesting inline values from a InlineValuesProvider.\n * @internal\n */\nexport interface InlineValueContext {\n\tframeId: number;\n\tstoppedLocation: Range;\n}\n\n/**\n * Provide inline value as text.\n * @internal\n */\nexport interface InlineValueText {\n\ttype: 'text';\n\trange: IRange;\n\ttext: string;\n}\n\n/**\n * Provide inline value through a variable lookup.\n * @internal\n */\nexport interface InlineValueVariableLookup {\n\ttype: 'variable';\n\trange: IRange;\n\tvariableName?: string;\n\tcaseSensitiveLookup: boolean;\n}\n\n/**\n * Provide inline value through an expression evaluation.\n * @internal\n */\nexport interface InlineValueExpression {\n\ttype: 'expression';\n\trange: IRange;\n\texpression?: string;\n}\n\n/**\n * Inline value information can be provided by different means:\n * - directly as a text value (class InlineValueText).\n * - as a name to use for a variable lookup (class InlineValueVariableLookup)\n * - as an evaluatable expression (class InlineValueEvaluatableExpression)\n * The InlineValue types combines all inline value types into one type.\n * @internal\n */\nexport type InlineValue = InlineValueText | InlineValueVariableLookup | InlineValueExpression;\n\n/**\n * The inline values provider interface defines the contract between extensions and\n * the debugger's inline values feature.\n * @internal\n */\nexport interface InlineValuesProvider {\n\t/**\n\t */\n\tonDidChangeInlineValues?: Event | undefined;\n\t/**\n\t * Provide the \"inline values\" for the given range 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\tprovideInlineValues(model: model.ITextModel, viewPort: Range, context: InlineValueContext, token: CancellationToken): ProviderResult;\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\t/**\n\t * @internal\n\t */\n\t_id?: [number, number];\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 * 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): 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 label: string;\n\treadonly detail: string;\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 DocumentPasteContext {\n\treadonly only?: string;\n\treadonly trigger: 'explicit' | 'implicit';\n}\n\n/**\n * @internal\n */\nexport interface DocumentPasteEditProvider {\n\n\treadonly id: string;\n\n\treadonly copyMimeTypes?: readonly string[];\n\treadonly pasteMimeTypes?: readonly string[];\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\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\tselector: LanguageFilter;\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\tstatic asEditOperation(edit: TextEdit): ISingleEditOperation {\n\t\treturn EditOperation.replace(Range.lift(edit.range), edit.text);\n\t}\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\n\t/**\n\t * @internal\n\t */\n\treadonly extensionId?: ExtensionIdentifier;\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 * @internal\n\t */\n\treadonly id?: string;\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\t/**\n\t * @internal\n\t */\n\ticonPath?: ThemeIcon | URI | { light: URI; dark: URI };\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\t/**\n\t * @internal\n\t */\n\tcontents?: Promise;\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 interface NewSymbolName {\n\treadonly newSymbolName: string;\n\treadonly tags?: readonly NewSymbolNameTag[];\n}\n\nexport interface NewSymbolNamesProvider {\n\tprovideNewSymbolNames(model: model.ITextModel, range: IRange, 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\n/**\n * @internal\n */\nexport interface CommentThreadTemplate {\n\tcontrollerHandle: number;\n\tlabel: string;\n\tacceptInputCommand?: Command;\n\tadditionalCommands?: Command[];\n\tdeleteCommand?: Command;\n}\n\n/**\n * @internal\n */\nexport interface CommentInfo {\n\textensionId?: string;\n\tthreads: CommentThread[];\n\tpendingCommentThreads?: PendingCommentThread[];\n\tcommentingRanges: CommentingRanges;\n}\n\n/**\n * @internal\n */\nexport enum CommentThreadCollapsibleState {\n\t/**\n\t * Determines an item is collapsed\n\t */\n\tCollapsed = 0,\n\t/**\n\t * Determines an item is expanded\n\t */\n\tExpanded = 1\n}\n\n/**\n * @internal\n */\nexport enum CommentThreadState {\n\tUnresolved = 0,\n\tResolved = 1\n}\n\n/**\n * @internal\n */\nexport interface CommentWidget {\n\tcommentThread: CommentThread;\n\tcomment?: Comment;\n\tinput: string;\n\tonDidChangeInput: Event;\n}\n\n/**\n * @internal\n */\nexport interface CommentInput {\n\tvalue: string;\n\turi: URI;\n}\n\n/**\n * @internal\n */\nexport interface CommentThread {\n\tisDocumentCommentThread(): this is CommentThread;\n\tcommentThreadHandle: number;\n\tcontrollerHandle: number;\n\textensionId?: string;\n\tthreadId: string;\n\tresource: string | null;\n\trange: T | undefined;\n\tlabel: string | undefined;\n\tcontextValue: string | undefined;\n\tcomments: Comment[] | undefined;\n\tonDidChangeComments: Event;\n\tcollapsibleState?: CommentThreadCollapsibleState;\n\tinitialCollapsibleState?: CommentThreadCollapsibleState;\n\tonDidChangeInitialCollapsibleState: Event;\n\tstate?: CommentThreadState;\n\tcanReply: boolean;\n\tinput?: CommentInput;\n\tonDidChangeInput: Event;\n\tonDidChangeRange: Event;\n\tonDidChangeLabel: Event;\n\tonDidChangeCollapsibleState: Event;\n\tonDidChangeState: Event;\n\tonDidChangeCanReply: Event;\n\tisDisposed: boolean;\n\tisTemplate: boolean;\n}\n\n/**\n * @internal\n */\n\nexport interface CommentingRanges {\n\treadonly resource: URI;\n\tranges: IRange[];\n\tfileComments: boolean;\n}\n\nexport interface CommentAuthorInformation {\n\tname: string;\n\ticonPath?: UriComponents;\n\n}\n\n/**\n * @internal\n */\nexport interface CommentReaction {\n\treadonly label?: string;\n\treadonly iconPath?: UriComponents;\n\treadonly count?: number;\n\treadonly hasReacted?: boolean;\n\treadonly canEdit?: boolean;\n\treadonly reactors?: readonly string[];\n}\n\n/**\n * @internal\n */\nexport interface CommentOptions {\n\t/**\n\t * An optional string to show on the comment input box when it's collapsed.\n\t */\n\tprompt?: string;\n\n\t/**\n\t * An optional string to show as placeholder in the comment input box when it's focused.\n\t */\n\tplaceHolder?: string;\n}\n\n/**\n * @internal\n */\nexport enum CommentMode {\n\tEditing = 0,\n\tPreview = 1\n}\n\n/**\n * @internal\n */\nexport enum CommentState {\n\tPublished = 0,\n\tDraft = 1\n}\n\n/**\n * @internal\n */\nexport interface Comment {\n\treadonly uniqueIdInThread: number;\n\treadonly body: string | IMarkdownString;\n\treadonly userName: string;\n\treadonly userIconPath?: UriComponents;\n\treadonly contextValue?: string;\n\treadonly commentReactions?: CommentReaction[];\n\treadonly label?: string;\n\treadonly mode?: CommentMode;\n\treadonly timestamp?: string;\n}\n\nexport interface PendingCommentThread {\n\tbody: string;\n\trange: IRange | undefined;\n\turi: URI;\n\towner: string;\n\tisReply: boolean;\n}\n\n/**\n * @internal\n */\nexport interface CommentThreadChangedEvent {\n\t/**\n\t * Pending comment threads.\n\t */\n\treadonly pending: PendingCommentThread[];\n\n\t/**\n\t * Added comment threads.\n\t */\n\treadonly added: CommentThread[];\n\n\t/**\n\t * Removed comment threads.\n\t */\n\treadonly removed: CommentThread[];\n\n\t/**\n\t * Changed comment threads.\n\t */\n\treadonly changed: CommentThread[];\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/**\n * @internal\n */\nexport enum ExternalUriOpenerPriority {\n\tNone = 0,\n\tOption = 1,\n\tDefault = 2,\n\tPreferred = 3,\n}\n\n/**\n * @internal\n */\nexport type DropYieldTo = { readonly providerId: string } | { readonly mimeType: string };\n\n/**\n * @internal\n */\nexport interface DocumentOnDropEdit {\n\treadonly label: string;\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 DocumentOnDropEditProvider {\n\treadonly id?: string;\n\treadonly dropMimeTypes?: readonly string[];\n\n\tprovideDocumentOnDropEdits(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 function tokenizeToStringSync(languageService: ILanguageService, text: string, languageId: string): string {\n\treturn _tokenizeToString(text, languageService.languageIdCodec, TokenizationRegistry.get(languageId) || fallback);\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 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\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\ninterface RangePriorityQueue {\n\tget min(): number | null;\n\tremoveMin(): number | null;\n\n\taddRange(range: OffsetRange): void;\n\n\taddRangeAndResize(range: OffsetRange, newLength: number): void;\n}\n\nexport class RangePriorityQueueImpl implements RangePriorityQueue {\n\tprivate readonly _ranges: OffsetRange[] = [];\n\n\tpublic getRanges(): OffsetRange[] {\n\t\treturn this._ranges;\n\t}\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 removeMin(): number | null {\n\t\tif (this._ranges.length === 0) {\n\t\t\treturn null;\n\t\t}\n\t\tconst range = this._ranges[0];\n\t\tif (range.start + 1 === range.endExclusive) {\n\t\t\tthis._ranges.shift();\n\t\t} else {\n\t\t\tthis._ranges[0] = new OffsetRange(range.start + 1, range.endExclusive);\n\t\t}\n\t\treturn range.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\t_hasListeners(): boolean {\n\t\treturn (this._onDidChangeLanguage.hasListeners()\n\t\t\t|| this._onDidChangeLanguageConfiguration.hasListeners()\n\t\t\t|| this._onDidChangeTokens.hasListeners());\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 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 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 { DiffComputer, IChange } from 'vs/editor/common/diff/legacyLinesDiffComputer';\nimport { ILinesDiffComputer, ILinesDiffComputerOptions } 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 { BugIndicatingError } from 'vs/base/common/errors';\nimport { IDocumentColorComputerTarget, computeDefaultDocumentColors } from 'vs/editor/common/languages/defaultDocumentColorsComputer';\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\turi: URI;\n\tversion: number;\n\teol: string;\n\tgetValue(): 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\tgetWordUntilPosition(position: IPosition, wordDefinition: RegExp): IWordAtPosition;\n\tgetValueInRange(range: IRange): string;\n\tgetWordAtPosition(position: IPosition, wordDefinition: RegExp): Range | null;\n\toffsetAt(position: IPosition): number;\n\tpositionAt(offset: number): IPosition;\n\tfindMatches(regex: RegExp): RegExpMatchArray[];\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\tpublic getWordUntilPosition(position: IPosition, wordDefinition: RegExp): IWordAtPosition {\n\t\tconst wordAtPosition = this.getWordAtPosition(position, wordDefinition);\n\t\tif (!wordAtPosition) {\n\t\t\treturn {\n\t\t\t\tword: '',\n\t\t\t\tstartColumn: position.column,\n\t\t\t\tendColumn: position.column\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tword: this._lines[position.lineNumber - 1].substring(wordAtPosition.startColumn - 1, position.column - 1),\n\t\t\tstartColumn: wordAtPosition.startColumn,\n\t\t\tendColumn: position.column\n\t\t};\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\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\tpublic async computeDirtyDiff(originalUrl: string, modifiedUrl: string, ignoreTrimWhitespace: boolean): 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 originalLines = original.getLinesContent();\n\t\tconst modifiedLines = modified.getLinesContent();\n\t\tconst diffComputer = new DiffComputer(originalLines, modifiedLines, {\n\t\t\tshouldComputeCharChanges: false,\n\t\t\tshouldPostProcessCharChanges: false,\n\t\t\tshouldIgnoreTrimWhitespace: ignoreTrimWhitespace,\n\t\t\tshouldMakePrettyDiff: true,\n\t\t\tmaxComputationTime: 1000\n\t\t});\n\t\treturn diffComputer.computeDiff().changes;\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\tpublic computeHumanReadableDiff(modelUrl: string, edits: TextEdit[], options: ILinesDiffComputerOptions): TextEdit[] {\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\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\n\t\t\tconst originalLines = original.split(/\\r\\n|\\n|\\r/);\n\t\t\tconst modifiedLines = text.split(/\\r\\n|\\n|\\r/);\n\n\t\t\tconst diff = linesDiffComputers.getDefault().computeDiff(originalLines, modifiedLines, options);\n\n\t\t\tconst start = Range.lift(range).getStartPosition();\n\n\t\t\tfunction addPositions(pos1: Position, pos2: Position): Position {\n\t\t\t\treturn new Position(pos1.lineNumber + pos2.lineNumber - 1, pos2.lineNumber === 1 ? pos1.column + pos2.column - 1 : pos2.column);\n\t\t\t}\n\n\t\t\tfunction getText(lines: string[], range: Range): string[] {\n\t\t\t\tconst result: string[] = [];\n\t\t\t\tfor (let i = range.startLineNumber; i <= range.endLineNumber; i++) {\n\t\t\t\t\tconst line = lines[i - 1];\n\t\t\t\t\tif (i === range.startLineNumber && i === range.endLineNumber) {\n\t\t\t\t\t\tresult.push(line.substring(range.startColumn - 1, range.endColumn - 1));\n\t\t\t\t\t} else if (i === range.startLineNumber) {\n\t\t\t\t\t\tresult.push(line.substring(range.startColumn - 1));\n\t\t\t\t\t} else if (i === range.endLineNumber) {\n\t\t\t\t\t\tresult.push(line.substring(0, range.endColumn - 1));\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresult.push(line);\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\tfor (const c of diff.changes) {\n\t\t\t\tif (c.innerChanges) {\n\t\t\t\t\tfor (const x of c.innerChanges) {\n\t\t\t\t\t\tresult.push({\n\t\t\t\t\t\t\trange: Range.fromPositions(\n\t\t\t\t\t\t\t\taddPositions(start, x.originalRange.getStartPosition()),\n\t\t\t\t\t\t\t\taddPositions(start, x.originalRange.getEndPosition())\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\ttext: getText(modifiedLines, x.modifiedRange).join(model.eol)\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tthrow new BugIndicatingError('The experimental diff algorithm always produces inner changes');\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 setDelegate(delegate: IUndoRedoDelegate): void {\n\t\tthis._delegate = delegate;\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 getMissingModels(): URI[] {\n\t\tconst result: URI[] = [];\n\t\tfor (const editStackElement of this._editStackElementsArr) {\n\t\t\tif (URI.isUri(editStackElement.model)) {\n\t\t\t\tresult.push(editStackElement.model);\n\t\t\t}\n\t\t}\n\t\treturn result;\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 AccessibilityHelpNLS {\n\texport const accessibilityHelpTitle = nls.localize('accessibilityHelpTitle', \"Accessibility Help\");\n\texport const openingDocs = nls.localize(\"openingDocs\", \"Opening the Accessibility documentation page.\");\n\texport const readonlyDiffEditor = nls.localize(\"readonlyDiffEditor\", \"You are in a read-only pane of a diff editor.\");\n\texport const editableDiffEditor = nls.localize(\"editableDiffEditor\", \"You are in a pane of a diff editor.\");\n\texport const readonlyEditor = nls.localize(\"readonlyEditor\", \"You are in a read-only code editor.\");\n\texport const editableEditor = nls.localize(\"editableEditor\", \"You are in a code editor.\");\n\texport const changeConfigToOnMac = nls.localize(\"changeConfigToOnMac\", \"Configure the application to be optimized for usage with a Screen Reader (Command+E).\");\n\texport const changeConfigToOnWinLinux = nls.localize(\"changeConfigToOnWinLinux\", \"Configure the application to be optimized for usage with a Screen Reader (Control+E).\");\n\texport const auto_on = nls.localize(\"auto_on\", \"The application is configured to be optimized for usage with a Screen Reader.\");\n\texport const auto_off = nls.localize(\"auto_off\", \"The application is configured to never be optimized for usage with a Screen Reader.\");\n\texport const screenReaderModeEnabled = nls.localize(\"screenReaderModeEnabled\", \"Screen Reader Optimized Mode enabled.\");\n\texport const screenReaderModeDisabled = nls.localize(\"screenReaderModeDisabled\", \"Screen Reader Optimized Mode disabled.\");\n\texport const tabFocusModeOnMsg = nls.localize(\"tabFocusModeOnMsg\", \"Pressing Tab in the current editor will move focus to the next focusable element. Toggle this behavior {0}.\");\n\texport const tabFocusModeOnMsgNoKb = nls.localize(\"tabFocusModeOnMsgNoKb\", \"Pressing Tab in the current editor will move focus to the next focusable element. The command {0} is currently not triggerable by a keybinding.\");\n\texport const stickScrollKb = nls.localize(\"stickScrollKb\", \"Focus Sticky Scroll ({0}) to focus the currently nested scopes.\");\n\texport const stickScrollNoKb = nls.localize(\"stickScrollNoKb\", \"Focus Sticky Scroll to focus the currently nested scopes. It is currently not triggerable by a keybinding.\");\n\texport const tabFocusModeOffMsg = nls.localize(\"tabFocusModeOffMsg\", \"Pressing Tab in the current editor will insert the tab character. Toggle this behavior {0}.\");\n\texport const tabFocusModeOffMsgNoKb = nls.localize(\"tabFocusModeOffMsgNoKb\", \"Pressing Tab in the current editor will insert the tab character. The command {0} is currently not triggerable by a keybinding.\");\n\texport const showAccessibilityHelpAction = nls.localize(\"showAccessibilityHelpAction\", \"Show Accessibility Help\");\n\texport const listSignalSounds = nls.localize(\"listSignalSoundsCommand\", \"Run the command: List Signal Sounds for an overview of all sounds and their current status.\");\n\texport const listAlerts = nls.localize(\"listAnnouncementsCommand\", \"Run the command: List Signal Announcements for an overview of announcements and their current status.\");\n\texport const quickChat = nls.localize(\"quickChatCommand\", \"Toggle quick chat ({0}) to open or close a chat session.\");\n\texport const quickChatNoKb = nls.localize(\"quickChatCommandNoKb\", \"Toggle quick chat is not currently triggerable by a keybinding.\");\n\texport const startInlineChat = nls.localize(\"startInlineChatCommand\", \"Start inline chat ({0}) to create an in editor chat session.\");\n\texport const startInlineChatNoKb = nls.localize(\"startInlineChatCommandNoKb\", \"The command: Start inline chat is not currentlyt riggerable by a keybinding.\");\n}\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\tpublic inflate() {\n\t\tconst result: [number, number, number][] = [];\n\t\tfor (let i = 0; i < this.length; i++) {\n\t\t\tconst partData = this._data[i];\n\t\t\tconst partIndex = CharacterMapping.getPartIndex(partData);\n\t\t\tconst charIndex = CharacterMapping.getCharIndex(partData);\n\t\t\tconst visibleColumn = this._horizontalOffset[i];\n\t\t\tresult.push([partIndex, charIndex, visibleColumn]);\n\t\t}\n\t\treturn result;\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 { URI, UriDto } 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\ttooltip?: string;\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 ICommandActionSource {\n\treadonly id: string;\n\treadonly title: string;\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\tsource?: ICommandActionSource;\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\nexport type ISerializableCommandAction = UriDto;\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 * as platform from 'vs/base/common/platform';\nimport type { IExperimentationFilterProvider } from 'tas-client-umd';\n\nexport const ASSIGNMENT_STORAGE_KEY = 'VSCode.ABExp.FeatureData';\nexport const ASSIGNMENT_REFETCH_INTERVAL = 0; // no polling\n\nexport interface IAssignmentService {\n\treadonly _serviceBrand: undefined;\n\tgetTreatment(name: string): Promise;\n}\n\nexport enum TargetPopulation {\n\tInsiders = 'insider',\n\tPublic = 'public',\n\tExploration = 'exploration'\n}\n\n/*\nBased upon the official VSCode currently existing filters in the\nExP backend for the VSCode cluster.\nhttps://experimentation.visualstudio.com/Analysis%20and%20Experimentation/_git/AnE.ExP.TAS.TachyonHost.Configuration?path=%2FConfigurations%2Fvscode%2Fvscode.json&version=GBmaster\n\"X-MSEdge-Market\": \"detection.market\",\n\"X-FD-Corpnet\": \"detection.corpnet\",\n\"X-VSCode-AppVersion\": \"appversion\",\n\"X-VSCode-Build\": \"build\",\n\"X-MSEdge-ClientId\": \"clientid\",\n\"X-VSCode-ExtensionName\": \"extensionname\",\n\"X-VSCode-ExtensionVersion\": \"extensionversion\",\n\"X-VSCode-TargetPopulation\": \"targetpopulation\",\n\"X-VSCode-Language\": \"language\"\n*/\nexport enum Filters {\n\t/**\n\t * The market in which the extension is distributed.\n\t */\n\tMarket = 'X-MSEdge-Market',\n\n\t/**\n\t * The corporation network.\n\t */\n\tCorpNet = 'X-FD-Corpnet',\n\n\t/**\n\t * Version of the application which uses experimentation service.\n\t */\n\tApplicationVersion = 'X-VSCode-AppVersion',\n\n\t/**\n\t * Insiders vs Stable.\n\t */\n\tBuild = 'X-VSCode-Build',\n\n\t/**\n\t * Client Id which is used as primary unit for the experimentation.\n\t */\n\tClientId = 'X-MSEdge-ClientId',\n\n\t/**\n\t * Extension header.\n\t */\n\tExtensionName = 'X-VSCode-ExtensionName',\n\n\t/**\n\t * The version of the extension.\n\t */\n\tExtensionVersion = 'X-VSCode-ExtensionVersion',\n\n\t/**\n\t * The language in use by VS Code\n\t */\n\tLanguage = 'X-VSCode-Language',\n\n\t/**\n\t * The target population.\n\t * This is used to separate internal, early preview, GA, etc.\n\t */\n\tTargetPopulation = 'X-VSCode-TargetPopulation',\n}\n\nexport class AssignmentFilterProvider implements IExperimentationFilterProvider {\n\tconstructor(\n\t\tprivate version: string,\n\t\tprivate appName: string,\n\t\tprivate machineId: string,\n\t\tprivate targetPopulation: TargetPopulation\n\t) { }\n\n\t/**\n\t * Returns a version string that can be parsed by the TAS client.\n\t * The tas client cannot handle suffixes lke \"-insider\"\n\t * Ref: https://github.com/microsoft/tas-client/blob/30340d5e1da37c2789049fcf45928b954680606f/vscode-tas-client/src/vscode-tas-client/VSCodeFilterProvider.ts#L35\n\t *\n\t * @param version Version string to be trimmed.\n\t*/\n\tprivate static trimVersionSuffix(version: string): string {\n\t\tconst regex = /\\-[a-zA-Z0-9]+$/;\n\t\tconst result = version.split(regex);\n\n\t\treturn result[0];\n\t}\n\n\tgetFilterValue(filter: string): string | null {\n\t\tswitch (filter) {\n\t\t\tcase Filters.ApplicationVersion:\n\t\t\t\treturn AssignmentFilterProvider.trimVersionSuffix(this.version); // productService.version\n\t\t\tcase Filters.Build:\n\t\t\t\treturn this.appName; // productService.nameLong\n\t\t\tcase Filters.ClientId:\n\t\t\t\treturn this.machineId;\n\t\t\tcase Filters.Language:\n\t\t\t\treturn platform.language;\n\t\t\tcase Filters.ExtensionName:\n\t\t\t\treturn 'vscode-core'; // always return vscode-core for exp service\n\t\t\tcase Filters.ExtensionVersion:\n\t\t\t\treturn '999999.0'; // always return a very large number for cross-extension experimentation\n\t\t\tcase Filters.TargetPopulation:\n\t\t\t\treturn this.targetPopulation;\n\t\t\tdefault:\n\t\t\t\treturn '';\n\t\t}\n\t}\n\n\tgetFilters(): Map {\n\t\tconst filters: Map = new Map();\n\t\tconst filterValues = Object.values(Filters);\n\t\tfor (const value of filterValues) {\n\t\t\tfilters.set(value, this.getFilterValue(value));\n\t\t}\n\n\t\treturn filters;\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { IWorkspaceIdentifier } from 'vs/platform/workspace/common/workspace';\n\nexport interface IBaseBackupInfo {\n\tremoteAuthority?: string;\n}\n\nexport interface IWorkspaceBackupInfo extends IBaseBackupInfo {\n\treadonly workspace: IWorkspaceIdentifier;\n}\n\nexport interface IFolderBackupInfo extends IBaseBackupInfo {\n\treadonly folderUri: URI;\n}\n\nexport function isFolderBackupInfo(curr: IWorkspaceBackupInfo | IFolderBackupInfo): curr is IFolderBackupInfo {\n\treturn curr && curr.hasOwnProperty('folderUri');\n}\n\nexport function isWorkspaceBackupInfo(curr: IWorkspaceBackupInfo | IFolderBackupInfo): curr is IWorkspaceBackupInfo {\n\treturn curr && curr.hasOwnProperty('workspace');\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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\tget errors(): Readonly {\n\t\treturn this._errors;\n\t}\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 { Emitter, Event } from 'vs/base/common/event';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';\nimport { IAttachSessionEvent, ICloseSessionEvent, IExtensionHostDebugService, IOpenExtensionWindowResult, IReloadSessionEvent, ITerminateSessionEvent } from 'vs/platform/debug/common/extensionHostDebug';\n\nexport class ExtensionHostDebugBroadcastChannel implements IServerChannel {\n\n\tstatic readonly ChannelName = 'extensionhostdebugservice';\n\n\tprivate readonly _onCloseEmitter = new Emitter();\n\tprivate readonly _onReloadEmitter = new Emitter();\n\tprivate readonly _onTerminateEmitter = new Emitter();\n\tprivate readonly _onAttachEmitter = new Emitter();\n\n\tcall(ctx: TContext, command: string, arg?: any): Promise {\n\t\tswitch (command) {\n\t\t\tcase 'close':\n\t\t\t\treturn Promise.resolve(this._onCloseEmitter.fire({ sessionId: arg[0] }));\n\t\t\tcase 'reload':\n\t\t\t\treturn Promise.resolve(this._onReloadEmitter.fire({ sessionId: arg[0] }));\n\t\t\tcase 'terminate':\n\t\t\t\treturn Promise.resolve(this._onTerminateEmitter.fire({ sessionId: arg[0] }));\n\t\t\tcase 'attach':\n\t\t\t\treturn Promise.resolve(this._onAttachEmitter.fire({ sessionId: arg[0], port: arg[1], subId: arg[2] }));\n\t\t}\n\t\tthrow new Error('Method not implemented.');\n\t}\n\n\tlisten(ctx: TContext, event: string, arg?: any): Event {\n\t\tswitch (event) {\n\t\t\tcase 'close':\n\t\t\t\treturn this._onCloseEmitter.event;\n\t\t\tcase 'reload':\n\t\t\t\treturn this._onReloadEmitter.event;\n\t\t\tcase 'terminate':\n\t\t\t\treturn this._onTerminateEmitter.event;\n\t\t\tcase 'attach':\n\t\t\t\treturn this._onAttachEmitter.event;\n\t\t}\n\t\tthrow new Error('Method not implemented.');\n\t}\n}\n\nexport class ExtensionHostDebugChannelClient extends Disposable implements IExtensionHostDebugService {\n\n\tdeclare readonly _serviceBrand: undefined;\n\n\tconstructor(private channel: IChannel) {\n\t\tsuper();\n\t}\n\n\treload(sessionId: string): void {\n\t\tthis.channel.call('reload', [sessionId]);\n\t}\n\n\tget onReload(): Event {\n\t\treturn this.channel.listen('reload');\n\t}\n\n\tclose(sessionId: string): void {\n\t\tthis.channel.call('close', [sessionId]);\n\t}\n\n\tget onClose(): Event {\n\t\treturn this.channel.listen('close');\n\t}\n\n\tattachSession(sessionId: string, port: number, subId?: string): void {\n\t\tthis.channel.call('attach', [sessionId, port, subId]);\n\t}\n\n\tget onAttachSession(): Event {\n\t\treturn this.channel.listen('attach');\n\t}\n\n\tterminateSession(sessionId: string, subId?: string): void {\n\t\tthis.channel.call('terminate', [sessionId, subId]);\n\t}\n\n\tget onTerminateSession(): Event {\n\t\treturn this.channel.listen('terminate');\n\t}\n\n\topenExtensionDevelopmentHostWindow(args: string[], debugRenderer: boolean): Promise {\n\t\treturn this.channel.call('openExtensionDevelopmentHostWindow', [args, debugRenderer]);\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { IURITransformer } from 'vs/base/common/uriIpc';\nimport { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';\nimport { IDownloadService } from 'vs/platform/download/common/download';\n\nexport class DownloadServiceChannel implements IServerChannel {\n\n\tconstructor(private readonly service: IDownloadService) { }\n\n\tlisten(_: unknown, event: string, arg?: any): Event {\n\t\tthrow new Error('Invalid listen');\n\t}\n\n\tcall(context: any, command: string, args?: any): Promise {\n\t\tswitch (command) {\n\t\t\tcase 'download': return this.service.download(URI.revive(args[0]), URI.revive(args[1]));\n\t\t}\n\t\tthrow new Error('Invalid call');\n\t}\n}\n\nexport class DownloadServiceChannelClient implements IDownloadService {\n\n\tdeclare readonly _serviceBrand: undefined;\n\n\tconstructor(private channel: IChannel, private getUriTransformer: () => IURITransformer | null) { }\n\n\tasync download(from: URI, to: URI): Promise {\n\t\tconst uriTransformer = this.getUriTransformer();\n\t\tif (uriTransformer) {\n\t\t\tfrom = uriTransformer.transformOutgoingURI(from);\n\t\t\tto = uriTransformer.transformOutgoingURI(to);\n\t\t}\n\t\tawait this.channel.call('download', [from, to]);\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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\t/**\n\t * Resolves the model.\n\t */\n\tresolve(): Promise;\n\n\t/**\n\t * Find out if the editor model was resolved or not.\n\t */\n\tisResolved(): boolean;\n}\n\nexport function isResolvedEditorModel(model: IDisposable | undefined | null): model is IResolvableEditorModel {\n\tconst candidate = model as IResolvableEditorModel | undefined | null;\n\n\treturn typeof candidate?.resolve === 'function'\n\t\t&& typeof candidate?.isResolved === 'function';\n}\n\nexport interface IBaseUntypedEditorInput {\n\n\t/**\n\t * Optional options to use when opening the input.\n\t */\n\toptions?: IEditorOptions;\n\n\t/**\n\t * Label to show for the input.\n\t */\n\treadonly label?: string;\n\n\t/**\n\t * Description to show for the input.\n\t */\n\treadonly description?: string;\n}\n\nexport interface IBaseResourceEditorInput extends IBaseUntypedEditorInput {\n\n\t/**\n\t * Hint to indicate that this input should be treated as a\n\t * untitled file.\n\t *\n\t * Without this hint, the editor service will make a guess by\n\t * looking at the scheme of the resource(s).\n\t *\n\t * Use `forceUntitled: true` when you pass in a `resource` that\n\t * does not use the `untitled` scheme. The `resource` will then\n\t * be used as associated path when saving the untitled file.\n\t */\n\treadonly forceUntitled?: boolean;\n}\n\nexport interface IBaseTextResourceEditorInput extends IBaseResourceEditorInput {\n\n\t/**\n\t * Optional options to use when opening the text input.\n\t */\n\toptions?: ITextEditorOptions;\n\n\t/**\n\t * The contents of the text input if known. If provided,\n\t * the input will not attempt to load the contents from\n\t * disk and may appear dirty.\n\t */\n\tcontents?: string;\n\n\t/**\n\t * The encoding of the text input if known.\n\t */\n\tencoding?: string;\n\n\t/**\n\t * The identifier of the language id of the text input\n\t * if known to use when displaying the contents.\n\t */\n\tlanguageId?: string;\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\n/**\n * This identifier allows to uniquely identify an editor with a\n * resource, type and editor identifier.\n */\nexport interface IResourceEditorInputIdentifier {\n\n\t/**\n\t * The type of the editor.\n\t */\n\treadonly typeId: string;\n\n\t/**\n\t * The identifier of the editor if provided.\n\t */\n\treadonly editorId: string | undefined;\n\n\t/**\n\t * The resource URI of the editor.\n\t */\n\treadonly resource: URI;\n}\n\nexport enum EditorActivation {\n\n\t/**\n\t * Activate the editor after it opened. This will automatically restore\n\t * the editor if it is minimized.\n\t */\n\tACTIVATE = 1,\n\n\t/**\n\t * Only restore the editor if it is minimized but do not activate it.\n\t *\n\t * Note: will only work in combination with the `preserveFocus: true` option.\n\t * Otherwise, if focus moves into the editor, it will activate and restore\n\t * automatically.\n\t */\n\tRESTORE,\n\n\t/**\n\t * Preserve the current active editor.\n\t *\n\t * Note: will only work in combination with the `preserveFocus: true` option.\n\t * Otherwise, if focus moves into the editor, it will activate and restore\n\t * automatically.\n\t */\n\tPRESERVE\n}\n\nexport enum EditorResolution {\n\n\t/**\n\t * Displays a picker and allows the user to decide which editor to use.\n\t */\n\tPICK,\n\n\t/**\n\t * Only exclusive editors are considered.\n\t */\n\tEXCLUSIVE_ONLY\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 * This option is only relevant if an editor is opened into a group that is not active\n\t * already and allows to control if the inactive group should become active, restored\n\t * or preserved.\n\t *\n\t * By default, the editor group will become active unless `preserveFocus` or `inactive`\n\t * is specified.\n\t */\n\tactivation?: EditorActivation;\n\n\t/**\n\t * Tells the editor to reload the editor input in the editor even if it is identical to the one\n\t * already showing. By default, the editor will not reload the input if it is identical to the\n\t * one showing.\n\t */\n\tforceReload?: 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 * An editor that is sticky moves to the beginning of the editors list within the group and will remain\n\t * there unless explicitly closed. Operations such as \"Close All\" will not close sticky editors.\n\t */\n\tsticky?: boolean;\n\n\t/**\n\t * The index in the document stack where to insert the editor into when opening.\n\t */\n\tindex?: number;\n\n\t/**\n\t * An active editor that is opened will show its contents directly. Set to true to open an editor\n\t * in the background without loading its contents.\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\tinactive?: boolean;\n\n\t/**\n\t * Will not show an error in case opening the editor fails and thus allows to show a custom error\n\t * message as needed. By default, an error will be presented as notification if opening was not possible.\n\t */\n\n\t/**\n\t * In case of an error opening the editor, will not present this error to the user (e.g. by showing\n\t * a generic placeholder in the editor area). So it is up to the caller to provide error information\n\t * in that case.\n\t *\n\t * By default, an error when opening an editor will result in a placeholder editor that shows the error.\n\t * In certain cases a modal dialog may be presented to ask the user for further action.\n\t */\n\tignoreError?: boolean;\n\n\t/**\n\t * Allows to override the editor that should be used to display the input:\n\t * - `undefined`: let the editor decide for itself\n\t * - `string`: specific override by id\n\t * - `EditorResolution`: specific override handling\n\t */\n\toverride?: string | EditorResolution;\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\t/**\n\t * An optional property to signal that certain view state should be\n\t * applied when opening the editor.\n\t */\n\tviewState?: object;\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 * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { toLocalISOString } from 'vs/base/common/date';\nimport { memoize } from 'vs/base/common/decorators';\nimport { FileAccess, Schemas } from 'vs/base/common/network';\nimport { dirname, join, normalize, resolve } from 'vs/base/common/path';\nimport { env } from 'vs/base/common/process';\nimport { joinPath } from 'vs/base/common/resources';\nimport { URI } from 'vs/base/common/uri';\nimport { NativeParsedArgs } from 'vs/platform/environment/common/argv';\nimport { ExtensionKind, IExtensionHostDebugParams, INativeEnvironmentService } from 'vs/platform/environment/common/environment';\nimport { IProductService } from 'vs/platform/product/common/productService';\n\nexport const EXTENSION_IDENTIFIER_WITH_LOG_REGEX = /^([^.]+\\..+)[:=](.+)$/;\n\nexport interface INativeEnvironmentPaths {\n\n\t/**\n\t * The user data directory to use for anything that should be\n\t * persisted except for the content that is meant for the `homeDir`.\n\t *\n\t * Only one instance of VSCode can use the same `userDataDir`.\n\t */\n\tuserDataDir: string;\n\n\t/**\n\t * The user home directory mainly used for persisting extensions\n\t * and global configuration that should be shared across all\n\t * versions.\n\t */\n\thomeDir: string;\n\n\t/**\n\t * OS tmp dir.\n\t */\n\ttmpDir: string;\n}\n\nexport abstract class AbstractNativeEnvironmentService implements INativeEnvironmentService {\n\n\tdeclare readonly _serviceBrand: undefined;\n\n\t@memoize\n\tget appRoot(): string { return dirname(FileAccess.asFileUri('').fsPath); }\n\n\t@memoize\n\tget userHome(): URI { return URI.file(this.paths.homeDir); }\n\n\t@memoize\n\tget userDataPath(): string { return this.paths.userDataDir; }\n\n\t@memoize\n\tget appSettingsHome(): URI { return URI.file(join(this.userDataPath, 'User')); }\n\n\t@memoize\n\tget tmpDir(): URI { return URI.file(this.paths.tmpDir); }\n\n\t@memoize\n\tget cacheHome(): URI { return URI.file(this.userDataPath); }\n\n\t@memoize\n\tget stateResource(): URI { return joinPath(this.appSettingsHome, 'globalStorage', 'storage.json'); }\n\n\t@memoize\n\tget userRoamingDataHome(): URI { return this.appSettingsHome.with({ scheme: Schemas.vscodeUserData }); }\n\n\t@memoize\n\tget userDataSyncHome(): URI { return joinPath(this.appSettingsHome, 'sync'); }\n\n\tget logsHome(): URI {\n\t\tif (!this.args.logsPath) {\n\t\t\tconst key = toLocalISOString(new Date()).replace(/-|:|\\.\\d+Z$/g, '');\n\t\t\tthis.args.logsPath = join(this.userDataPath, 'logs', key);\n\t\t}\n\n\t\treturn URI.file(this.args.logsPath);\n\t}\n\n\t@memoize\n\tget sync(): 'on' | 'off' | undefined { return this.args.sync; }\n\n\t@memoize\n\tget machineSettingsResource(): URI { return joinPath(URI.file(join(this.userDataPath, 'Machine')), 'settings.json'); }\n\n\t@memoize\n\tget workspaceStorageHome(): URI { return joinPath(this.appSettingsHome, 'workspaceStorage'); }\n\n\t@memoize\n\tget localHistoryHome(): URI { return joinPath(this.appSettingsHome, 'History'); }\n\n\t@memoize\n\tget keyboardLayoutResource(): URI { return joinPath(this.userRoamingDataHome, 'keyboardLayout.json'); }\n\n\t@memoize\n\tget argvResource(): URI {\n\t\tconst vscodePortable = env['VSCODE_PORTABLE'];\n\t\tif (vscodePortable) {\n\t\t\treturn URI.file(join(vscodePortable, 'argv.json'));\n\t\t}\n\n\t\treturn joinPath(this.userHome, this.productService.dataFolderName, 'argv.json');\n\t}\n\n\t@memoize\n\tget isExtensionDevelopment(): boolean { return !!this.args.extensionDevelopmentPath; }\n\n\t@memoize\n\tget untitledWorkspacesHome(): URI { return URI.file(join(this.userDataPath, 'Workspaces')); }\n\n\t@memoize\n\tget builtinExtensionsPath(): string {\n\t\tconst cliBuiltinExtensionsDir = this.args['builtin-extensions-dir'];\n\t\tif (cliBuiltinExtensionsDir) {\n\t\t\treturn resolve(cliBuiltinExtensionsDir);\n\t\t}\n\n\t\treturn normalize(join(FileAccess.asFileUri('').fsPath, '..', 'extensions'));\n\t}\n\n\tget extensionsDownloadLocation(): URI {\n\t\tconst cliExtensionsDownloadDir = this.args['extensions-download-dir'];\n\t\tif (cliExtensionsDownloadDir) {\n\t\t\treturn URI.file(resolve(cliExtensionsDownloadDir));\n\t\t}\n\n\t\treturn URI.file(join(this.userDataPath, 'CachedExtensionVSIXs'));\n\t}\n\n\t@memoize\n\tget extensionsPath(): string {\n\t\tconst cliExtensionsDir = this.args['extensions-dir'];\n\t\tif (cliExtensionsDir) {\n\t\t\treturn resolve(cliExtensionsDir);\n\t\t}\n\n\t\tconst vscodeExtensions = env['VSCODE_EXTENSIONS'];\n\t\tif (vscodeExtensions) {\n\t\t\treturn vscodeExtensions;\n\t\t}\n\n\t\tconst vscodePortable = env['VSCODE_PORTABLE'];\n\t\tif (vscodePortable) {\n\t\t\treturn join(vscodePortable, 'extensions');\n\t\t}\n\n\t\treturn joinPath(this.userHome, this.productService.dataFolderName, 'extensions').fsPath;\n\t}\n\n\t@memoize\n\tget extensionDevelopmentLocationURI(): URI[] | undefined {\n\t\tconst extensionDevelopmentPaths = this.args.extensionDevelopmentPath;\n\t\tif (Array.isArray(extensionDevelopmentPaths)) {\n\t\t\treturn extensionDevelopmentPaths.map(extensionDevelopmentPath => {\n\t\t\t\tif (/^[^:/?#]+?:\\/\\//.test(extensionDevelopmentPath)) {\n\t\t\t\t\treturn URI.parse(extensionDevelopmentPath);\n\t\t\t\t}\n\n\t\t\t\treturn URI.file(normalize(extensionDevelopmentPath));\n\t\t\t});\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t@memoize\n\tget extensionDevelopmentKind(): ExtensionKind[] | undefined {\n\t\treturn this.args.extensionDevelopmentKind?.map(kind => kind === 'ui' || kind === 'workspace' || kind === 'web' ? kind : 'workspace');\n\t}\n\n\t@memoize\n\tget extensionTestsLocationURI(): URI | undefined {\n\t\tconst extensionTestsPath = this.args.extensionTestsPath;\n\t\tif (extensionTestsPath) {\n\t\t\tif (/^[^:/?#]+?:\\/\\//.test(extensionTestsPath)) {\n\t\t\t\treturn URI.parse(extensionTestsPath);\n\t\t\t}\n\n\t\t\treturn URI.file(normalize(extensionTestsPath));\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tget disableExtensions(): boolean | string[] {\n\t\tif (this.args['disable-extensions']) {\n\t\t\treturn true;\n\t\t}\n\n\t\tconst disableExtensions = this.args['disable-extension'];\n\t\tif (disableExtensions) {\n\t\t\tif (typeof disableExtensions === 'string') {\n\t\t\t\treturn [disableExtensions];\n\t\t\t}\n\n\t\t\tif (Array.isArray(disableExtensions) && disableExtensions.length > 0) {\n\t\t\t\treturn disableExtensions;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t@memoize\n\tget debugExtensionHost(): IExtensionHostDebugParams { return parseExtensionHostDebugPort(this.args, this.isBuilt); }\n\tget debugRenderer(): boolean { return !!this.args.debugRenderer; }\n\n\tget isBuilt(): boolean { return !env['VSCODE_DEV']; }\n\tget verbose(): boolean { return !!this.args.verbose; }\n\n\t@memoize\n\tget logLevel(): string | undefined { return this.args.log?.find(entry => !EXTENSION_IDENTIFIER_WITH_LOG_REGEX.test(entry)); }\n\t@memoize\n\tget extensionLogLevel(): [string, string][] | undefined {\n\t\tconst result: [string, string][] = [];\n\t\tfor (const entry of this.args.log || []) {\n\t\t\tconst matches = EXTENSION_IDENTIFIER_WITH_LOG_REGEX.exec(entry);\n\t\t\tif (matches && matches[1] && matches[2]) {\n\t\t\t\tresult.push([matches[1], matches[2]]);\n\t\t\t}\n\t\t}\n\t\treturn result.length ? result : undefined;\n\t}\n\n\t@memoize\n\tget serviceMachineIdResource(): URI { return joinPath(URI.file(this.userDataPath), 'machineid'); }\n\n\tget crashReporterId(): string | undefined { return this.args['crash-reporter-id']; }\n\tget crashReporterDirectory(): string | undefined { return this.args['crash-reporter-directory']; }\n\n\t@memoize\n\tget disableTelemetry(): boolean { return !!this.args['disable-telemetry']; }\n\n\t@memoize\n\tget disableWorkspaceTrust(): boolean { return !!this.args['disable-workspace-trust']; }\n\n\t@memoize\n\tget useInMemorySecretStorage(): boolean { return !!this.args['use-inmemory-secretstorage']; }\n\n\t@memoize\n\tget policyFile(): URI | undefined {\n\t\tif (this.args['__enable-file-policy']) {\n\t\t\tconst vscodePortable = env['VSCODE_PORTABLE'];\n\t\t\tif (vscodePortable) {\n\t\t\t\treturn URI.file(join(vscodePortable, 'policy.json'));\n\t\t\t}\n\n\t\t\treturn joinPath(this.userHome, this.productService.dataFolderName, 'policy.json');\n\t\t}\n\t\treturn undefined;\n\t}\n\n\teditSessionId: string | undefined = this.args['editSessionId'];\n\n\tget continueOn(): string | undefined {\n\t\treturn this.args['continueOn'];\n\t}\n\n\tset continueOn(value: string | undefined) {\n\t\tthis.args['continueOn'] = value;\n\t}\n\n\tget args(): NativeParsedArgs { return this._args; }\n\n\tconstructor(\n\t\tprivate readonly _args: NativeParsedArgs,\n\t\tprivate readonly paths: INativeEnvironmentPaths,\n\t\tprotected readonly productService: IProductService\n\t) { }\n}\n\nexport function parseExtensionHostDebugPort(args: NativeParsedArgs, isBuilt: boolean): IExtensionHostDebugParams {\n\treturn parseDebugParams(args['inspect-extensions'], args['inspect-brk-extensions'], 5870, isBuilt, args.debugId, args.extensionEnvironment);\n}\n\nexport function parseDebugParams(debugArg: string | undefined, debugBrkArg: string | undefined, defaultBuildPort: number, isBuilt: boolean, debugId?: string, environmentString?: string): IExtensionHostDebugParams {\n\tconst portStr = debugBrkArg || debugArg;\n\tconst port = Number(portStr) || (!isBuilt ? defaultBuildPort : null);\n\tconst brk = port ? Boolean(!!debugBrkArg) : false;\n\tlet env: Record | undefined;\n\tif (environmentString) {\n\t\ttry {\n\t\t\tenv = JSON.parse(environmentString);\n\t\t} catch {\n\t\t\t// ignore\n\t\t}\n\t}\n\n\treturn { port, break: brk, debugId, env };\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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\nconst SshProtocolMatcher = /^([^@:]+@)?([^:]+):/;\nconst SshUrlMatcher = /^([^@:]+@)?([^:]+):(.+)$/;\nconst AuthorityMatcher = /^([^@]+@)?([^:]+)(:\\d+)?$/;\nconst SecondLevelDomainMatcher = /([^@:.]+\\.[^@:.]+)(:\\d+)?$/;\nconst RemoteMatcher = /^\\s*url\\s*=\\s*(.+\\S)\\s*$/mg;\nconst AnyButDot = /[^.]/g;\n\nexport const AllowedSecondLevelDomains = [\n\t'github.com',\n\t'bitbucket.org',\n\t'visualstudio.com',\n\t'gitlab.com',\n\t'heroku.com',\n\t'azurewebsites.net',\n\t'ibm.com',\n\t'amazon.com',\n\t'amazonaws.com',\n\t'cloudapp.net',\n\t'rhcloud.com',\n\t'google.com',\n\t'azure.com'\n];\n\nfunction stripLowLevelDomains(domain: string): string | null {\n\tconst match = domain.match(SecondLevelDomainMatcher);\n\treturn match ? match[1] : null;\n}\n\nfunction extractDomain(url: string): string | null {\n\tif (url.indexOf('://') === -1) {\n\t\tconst match = url.match(SshProtocolMatcher);\n\t\tif (match) {\n\t\t\treturn stripLowLevelDomains(match[2]);\n\t\t} else {\n\t\t\treturn null;\n\t\t}\n\t}\n\ttry {\n\t\tconst uri = URI.parse(url);\n\t\tif (uri.authority) {\n\t\t\treturn stripLowLevelDomains(uri.authority);\n\t\t}\n\t} catch (e) {\n\t\t// ignore invalid URIs\n\t}\n\treturn null;\n}\n\nexport function getDomainsOfRemotes(text: string, allowedDomains: readonly string[]): string[] {\n\tconst domains = new Set();\n\tlet match: RegExpExecArray | null;\n\twhile (match = RemoteMatcher.exec(text)) {\n\t\tconst domain = extractDomain(match[1]);\n\t\tif (domain) {\n\t\t\tdomains.add(domain);\n\t\t}\n\t}\n\n\tconst allowedDomainsSet = new Set(allowedDomains);\n\treturn Array.from(domains)\n\t\t.map(key => allowedDomainsSet.has(key) ? key : key.replace(AnyButDot, 'a'));\n}\n\nfunction stripPort(authority: string): string | null {\n\tconst match = authority.match(AuthorityMatcher);\n\treturn match ? match[2] : null;\n}\n\nfunction normalizeRemote(host: string | null, path: string, stripEndingDotGit: boolean): string | null {\n\tif (host && path) {\n\t\tif (stripEndingDotGit && path.endsWith('.git')) {\n\t\t\tpath = path.substr(0, path.length - 4);\n\t\t}\n\t\treturn (path.indexOf('/') === 0) ? `${host}${path}` : `${host}/${path}`;\n\t}\n\treturn null;\n}\n\nfunction extractRemote(url: string, stripEndingDotGit: boolean): string | null {\n\tif (url.indexOf('://') === -1) {\n\t\tconst match = url.match(SshUrlMatcher);\n\t\tif (match) {\n\t\t\treturn normalizeRemote(match[2], match[3], stripEndingDotGit);\n\t\t}\n\t}\n\ttry {\n\t\tconst uri = URI.parse(url);\n\t\tif (uri.authority) {\n\t\t\treturn normalizeRemote(stripPort(uri.authority), uri.path, stripEndingDotGit);\n\t\t}\n\t} catch (e) {\n\t\t// ignore invalid URIs\n\t}\n\treturn null;\n}\n\nexport function getRemotes(text: string, stripEndingDotGit: boolean = false): string[] {\n\tconst remotes: string[] = [];\n\tlet match: RegExpExecArray | null;\n\twhile (match = RemoteMatcher.exec(text)) {\n\t\tconst remote = extractRemote(match[1], stripEndingDotGit);\n\t\tif (remote) {\n\t\t\tremotes.push(remote);\n\t\t}\n\t}\n\treturn remotes;\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { isObject, isString } from 'vs/base/common/types';\nimport { ILocalizedString } from 'vs/platform/action/common/action';\nimport { IExtensionManifest } from 'vs/platform/extensions/common/extensions';\nimport { localize } from 'vs/nls';\nimport { ILogger } from 'vs/platform/log/common/log';\n\nexport interface ITranslations {\n\t[key: string]: string | { message: string; comment: string[] } | undefined;\n}\n\nexport function localizeManifest(logger: ILogger, extensionManifest: IExtensionManifest, translations: ITranslations, fallbackTranslations?: ITranslations): IExtensionManifest {\n\ttry {\n\t\treplaceNLStrings(logger, extensionManifest, translations, fallbackTranslations);\n\t} catch (error) {\n\t\tlogger.error(error?.message ?? error);\n\t\t/*Ignore Error*/\n\t}\n\treturn extensionManifest;\n}\n\n/**\n * This routine makes the following assumptions:\n * The root element is an object literal\n */\nfunction replaceNLStrings(logger: ILogger, extensionManifest: IExtensionManifest, messages: ITranslations, originalMessages?: ITranslations): void {\n\tconst processEntry = (obj: any, key: string | number, command?: boolean) => {\n\t\tconst value = obj[key];\n\t\tif (isString(value)) {\n\t\t\tconst str = value;\n\t\t\tconst length = str.length;\n\t\t\tif (length > 1 && str[0] === '%' && str[length - 1] === '%') {\n\t\t\t\tconst messageKey = str.substr(1, length - 2);\n\t\t\t\tlet translated = messages[messageKey];\n\t\t\t\t// If the messages come from a language pack they might miss some keys\n\t\t\t\t// Fill them from the original messages.\n\t\t\t\tif (translated === undefined && originalMessages) {\n\t\t\t\t\ttranslated = originalMessages[messageKey];\n\t\t\t\t}\n\t\t\t\tconst message: string | undefined = typeof translated === 'string' ? translated : translated?.message;\n\n\t\t\t\t// This branch returns ILocalizedString's instead of Strings so that the Command Palette can contain both the localized and the original value.\n\t\t\t\tconst original = originalMessages?.[messageKey];\n\t\t\t\tconst originalMessage: string | undefined = typeof original === 'string' ? original : original?.message;\n\n\t\t\t\tif (!message) {\n\t\t\t\t\tif (!originalMessage) {\n\t\t\t\t\t\tlogger.warn(`[${extensionManifest.name}]: ${localize('missingNLSKey', \"Couldn't find message for key {0}.\", messageKey)}`);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (\n\t\t\t\t\t// if we are translating the title or category of a command\n\t\t\t\t\tcommand && (key === 'title' || key === 'category') &&\n\t\t\t\t\t// and the original value is not the same as the translated value\n\t\t\t\t\toriginalMessage && originalMessage !== message\n\t\t\t\t) {\n\t\t\t\t\tconst localizedString: ILocalizedString = {\n\t\t\t\t\t\tvalue: message,\n\t\t\t\t\t\toriginal: originalMessage\n\t\t\t\t\t};\n\t\t\t\t\tobj[key] = localizedString;\n\t\t\t\t} else {\n\t\t\t\t\tobj[key] = message;\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (isObject(value)) {\n\t\t\tfor (const k in value) {\n\t\t\t\tif (value.hasOwnProperty(k)) {\n\t\t\t\t\tk === 'commands' ? processEntry(value, k, true) : processEntry(value, k, command);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (Array.isArray(value)) {\n\t\t\tfor (let i = 0; i < value.length; i++) {\n\t\t\t\tprocessEntry(value, i, command);\n\t\t\t}\n\t\t}\n\t};\n\n\tfor (const key in extensionManifest) {\n\t\tif (extensionManifest.hasOwnProperty(key)) {\n\t\t\tprocessEntry(extensionManifest, key);\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 { isEqualOrParent, joinPath } from 'vs/base/common/resources';\nimport Severity from 'vs/base/common/severity';\nimport { URI } from 'vs/base/common/uri';\nimport * as nls from 'vs/nls';\nimport * as semver from 'vs/base/common/semver/semver';\nimport { IExtensionManifest } from 'vs/platform/extensions/common/extensions';\n\nexport interface IParsedVersion {\n\thasCaret: boolean;\n\thasGreaterEquals: boolean;\n\tmajorBase: number;\n\tmajorMustEqual: boolean;\n\tminorBase: number;\n\tminorMustEqual: boolean;\n\tpatchBase: number;\n\tpatchMustEqual: boolean;\n\tpreRelease: string | null;\n}\n\nexport interface INormalizedVersion {\n\tmajorBase: number;\n\tmajorMustEqual: boolean;\n\tminorBase: number;\n\tminorMustEqual: boolean;\n\tpatchBase: number;\n\tpatchMustEqual: boolean;\n\tnotBefore: number; /* milliseconds timestamp, or 0 */\n\tisMinimum: boolean;\n}\n\nconst VERSION_REGEXP = /^(\\^|>=)?((\\d+)|x)\\.((\\d+)|x)\\.((\\d+)|x)(\\-.*)?$/;\nconst NOT_BEFORE_REGEXP = /^-(\\d{4})(\\d{2})(\\d{2})$/;\n\nexport function isValidVersionStr(version: string): boolean {\n\tversion = version.trim();\n\treturn (version === '*' || VERSION_REGEXP.test(version));\n}\n\nexport function parseVersion(version: string): IParsedVersion | null {\n\tif (!isValidVersionStr(version)) {\n\t\treturn null;\n\t}\n\n\tversion = version.trim();\n\n\tif (version === '*') {\n\t\treturn {\n\t\t\thasCaret: false,\n\t\t\thasGreaterEquals: false,\n\t\t\tmajorBase: 0,\n\t\t\tmajorMustEqual: false,\n\t\t\tminorBase: 0,\n\t\t\tminorMustEqual: false,\n\t\t\tpatchBase: 0,\n\t\t\tpatchMustEqual: false,\n\t\t\tpreRelease: null\n\t\t};\n\t}\n\n\tconst m = version.match(VERSION_REGEXP);\n\tif (!m) {\n\t\treturn null;\n\t}\n\treturn {\n\t\thasCaret: m[1] === '^',\n\t\thasGreaterEquals: m[1] === '>=',\n\t\tmajorBase: m[2] === 'x' ? 0 : parseInt(m[2], 10),\n\t\tmajorMustEqual: (m[2] === 'x' ? false : true),\n\t\tminorBase: m[4] === 'x' ? 0 : parseInt(m[4], 10),\n\t\tminorMustEqual: (m[4] === 'x' ? false : true),\n\t\tpatchBase: m[6] === 'x' ? 0 : parseInt(m[6], 10),\n\t\tpatchMustEqual: (m[6] === 'x' ? false : true),\n\t\tpreRelease: m[8] || null\n\t};\n}\n\nexport function normalizeVersion(version: IParsedVersion | null): INormalizedVersion | null {\n\tif (!version) {\n\t\treturn null;\n\t}\n\n\tconst majorBase = version.majorBase;\n\tconst majorMustEqual = version.majorMustEqual;\n\tconst minorBase = version.minorBase;\n\tlet minorMustEqual = version.minorMustEqual;\n\tconst patchBase = version.patchBase;\n\tlet patchMustEqual = version.patchMustEqual;\n\n\tif (version.hasCaret) {\n\t\tif (majorBase === 0) {\n\t\t\tpatchMustEqual = false;\n\t\t} else {\n\t\t\tminorMustEqual = false;\n\t\t\tpatchMustEqual = false;\n\t\t}\n\t}\n\n\tlet notBefore = 0;\n\tif (version.preRelease) {\n\t\tconst match = NOT_BEFORE_REGEXP.exec(version.preRelease);\n\t\tif (match) {\n\t\t\tconst [, year, month, day] = match;\n\t\t\tnotBefore = Date.UTC(Number(year), Number(month) - 1, Number(day));\n\t\t}\n\t}\n\n\treturn {\n\t\tmajorBase: majorBase,\n\t\tmajorMustEqual: majorMustEqual,\n\t\tminorBase: minorBase,\n\t\tminorMustEqual: minorMustEqual,\n\t\tpatchBase: patchBase,\n\t\tpatchMustEqual: patchMustEqual,\n\t\tisMinimum: version.hasGreaterEquals,\n\t\tnotBefore,\n\t};\n}\n\nexport function isValidVersion(_inputVersion: string | INormalizedVersion, _inputDate: ProductDate, _desiredVersion: string | INormalizedVersion): boolean {\n\tlet version: INormalizedVersion | null;\n\tif (typeof _inputVersion === 'string') {\n\t\tversion = normalizeVersion(parseVersion(_inputVersion));\n\t} else {\n\t\tversion = _inputVersion;\n\t}\n\n\tlet productTs: number | undefined;\n\tif (_inputDate instanceof Date) {\n\t\tproductTs = _inputDate.getTime();\n\t} else if (typeof _inputDate === 'string') {\n\t\tproductTs = new Date(_inputDate).getTime();\n\t}\n\n\tlet desiredVersion: INormalizedVersion | null;\n\tif (typeof _desiredVersion === 'string') {\n\t\tdesiredVersion = normalizeVersion(parseVersion(_desiredVersion));\n\t} else {\n\t\tdesiredVersion = _desiredVersion;\n\t}\n\n\tif (!version || !desiredVersion) {\n\t\treturn false;\n\t}\n\n\tconst majorBase = version.majorBase;\n\tconst minorBase = version.minorBase;\n\tconst patchBase = version.patchBase;\n\n\tlet desiredMajorBase = desiredVersion.majorBase;\n\tlet desiredMinorBase = desiredVersion.minorBase;\n\tlet desiredPatchBase = desiredVersion.patchBase;\n\tconst desiredNotBefore = desiredVersion.notBefore;\n\n\tlet majorMustEqual = desiredVersion.majorMustEqual;\n\tlet minorMustEqual = desiredVersion.minorMustEqual;\n\tlet patchMustEqual = desiredVersion.patchMustEqual;\n\n\tif (desiredVersion.isMinimum) {\n\t\tif (majorBase > desiredMajorBase) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (majorBase < desiredMajorBase) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (minorBase > desiredMinorBase) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (minorBase < desiredMinorBase) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (productTs && productTs < desiredNotBefore) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn patchBase >= desiredPatchBase;\n\t}\n\n\t// Anything < 1.0.0 is compatible with >= 1.0.0, except exact matches\n\tif (majorBase === 1 && desiredMajorBase === 0 && (!majorMustEqual || !minorMustEqual || !patchMustEqual)) {\n\t\tdesiredMajorBase = 1;\n\t\tdesiredMinorBase = 0;\n\t\tdesiredPatchBase = 0;\n\t\tmajorMustEqual = true;\n\t\tminorMustEqual = false;\n\t\tpatchMustEqual = false;\n\t}\n\n\tif (majorBase < desiredMajorBase) {\n\t\t// smaller major version\n\t\treturn false;\n\t}\n\n\tif (majorBase > desiredMajorBase) {\n\t\t// higher major version\n\t\treturn (!majorMustEqual);\n\t}\n\n\t// at this point, majorBase are equal\n\n\tif (minorBase < desiredMinorBase) {\n\t\t// smaller minor version\n\t\treturn false;\n\t}\n\n\tif (minorBase > desiredMinorBase) {\n\t\t// higher minor version\n\t\treturn (!minorMustEqual);\n\t}\n\n\t// at this point, minorBase are equal\n\n\tif (patchBase < desiredPatchBase) {\n\t\t// smaller patch version\n\t\treturn false;\n\t}\n\n\tif (patchBase > desiredPatchBase) {\n\t\t// higher patch version\n\t\treturn (!patchMustEqual);\n\t}\n\n\t// at this point, patchBase are equal\n\n\tif (productTs && productTs < desiredNotBefore) {\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\ntype ProductDate = string | Date | undefined;\n\nexport function validateExtensionManifest(productVersion: string, productDate: ProductDate, extensionLocation: URI, extensionManifest: IExtensionManifest, extensionIsBuiltin: boolean): readonly [Severity, string][] {\n\tconst validations: [Severity, string][] = [];\n\tif (typeof extensionManifest.publisher !== 'undefined' && typeof extensionManifest.publisher !== 'string') {\n\t\tvalidations.push([Severity.Error, nls.localize('extensionDescription.publisher', \"property publisher must be of type `string`.\")]);\n\t\treturn validations;\n\t}\n\tif (typeof extensionManifest.name !== 'string') {\n\t\tvalidations.push([Severity.Error, nls.localize('extensionDescription.name', \"property `{0}` is mandatory and must be of type `string`\", 'name')]);\n\t\treturn validations;\n\t}\n\tif (typeof extensionManifest.version !== 'string') {\n\t\tvalidations.push([Severity.Error, nls.localize('extensionDescription.version', \"property `{0}` is mandatory and must be of type `string`\", 'version')]);\n\t\treturn validations;\n\t}\n\tif (!extensionManifest.engines) {\n\t\tvalidations.push([Severity.Error, nls.localize('extensionDescription.engines', \"property `{0}` is mandatory and must be of type `object`\", 'engines')]);\n\t\treturn validations;\n\t}\n\tif (typeof extensionManifest.engines.vscode !== 'string') {\n\t\tvalidations.push([Severity.Error, nls.localize('extensionDescription.engines.vscode', \"property `{0}` is mandatory and must be of type `string`\", 'engines.vscode')]);\n\t\treturn validations;\n\t}\n\tif (typeof extensionManifest.extensionDependencies !== 'undefined') {\n\t\tif (!isStringArray(extensionManifest.extensionDependencies)) {\n\t\t\tvalidations.push([Severity.Error, nls.localize('extensionDescription.extensionDependencies', \"property `{0}` can be omitted or must be of type `string[]`\", 'extensionDependencies')]);\n\t\t\treturn validations;\n\t\t}\n\t}\n\tif (typeof extensionManifest.activationEvents !== 'undefined') {\n\t\tif (!isStringArray(extensionManifest.activationEvents)) {\n\t\t\tvalidations.push([Severity.Error, nls.localize('extensionDescription.activationEvents1', \"property `{0}` can be omitted or must be of type `string[]`\", 'activationEvents')]);\n\t\t\treturn validations;\n\t\t}\n\t\tif (typeof extensionManifest.main === 'undefined' && typeof extensionManifest.browser === 'undefined') {\n\t\t\tvalidations.push([Severity.Error, nls.localize('extensionDescription.activationEvents2', \"property `{0}` should be omitted if the extension doesn't have a `{1}` or `{2}` property.\", 'activationEvents', 'main', 'browser')]);\n\t\t\treturn validations;\n\t\t}\n\t}\n\tif (typeof extensionManifest.extensionKind !== 'undefined') {\n\t\tif (typeof extensionManifest.main === 'undefined') {\n\t\t\tvalidations.push([Severity.Warning, nls.localize('extensionDescription.extensionKind', \"property `{0}` can be defined only if property `main` is also defined.\", 'extensionKind')]);\n\t\t\t// not a failure case\n\t\t}\n\t}\n\tif (typeof extensionManifest.main !== 'undefined') {\n\t\tif (typeof extensionManifest.main !== 'string') {\n\t\t\tvalidations.push([Severity.Error, nls.localize('extensionDescription.main1', \"property `{0}` can be omitted or must be of type `string`\", 'main')]);\n\t\t\treturn validations;\n\t\t} else {\n\t\t\tconst mainLocation = joinPath(extensionLocation, extensionManifest.main);\n\t\t\tif (!isEqualOrParent(mainLocation, extensionLocation)) {\n\t\t\t\tvalidations.push([Severity.Warning, nls.localize('extensionDescription.main2', \"Expected `main` ({0}) to be included inside extension's folder ({1}). This might make the extension non-portable.\", mainLocation.path, extensionLocation.path)]);\n\t\t\t\t// not a failure case\n\t\t\t}\n\t\t}\n\t}\n\tif (typeof extensionManifest.browser !== 'undefined') {\n\t\tif (typeof extensionManifest.browser !== 'string') {\n\t\t\tvalidations.push([Severity.Error, nls.localize('extensionDescription.browser1', \"property `{0}` can be omitted or must be of type `string`\", 'browser')]);\n\t\t\treturn validations;\n\t\t} else {\n\t\t\tconst browserLocation = joinPath(extensionLocation, extensionManifest.browser);\n\t\t\tif (!isEqualOrParent(browserLocation, extensionLocation)) {\n\t\t\t\tvalidations.push([Severity.Warning, nls.localize('extensionDescription.browser2', \"Expected `browser` ({0}) to be included inside extension's folder ({1}). This might make the extension non-portable.\", browserLocation.path, extensionLocation.path)]);\n\t\t\t\t// not a failure case\n\t\t\t}\n\t\t}\n\t}\n\n\tif (!semver.valid(extensionManifest.version)) {\n\t\tvalidations.push([Severity.Error, nls.localize('notSemver', \"Extension version is not semver compatible.\")]);\n\t\treturn validations;\n\t}\n\n\tconst notices: string[] = [];\n\tconst isValid = isValidExtensionVersion(productVersion, productDate, extensionManifest, extensionIsBuiltin, notices);\n\tif (!isValid) {\n\t\tfor (const notice of notices) {\n\t\t\tvalidations.push([Severity.Error, notice]);\n\t\t}\n\t}\n\treturn validations;\n}\n\nexport function isValidExtensionVersion(productVersion: string, productDate: ProductDate, extensionManifest: IExtensionManifest, extensionIsBuiltin: boolean, notices: string[]): boolean {\n\n\tif (extensionIsBuiltin || (typeof extensionManifest.main === 'undefined' && typeof extensionManifest.browser === 'undefined')) {\n\t\t// No version check for builtin or declarative extensions\n\t\treturn true;\n\t}\n\n\treturn isVersionValid(productVersion, productDate, extensionManifest.engines.vscode, notices);\n}\n\nexport function isEngineValid(engine: string, version: string, date: ProductDate): boolean {\n\t// TODO@joao: discuss with alex '*' doesn't seem to be a valid engine version\n\treturn engine === '*' || isVersionValid(version, date, engine);\n}\n\nfunction isVersionValid(currentVersion: string, date: ProductDate, requestedVersion: string, notices: string[] = []): boolean {\n\n\tconst desiredVersion = normalizeVersion(parseVersion(requestedVersion));\n\tif (!desiredVersion) {\n\t\tnotices.push(nls.localize('versionSyntax', \"Could not parse `engines.vscode` value {0}. Please use, for example: ^1.22.0, ^1.22.x, etc.\", requestedVersion));\n\t\treturn false;\n\t}\n\n\t// enforce that a breaking API version is specified.\n\t// for 0.X.Y, that means up to 0.X must be specified\n\t// otherwise for Z.X.Y, that means Z must be specified\n\tif (desiredVersion.majorBase === 0) {\n\t\t// force that major and minor must be specific\n\t\tif (!desiredVersion.majorMustEqual || !desiredVersion.minorMustEqual) {\n\t\t\tnotices.push(nls.localize('versionSpecificity1', \"Version specified in `engines.vscode` ({0}) is not specific enough. For vscode versions before 1.0.0, please define at a minimum the major and minor desired version. E.g. ^0.10.0, 0.10.x, 0.11.0, etc.\", requestedVersion));\n\t\t\treturn false;\n\t\t}\n\t} else {\n\t\t// force that major must be specific\n\t\tif (!desiredVersion.majorMustEqual) {\n\t\t\tnotices.push(nls.localize('versionSpecificity2', \"Version specified in `engines.vscode` ({0}) is not specific enough. For vscode versions after 1.0.0, please define at a minimum the major desired version. E.g. ^1.10.0, 1.10.x, 1.x.x, 2.x.x, etc.\", requestedVersion));\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tif (!isValidVersion(currentVersion, date, desiredVersion)) {\n\t\tnotices.push(nls.localize('versionMismatch', \"Extension is not compatible with Code {0}. Extension requires: {1}.\", currentVersion, requestedVersion));\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\nfunction isStringArray(arr: string[]): boolean {\n\tif (!Array.isArray(arr)) {\n\t\treturn false;\n\t}\n\tfor (let i = 0, len = arr.length; i < len; i++) {\n\t\tif (typeof arr[i] !== 'string') {\n\t\t\treturn false;\n\t\t}\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\nimport { VSBuffer } from 'vs/base/common/buffer';\nimport { generateUuid, isUUID } from 'vs/base/common/uuid';\nimport { IEnvironmentService } from 'vs/platform/environment/common/environment';\nimport { IFileService } from 'vs/platform/files/common/files';\nimport { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';\n\nexport async function getServiceMachineId(environmentService: IEnvironmentService, fileService: IFileService, storageService: IStorageService | undefined): Promise {\n\tlet uuid: string | null = storageService ? storageService.get('storage.serviceMachineId', StorageScope.APPLICATION) || null : null;\n\tif (uuid) {\n\t\treturn uuid;\n\t}\n\ttry {\n\t\tconst contents = await fileService.readFile(environmentService.serviceMachineIdResource);\n\t\tconst value = contents.value.toString();\n\t\tuuid = isUUID(value) ? value : null;\n\t} catch (e) {\n\t\tuuid = null;\n\t}\n\n\tif (!uuid) {\n\t\tuuid = generateUuid();\n\t\ttry {\n\t\t\tawait fileService.writeFile(environmentService.serviceMachineIdResource, VSBuffer.fromString(uuid));\n\t\t} catch (error) {\n\t\t\t//noop\n\t\t}\n\t}\n\n\tstorageService?.store('storage.serviceMachineId', uuid, StorageScope.APPLICATION, StorageTarget.MACHINE);\n\n\treturn uuid;\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (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 * Typings for the https://wicg.github.io/file-system-access\n *\n * Use `supported(window)` to find out if the browser supports this kind of API.\n */\nexport namespace WebFileSystemAccess {\n\n\texport function supported(obj: any & Window): boolean {\n\t\tif (typeof obj?.showDirectoryPicker === 'function') {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\texport function isFileSystemHandle(handle: unknown): handle is FileSystemHandle {\n\t\tconst candidate = handle as FileSystemHandle | undefined;\n\t\tif (!candidate) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn typeof candidate.kind === 'string' && typeof candidate.queryPermission === 'function' && typeof candidate.requestPermission === 'function';\n\t}\n\n\texport function isFileSystemFileHandle(handle: FileSystemHandle): handle is FileSystemFileHandle {\n\t\treturn handle.kind === 'file';\n\t}\n\n\texport function isFileSystemDirectoryHandle(handle: FileSystemHandle): handle is FileSystemDirectoryHandle {\n\t\treturn handle.kind === 'directory';\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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\tlookup(data: T): Node | undefined {\n\t\treturn this._nodes.get(this._hashFn(data));\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 * 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\tcreateChild(services: ServiceCollection): IInstantiationService;\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\nexport function refineServiceDecorator(serviceIdentifier: ServiceIdentifier): ServiceIdentifier {\n\treturn >serviceIdentifier;\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { IProgress, IProgressStep } from 'vs/platform/progress/common/progress';\nimport { IDisposable } from 'vs/base/common/lifecycle';\nimport { URI } from 'vs/base/common/uri';\nimport { isObject } from 'vs/base/common/types';\nimport { UndoRedoSource } from 'vs/platform/undoRedo/common/undoRedo';\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\tprogress?: IProgress;\n\ttoken?: CancellationToken;\n\tshowPreview?: boolean;\n\tlabel?: string;\n\tcode?: string;\n\tquotableLabel?: string;\n\tundoRedoSource?: UndoRedoSource;\n\tundoRedoGroupId?: number;\n\tconfirmBeforeUndo?: boolean;\n\trespectAutoSaveConfig?: boolean;\n}\n\nexport interface IBulkEditResult {\n\tariaSummary: string;\n\tisApplied: boolean;\n}\n\nexport type IBulkEditPreviewHandler = (edits: ResourceEdit[], options?: IBulkEditOptions) => Promise;\n\nexport interface IBulkEditService {\n\treadonly _serviceBrand: undefined;\n\n\thasPreviewHandler(): boolean;\n\n\tsetPreviewHandler(handler: IBulkEditPreviewHandler): IDisposable;\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 { IDecorationRenderOptions } from 'vs/editor/common/editorCommon';\nimport { IModelDecorationOptions, ITextModel } from 'vs/editor/common/model';\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\n\treadonly onWillCreateCodeEditor: Event;\n\treadonly onCodeEditorAdd: Event;\n\treadonly onCodeEditorRemove: Event;\n\n\treadonly onWillCreateDiffEditor: Event;\n\treadonly onDiffEditorAdd: Event;\n\treadonly onDiffEditorRemove: Event;\n\n\treadonly onDidChangeTransientModelProperty: Event;\n\treadonly onDecorationTypeRegistered: 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\tremoveDiffEditor(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\n\tregisterDecorationType(description: string, key: string, options: IDecorationRenderOptions, parentTypeKey?: string, editor?: ICodeEditor): void;\n\tlistDecorationTypes(): string[];\n\tremoveDecorationType(key: string): void;\n\tresolveDecorationOptions(typeKey: string, writable: boolean): IModelDecorationOptions;\n\tresolveDecorationCSSRules(decorationTypeKey: string): CSSRuleList | null;\n\n\tsetModelProperty(resource: URI, key: string, value: any): void;\n\tgetModelProperty(resource: URI, key: string): any;\n\n\tsetTransientModelProperty(model: ITextModel, key: string, value: any): void;\n\tgetTransientModelProperty(model: ITextModel, key: string): any;\n\tgetTransientModelProperties(model: ITextModel): [string, any][] | undefined;\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.Explicit) {\n\t\t\t\tconst m = this._diffModel.get();\n\t\t\t\ttransaction(tx => {\n\t\t\t\t\tfor (const s of this._editors.original.getSelections() || []) {\n\t\t\t\t\t\tm?.ensureOriginalLineIsVisible(s.getStartPosition().lineNumber, RevealPreference.FromCloserSide, tx);\n\t\t\t\t\t\tm?.ensureOriginalLineIsVisible(s.getEndPosition().lineNumber, RevealPreference.FromCloserSide, tx);\n\t\t\t\t\t}\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.Explicit) {\n\t\t\t\tconst m = this._diffModel.get();\n\t\t\t\ttransaction(tx => {\n\t\t\t\t\tfor (const s of this._editors.modified.getSelections() || []) {\n\t\t\t\t\t\tm?.ensureModifiedLineIsVisible(s.getStartPosition().lineNumber, RevealPreference.FromCloserSide, tx);\n\t\t\t\t\t\tm?.ensureModifiedLineIsVisible(s.getEndPosition().lineNumber, RevealPreference.FromCloserSide, tx);\n\t\t\t\t\t}\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 = editor.getTopForLineNumber(this._unchangedRegionRange.endLineNumberExclusive);\n\t\t\t\tthis._unchangedRegion.visibleLineCountBottom.set(newVal, undefined);\n\t\t\t\tconst top2 = 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 { IDisposable } from 'vs/base/common/lifecycle';\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 ILanguageNameIdPair {\n\treadonly languageName: string;\n\treadonly languageId: string;\n}\n\nexport interface ILanguageIcon {\n\treadonly light: URI;\n\treadonly dark: URI;\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 * An event emitted when languages have changed.\n\t */\n\tonDidChange: Event;\n\n\t/**\n\t * Register a language.\n\t */\n\tregisterLanguage(def: ILanguageExtensionPoint): IDisposable;\n\n\t/**\n\t * Check if `languageId` is registered.\n\t */\n\tisRegisteredLanguageId(languageId: string): boolean;\n\n\t/**\n\t * Get a list of all registered languages.\n\t */\n\tgetRegisteredLanguageIds(): string[];\n\n\t/**\n\t * Get a list of all registered languages with a name.\n\t * If a language is explicitly registered without a name, it will not be part of the result.\n\t * The result is sorted using by name case insensitive.\n\t */\n\tgetSortedRegisteredLanguageNames(): ILanguageNameIdPair[];\n\n\t/**\n\t * Get the preferred language name for a language.\n\t */\n\tgetLanguageName(languageId: string): string | null;\n\n\t/**\n\t * Get the mimetype for a language.\n\t */\n\tgetMimeType(languageId: string): string | null;\n\n\t/**\n\t * Get the default icon for the language.\n\t */\n\tgetIcon(languageId: string): ILanguageIcon | null;\n\n\t/**\n\t * Get all file extensions for a language.\n\t */\n\tgetExtensions(languageId: string): ReadonlyArray;\n\n\t/**\n\t * Get all file names for a language.\n\t */\n\tgetFilenames(languageId: string): ReadonlyArray;\n\n\t/**\n\t * Get all language configuration files for a language.\n\t */\n\tgetConfigurationFiles(languageId: string): ReadonlyArray;\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 `mimeType` is unknown.\n\t */\n\tcreateByMimeType(mimeType: 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 { IChange } from 'vs/editor/common/diff/legacyLinesDiffComputer';\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 type { EditorSimpleWorker } from 'vs/editor/common/services/editorSimpleWorker';\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\tcanComputeDirtyDiff(original: URI, modified: URI): boolean;\n\tcomputeDirtyDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean): Promise;\n\n\tcomputeMoreMinimalEdits(resource: URI, edits: TextEdit[] | null | undefined, pretty?: boolean): Promise;\n\tcomputeHumanReadableDiff(resource: URI, edits: TextEdit[] | null | undefined): 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\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, NotebookInfoResolver } from 'vs/editor/common/languageFeatureRegistry';\nimport { CodeActionProvider, CodeLensProvider, CompletionItemProvider, DeclarationProvider, DefinitionProvider, DocumentColorProvider, DocumentFormattingEditProvider, DocumentHighlightProvider, DocumentOnDropEditProvider, DocumentPasteEditProvider, DocumentRangeFormattingEditProvider, DocumentRangeSemanticTokensProvider, DocumentSemanticTokensProvider, DocumentSymbolProvider, EvaluatableExpressionProvider, FoldingRangeProvider, HoverProvider, ImplementationProvider, InlayHintsProvider, InlineCompletionsProvider, InlineValuesProvider, LinkedEditingRangeProvider, LinkProvider, MappedEditsProvider, 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 inlineValuesProvider: LanguageFeatureRegistry;\n\n\treadonly evaluatableExpressionProvider: LanguageFeatureRegistry;\n\n\treadonly documentOnDropEditProvider: LanguageFeatureRegistry;\n\n\treadonly mappedEditsProvider: LanguageFeatureRegistry;\n\n\t// --\n\n\tsetNotebookTypeResolver(resolver: NotebookInfoResolver | undefined): 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 { 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, DocumentOnDropEditProvider, DocumentRangeFormattingEditProvider, DocumentRangeSemanticTokensProvider, DocumentSemanticTokensProvider, DocumentSymbolProvider, EvaluatableExpressionProvider, FoldingRangeProvider, HoverProvider, ImplementationProvider, InlayHintsProvider, InlineCompletionsProvider, InlineValuesProvider, LinkedEditingRangeProvider, LinkProvider, OnTypeFormattingEditProvider, ReferenceProvider, RenameProvider, SelectionRangeProvider, SignatureHelpProvider, TypeDefinitionProvider, MappedEditsProvider, 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 inlineValuesProvider = new LanguageFeatureRegistry(this._score.bind(this));\n\treadonly evaluatableExpressionProvider = 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 documentOnDropEditProvider = new LanguageFeatureRegistry(this._score.bind(this));\n\treadonly documentPasteEditProvider = new LanguageFeatureRegistry(this._score.bind(this));\n\treadonly mappedEditsProvider: LanguageFeatureRegistry = new LanguageFeatureRegistry(this._score.bind(this));\n\n\tprivate _notebookTypeResolver?: NotebookInfoResolver;\n\n\tsetNotebookTypeResolver(resolver: NotebookInfoResolver | undefined) {\n\t\tthis._notebookTypeResolver = resolver;\n\t}\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 { ITextModel, IModelDecoration } from 'vs/editor/common/model';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\nimport { IMarker } from 'vs/platform/markers/common/markers';\nimport { Event } from 'vs/base/common/event';\nimport { Range } from 'vs/editor/common/core/range';\nimport { URI } from 'vs/base/common/uri';\n\nexport const IMarkerDecorationsService = createDecorator('markerDecorationsService');\n\nexport interface IMarkerDecorationsService {\n\treadonly _serviceBrand: undefined;\n\n\tonDidChangeMarker: Event;\n\n\tgetMarker(uri: URI, decoration: IModelDecoration): IMarker | null;\n\n\tgetLiveMarkers(uri: URI): [Range, IMarker][];\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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\tupdateModel(model: ITextModel, value: string | ITextBufferFactory): void;\n\n\tdestroyModel(resource: URI): void;\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","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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, IReference } from 'vs/base/common/lifecycle';\nimport { URI } from 'vs/base/common/uri';\nimport { ITextModel, ITextSnapshot } 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\t/**\n\t * Registers a specific `scheme` content provider.\n\t */\n\tregisterTextModelContentProvider(scheme: string, provider: ITextModelContentProvider): IDisposable;\n\n\t/**\n\t * Check if the given resource can be resolved to a text model.\n\t */\n\tcanHandleResource(resource: URI): boolean;\n}\n\nexport interface ITextModelContentProvider {\n\n\t/**\n\t * Given a resource, return the content of the resource as `ITextModel`.\n\t */\n\tprovideTextContent(resource: URI): Promise | null;\n}\n\nexport interface ITextEditorModel extends IResolvableEditorModel {\n\n\t/**\n\t * Emitted when the text model is about to be disposed.\n\t */\n\treadonly onWillDispose: Event;\n\n\t/**\n\t * Provides access to the underlying `ITextModel`.\n\t */\n\treadonly textEditorModel: ITextModel | null;\n\n\t/**\n\t * Creates a snapshot of the model's contents.\n\t */\n\tcreateSnapshot(this: IResolvedTextEditorModel): ITextSnapshot;\n\tcreateSnapshot(this: ITextEditorModel): ITextSnapshot | null;\n\n\t/**\n\t * Signals if this model is readonly or not.\n\t */\n\tisReadonly(): boolean | IMarkdownString;\n\n\t/**\n\t * The language id of the text model if known.\n\t */\n\tgetLanguageId(): string | undefined;\n\n\t/**\n\t * Find out if this text model has been disposed.\n\t */\n\tisDisposed(): boolean;\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\nexport function isResolvedTextEditorModel(model: ITextEditorModel): model is IResolvedTextEditorModel {\n\tconst candidate = model as IResolvedTextEditorModel;\n\n\treturn !!candidate.textEditorModel;\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { IPosition } from 'vs/editor/common/core/position';\nimport { ConfigurationTarget, IConfigurationValue } from 'vs/platform/configuration/common/configuration';\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 * Event that fires when the configuration changes.\n\t */\n\tonDidChangeConfiguration: Event;\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\t/**\n\t * Inspects the values of the section for the given resource by applying language overrides.\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\tinspect(resource: URI | undefined, position: IPosition | null, section: string): IConfigurationValue>;\n\n\t/**\n\t * Update the configuration value for the given resource at the effective location.\n\t *\n\t * - If configurationTarget is not specified, target will be derived by checking where the configuration is defined.\n\t * - If the language overrides for the give resource contains the configuration, then it is updated.\n\t *\n\t * @param resource Resource for which the configuration has to be updated\n\t * @param key Configuration key\n\t * @param value Configuration value\n\t * @param configurationTarget Optional target into which the configuration has to be updated.\n\t * If not specified, target will be derived by checking where the configuration is defined.\n\t */\n\tupdateValue(resource: URI, key: string, value: any, configurationTarget?: ConfigurationTarget): Promise;\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 { DropYieldTo, WorkspaceEdit } from 'vs/editor/common/languages';\nimport { Range } from 'vs/editor/common/core/range';\nimport { SnippetParser } from 'vs/editor/contrib/snippet/browser/snippetParser';\n\nexport interface DropOrPasteEdit {\n\treadonly label: string;\n\treadonly insertText: string | { readonly snippet: string };\n\treadonly additionalEdit?: WorkspaceEdit;\n}\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: DropOrPasteEdit): 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\treturn ('providerId' in yTo && yTo.providerId === other.providerId)\n\t\t\t|| ('mimeType' in yTo && yTo.mimeType === other.handledMimeType);\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 for ${node.providerId}`);\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 { 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\t/**\n\t * Find out if resources are copied to the clipboard.\n\t */\n\thasResources(): 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\tonWillExecuteCommand: Event;\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\treadonly returns?: string;\n}\n\nexport interface ICommandRegistry {\n\tonDidRegisterCommand: Event;\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\tgetCommands(): ICommandsMap;\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 * as types from 'vs/base/common/types';\nimport { URI, UriComponents } from 'vs/base/common/uri';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\nimport { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';\n\nexport const IConfigurationService = createDecorator('configurationService');\n\nexport function isConfigurationOverrides(thing: any): thing is IConfigurationOverrides {\n\treturn thing\n\t\t&& typeof thing === 'object'\n\t\t&& (!thing.overrideIdentifier || typeof thing.overrideIdentifier === 'string')\n\t\t&& (!thing.resource || thing.resource instanceof URI);\n}\n\nexport interface IConfigurationOverrides {\n\toverrideIdentifier?: string | null;\n\tresource?: URI | null;\n}\n\nexport function isConfigurationUpdateOverrides(thing: any): thing is IConfigurationUpdateOverrides {\n\treturn thing\n\t\t&& typeof thing === 'object'\n\t\t&& (!thing.overrideIdentifiers || Array.isArray(thing.overrideIdentifiers))\n\t\t&& !thing.overrideIdentifier\n\t\t&& (!thing.resource || thing.resource instanceof URI);\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}\nexport function ConfigurationTargetToString(configurationTarget: ConfigurationTarget) {\n\tswitch (configurationTarget) {\n\t\tcase ConfigurationTarget.APPLICATION: return 'APPLICATION';\n\t\tcase ConfigurationTarget.USER: return 'USER';\n\t\tcase ConfigurationTarget.USER_LOCAL: return 'USER_LOCAL';\n\t\tcase ConfigurationTarget.USER_REMOTE: return 'USER_REMOTE';\n\t\tcase ConfigurationTarget.WORKSPACE: return 'WORKSPACE';\n\t\tcase ConfigurationTarget.WORKSPACE_FOLDER: return 'WORKSPACE_FOLDER';\n\t\tcase ConfigurationTarget.DEFAULT: return 'DEFAULT';\n\t\tcase ConfigurationTarget.MEMORY: return 'MEMORY';\n\t}\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\n\treadonly defaultValue?: T;\n\treadonly applicationValue?: T;\n\treadonly userValue?: T;\n\treadonly userLocalValue?: T;\n\treadonly userRemoteValue?: T;\n\treadonly workspaceValue?: T;\n\treadonly workspaceFolderValue?: T;\n\treadonly memoryValue?: T;\n\treadonly policyValue?: T;\n\treadonly value?: T;\n\n\treadonly default?: IInspectValue;\n\treadonly application?: IInspectValue;\n\treadonly user?: IInspectValue;\n\treadonly userLocal?: IInspectValue;\n\treadonly userRemote?: IInspectValue;\n\treadonly workspace?: IInspectValue;\n\treadonly workspaceFolder?: IInspectValue;\n\treadonly memory?: IInspectValue;\n\treadonly policy?: { value?: T };\n\n\treadonly overrideIdentifiers?: string[];\n}\n\nexport function isConfigured(configValue: IConfigurationValue): configValue is IConfigurationValue & { value: T } {\n\treturn configValue.applicationValue !== undefined ||\n\t\tconfigValue.userValue !== undefined ||\n\t\tconfigValue.userLocalValue !== undefined ||\n\t\tconfigValue.userRemoteValue !== undefined ||\n\t\tconfigValue.workspaceValue !== undefined ||\n\t\tconfigValue.workspaceFolderValue !== undefined;\n}\n\nexport interface IConfigurationUpdateOptions {\n\t/**\n\t * If `true`, do not notifies the error to user by showing the message box. Default is `false`.\n\t */\n\tdonotNotifyError?: boolean;\n\t/**\n\t * How to handle dirty file when updating the configuration.\n\t */\n\thandleDirtyFile?: 'save' | 'revert';\n}\n\nexport interface IConfigurationService {\n\treadonly _serviceBrand: undefined;\n\n\tonDidChangeConfiguration: Event;\n\n\tgetConfigurationData(): IConfigurationData | null;\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\treloadConfiguration(target?: ConfigurationTarget | IWorkspaceFolder): Promise;\n\n\tkeys(): {\n\t\tdefault: string[];\n\t\tuser: string[];\n\t\tworkspace: string[];\n\t\tworkspaceFolder: string[];\n\t\tmemory?: string[];\n\t};\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 interface IConfigurationCompareResult {\n\tadded: string[];\n\tremoved: string[];\n\tupdated: string[];\n\toverrides: [string, string[]][];\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\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 merge(base: any, add: any, overwrite: boolean): void {\n\tObject.keys(add).forEach(key => {\n\t\tif (key !== '__proto__') {\n\t\t\tif (key in base) {\n\t\t\t\tif (types.isObject(base[key]) && types.isObject(add[key])) {\n\t\t\t\t\tmerge(base[key], add[key], overwrite);\n\t\t\t\t} else if (overwrite) {\n\t\t\t\t\tbase[key] = add[key];\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tbase[key] = add[key];\n\t\t\t}\n\t\t}\n\t});\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\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { URI } from 'vs/base/common/uri';\nimport { IPosition, Position } from 'vs/editor/common/core/position';\nimport { ILanguageService } from 'vs/editor/common/languages/language';\nimport { IModelService } from 'vs/editor/common/services/model';\nimport { ITextResourceConfigurationService, ITextResourceConfigurationChangeEvent } from 'vs/editor/common/services/textResourceConfiguration';\nimport { IConfigurationService, ConfigurationTarget, IConfigurationValue, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration';\n\nexport class TextResourceConfigurationService extends Disposable implements ITextResourceConfigurationService {\n\n\tpublic _serviceBrand: undefined;\n\n\tprivate readonly _onDidChangeConfiguration: Emitter = this._register(new Emitter());\n\tpublic readonly onDidChangeConfiguration: Event = this._onDidChangeConfiguration.event;\n\n\tconstructor(\n\t\t@IConfigurationService private readonly configurationService: IConfigurationService,\n\t\t@IModelService private readonly modelService: IModelService,\n\t\t@ILanguageService private readonly languageService: ILanguageService,\n\t) {\n\t\tsuper();\n\t\tthis._register(this.configurationService.onDidChangeConfiguration(e => this._onDidChangeConfiguration.fire(this.toResourceConfigurationChangeEvent(e))));\n\t}\n\n\tgetValue(resource: URI | undefined, section?: string): T;\n\tgetValue(resource: URI | undefined, at?: IPosition, section?: string): T;\n\tgetValue(resource: URI | undefined, arg2?: any, arg3?: any): T {\n\t\tif (typeof arg3 === 'string') {\n\t\t\treturn this._getValue(resource, Position.isIPosition(arg2) ? arg2 : null, arg3);\n\t\t}\n\t\treturn this._getValue(resource, null, typeof arg2 === 'string' ? arg2 : undefined);\n\t}\n\n\tupdateValue(resource: URI, key: string, value: any, configurationTarget?: ConfigurationTarget): Promise {\n\t\tconst language = this.getLanguage(resource, null);\n\t\tconst configurationValue = this.configurationService.inspect(key, { resource, overrideIdentifier: language });\n\t\tif (configurationTarget === undefined) {\n\t\t\tconfigurationTarget = this.deriveConfigurationTarget(configurationValue, language);\n\t\t}\n\t\tswitch (configurationTarget) {\n\t\t\tcase ConfigurationTarget.MEMORY:\n\t\t\t\treturn this._updateValue(key, value, configurationTarget, configurationValue.memory?.override, resource, language);\n\t\t\tcase ConfigurationTarget.WORKSPACE_FOLDER:\n\t\t\t\treturn this._updateValue(key, value, configurationTarget, configurationValue.workspaceFolder?.override, resource, language);\n\t\t\tcase ConfigurationTarget.WORKSPACE:\n\t\t\t\treturn this._updateValue(key, value, configurationTarget, configurationValue.workspace?.override, resource, language);\n\t\t\tcase ConfigurationTarget.USER_REMOTE:\n\t\t\t\treturn this._updateValue(key, value, configurationTarget, configurationValue.userRemote?.override, resource, language);\n\t\t\tdefault:\n\t\t\t\treturn this._updateValue(key, value, configurationTarget, configurationValue.userLocal?.override, resource, language);\n\t\t}\n\t}\n\n\tprivate _updateValue(key: string, value: any, configurationTarget: ConfigurationTarget, overriddenValue: any | undefined, resource: URI, language: string | null): Promise {\n\t\tif (language && overriddenValue !== undefined) {\n\t\t\treturn this.configurationService.updateValue(key, value, { resource, overrideIdentifier: language }, configurationTarget);\n\t\t} else {\n\t\t\treturn this.configurationService.updateValue(key, value, { resource }, configurationTarget);\n\t\t}\n\t}\n\n\tprivate deriveConfigurationTarget(configurationValue: IConfigurationValue, language: string | null): ConfigurationTarget {\n\t\tif (language) {\n\t\t\tif (configurationValue.memory?.override !== undefined) {\n\t\t\t\treturn ConfigurationTarget.MEMORY;\n\t\t\t}\n\t\t\tif (configurationValue.workspaceFolder?.override !== undefined) {\n\t\t\t\treturn ConfigurationTarget.WORKSPACE_FOLDER;\n\t\t\t}\n\t\t\tif (configurationValue.workspace?.override !== undefined) {\n\t\t\t\treturn ConfigurationTarget.WORKSPACE;\n\t\t\t}\n\t\t\tif (configurationValue.userRemote?.override !== undefined) {\n\t\t\t\treturn ConfigurationTarget.USER_REMOTE;\n\t\t\t}\n\t\t\tif (configurationValue.userLocal?.override !== undefined) {\n\t\t\t\treturn ConfigurationTarget.USER_LOCAL;\n\t\t\t}\n\t\t}\n\t\tif (configurationValue.memory?.value !== undefined) {\n\t\t\treturn ConfigurationTarget.MEMORY;\n\t\t}\n\t\tif (configurationValue.workspaceFolder?.value !== undefined) {\n\t\t\treturn ConfigurationTarget.WORKSPACE_FOLDER;\n\t\t}\n\t\tif (configurationValue.workspace?.value !== undefined) {\n\t\t\treturn ConfigurationTarget.WORKSPACE;\n\t\t}\n\t\tif (configurationValue.userRemote?.value !== undefined) {\n\t\t\treturn ConfigurationTarget.USER_REMOTE;\n\t\t}\n\t\treturn ConfigurationTarget.USER_LOCAL;\n\t}\n\n\tprivate _getValue(resource: URI | undefined, position: IPosition | null, section: string | undefined): T {\n\t\tconst language = resource ? this.getLanguage(resource, position) : undefined;\n\t\tif (typeof section === 'undefined') {\n\t\t\treturn this.configurationService.getValue({ resource, overrideIdentifier: language });\n\t\t}\n\t\treturn this.configurationService.getValue(section, { resource, overrideIdentifier: language });\n\t}\n\n\tinspect(resource: URI | undefined, position: IPosition | null, section: string): IConfigurationValue> {\n\t\tconst language = resource ? this.getLanguage(resource, position) : undefined;\n\t\treturn this.configurationService.inspect(section, { resource, overrideIdentifier: language });\n\t}\n\n\tprivate getLanguage(resource: URI, position: IPosition | null): string | null {\n\t\tconst model = this.modelService.getModel(resource);\n\t\tif (model) {\n\t\t\treturn position ? model.getLanguageIdAtPosition(position.lineNumber, position.column) : model.getLanguageId();\n\t\t}\n\t\treturn this.languageService.guessLanguageIdByFilepathOrFirstLine(resource);\n\t}\n\n\tprivate toResourceConfigurationChangeEvent(configurationChangeEvent: IConfigurationChangeEvent): ITextResourceConfigurationChangeEvent {\n\t\treturn {\n\t\t\taffectedKeys: configurationChangeEvent.affectedKeys,\n\t\t\taffectsConfiguration: (resource: URI | undefined, configuration: string) => {\n\t\t\t\tconst overrideIdentifier = resource ? this.getLanguage(resource, null) : undefined;\n\t\t\t\treturn configurationChangeEvent.affectsConfiguration(configuration, { resource, overrideIdentifier });\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 { 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, LexingError, 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';\nimport { illegalArgument } from 'vs/base/common/errors';\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\n/** allow register constant context keys that are known only after startup; requires running `substituteConstants` on the context key - https://github.com/microsoft/vscode/issues/174218#issuecomment-1437972127 */\nexport function setConstant(key: string, value: boolean) {\n\tif (CONSTANT_VALUES.get(key) !== undefined) { throw illegalArgument('contextkey.setConstant(k, v) invoked with already set constant `k`'); }\n\n\tCONSTANT_VALUES.set(key, value);\n}\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 IContextKeyExprMapper {\n\tmapDefined(key: string): ContextKeyExpression;\n\tmapNot(key: string): ContextKeyExpression;\n\tmapEquals(key: string, value: any): ContextKeyExpression;\n\tmapNotEquals(key: string, value: any): ContextKeyExpression;\n\tmapGreater(key: string, value: any): ContextKeyExpression;\n\tmapGreaterEquals(key: string, value: any): ContextKeyExpression;\n\tmapSmaller(key: string, value: any): ContextKeyExpression;\n\tmapSmallerEquals(key: string, value: any): ContextKeyExpression;\n\tmapRegex(key: string, regexp: RegExp | null): ContextKeyRegexExpr;\n\tmapIn(key: string, valueKey: string): ContextKeyInExpr;\n\tmapNotIn(key: string, valueKey: string): ContextKeyNotInExpr;\n}\n\nexport interface IContextKeyExpression {\n\tcmp(other: ContextKeyExpression): number;\n\tequals(other: ContextKeyExpression): boolean;\n\tsubstituteConstants(): ContextKeyExpression | undefined;\n\tevaluate(context: IContext): boolean;\n\tserialize(): string;\n\tkeys(): string[];\n\tmap(mapFnc: IContextKeyExprMapper): ContextKeyExpression;\n\tnegate(): ContextKeyExpression;\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\tget lexingErrors(): Readonly {\n\t\treturn this._scanner.errors;\n\t}\n\n\tget parsingErrors(): Readonly {\n\t\treturn this._parsingErrors;\n\t}\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\tpublic static greater(key: string, value: number): ContextKeyExpression {\n\t\treturn ContextKeyGreaterExpr.create(key, value);\n\t}\n\tpublic static greaterEquals(key: string, value: number): ContextKeyExpression {\n\t\treturn ContextKeyGreaterEqualsExpr.create(key, value);\n\t}\n\tpublic static smaller(key: string, value: number): ContextKeyExpression {\n\t\treturn ContextKeySmallerExpr.create(key, value);\n\t}\n\tpublic static smallerEquals(key: string, value: number): ContextKeyExpression {\n\t\treturn ContextKeySmallerEqualsExpr.create(key, value);\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\n\nexport function validateWhenClauses(whenClauses: string[]): any {\n\n\tconst parser = new Parser({ regexParsingWithErrorRecovery: false }); // we run with no recovery to guide users to use correct regexes\n\n\treturn whenClauses.map(whenClause => {\n\t\tparser.parse(whenClause);\n\n\t\tif (parser.lexingErrors.length > 0) {\n\t\t\treturn parser.lexingErrors.map((se: LexingError) => ({\n\t\t\t\terrorMessage: se.additionalInfo ?\n\t\t\t\t\tlocalize('contextkey.scanner.errorForLinterWithHint', \"Unexpected token. Hint: {0}\", se.additionalInfo) :\n\t\t\t\t\tlocalize('contextkey.scanner.errorForLinter', \"Unexpected token.\"),\n\t\t\t\toffset: se.offset,\n\t\t\t\tlength: se.lexeme.length,\n\t\t\t}));\n\t\t} else if (parser.parsingErrors.length > 0) {\n\t\t\treturn parser.parsingErrors.map((pe: ParsingError) => ({\n\t\t\t\terrorMessage: pe.additionalInfo ? `${pe.message}. ${pe.additionalInfo}` : pe.message,\n\t\t\t\toffset: pe.offset,\n\t\t\t\tlength: pe.lexeme.length,\n\t\t\t}));\n\t\t} else {\n\t\t\treturn [];\n\t\t}\n\t});\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 map(mapFnc: IContextKeyExprMapper): ContextKeyExpression {\n\t\treturn this;\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 map(mapFnc: IContextKeyExprMapper): ContextKeyExpression {\n\t\treturn this;\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 map(mapFnc: IContextKeyExprMapper): ContextKeyExpression {\n\t\treturn mapFnc.mapDefined(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 map(mapFnc: IContextKeyExprMapper): ContextKeyExpression {\n\t\treturn mapFnc.mapEquals(this.key, this.value);\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 map(mapFnc: IContextKeyExprMapper): ContextKeyInExpr {\n\t\treturn mapFnc.mapIn(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 map(mapFnc: IContextKeyExprMapper): ContextKeyExpression {\n\t\treturn mapFnc.mapNotIn(this.key, this.valueKey);\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 map(mapFnc: IContextKeyExprMapper): ContextKeyExpression {\n\t\treturn mapFnc.mapNotEquals(this.key, this.value);\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 map(mapFnc: IContextKeyExprMapper): ContextKeyExpression {\n\t\treturn mapFnc.mapNot(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 map(mapFnc: IContextKeyExprMapper): ContextKeyExpression {\n\t\treturn mapFnc.mapGreater(this.key, this.value);\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 map(mapFnc: IContextKeyExprMapper): ContextKeyExpression {\n\t\treturn mapFnc.mapGreaterEquals(this.key, this.value);\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 map(mapFnc: IContextKeyExprMapper): ContextKeyExpression {\n\t\treturn mapFnc.mapSmaller(this.key, this.value);\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 map(mapFnc: IContextKeyExprMapper): ContextKeyExpression {\n\t\treturn mapFnc.mapSmallerEquals(this.key, this.value);\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 map(mapFnc: IContextKeyExprMapper): ContextKeyRegexExpr {\n\t\treturn mapFnc.mapRegex(this.key, this.regexp);\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 map(mapFnc: IContextKeyExprMapper): ContextKeyExpression {\n\t\treturn new ContextKeyNotRegexExpr(this._actual.map(mapFnc));\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 map(mapFnc: IContextKeyExprMapper): ContextKeyExpression {\n\t\treturn new ContextKeyAndExpr(this.expr.map(expr => expr.map(mapFnc)), null);\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 map(mapFnc: IContextKeyExprMapper): ContextKeyExpression {\n\t\treturn new ContextKeyOrExpr(this.expr.map(expr => expr.map(mapFnc)), null);\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\tpublic notEqualsTo(value: any): ContextKeyExpression {\n\t\treturn ContextKeyNotEqualsExpr.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\tcreateOverlay(overlay: Iterable<[string, any]>): IContextKeyService;\n\tgetContext(target: IContextKeyServiceTarget | null): IContext;\n\n\tupdateParent(parentContextKeyService: IContextKeyService): void;\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\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 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\treadonly onDidChangeReducedMotion: Event;\n\n\talwaysUnderlineAccessKeys(): Promise;\n\tisScreenReaderOptimized(): boolean;\n\tisMotionReduced(): boolean;\n\tgetAccessibilitySupport(): AccessibilitySupport;\n\tsetAccessibilitySupport(accessibilitySupport: AccessibilitySupport): void;\n\talert(message: string): void;\n\tstatus(message: string): void;\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\nexport interface IAccessibilityInformation {\n\tlabel: string;\n\trole?: string;\n}\n\nexport function isAccessibilityInformation(obj: any): obj is IAccessibilityInformation {\n\treturn obj && typeof obj === 'object'\n\t\t&& typeof obj.label === 'string'\n\t\t&& (typeof obj.role === 'undefined' || typeof obj.role === '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 * 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';\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\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\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._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 { Emitter, Event, 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, distinct } 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\tpublic updateParent(parent: Context): void {\n\t\tthis._parent = parent;\n\t}\n\n\tpublic collectAllValues(): Record {\n\t\tlet result = this._parent ? this._parent.collectAllValues() : Object.create(null);\n\t\tresult = { ...result, ...this._value };\n\t\tdelete result['_contextId'];\n\t\treturn result;\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\toverride collectAllValues(): { [key: string]: any } {\n\t\treturn Object.create(null);\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\toverride collectAllValues(): { [key: string]: any } {\n\t\tconst result: { [key: string]: any } = Object.create(null);\n\t\tthis._values.forEach((value, index) => result[index] = value);\n\t\treturn { ...result, ...super.collectAllValues() };\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 get contextId(): number {\n\t\treturn this._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\tcreateOverlay(overlay: Iterable<[string, any]> = Iterable.empty()): IContextKeyService {\n\t\tif (this._isDisposed) {\n\t\t\tthrow new Error(`AbstractContextKeyService has been disposed`);\n\t\t}\n\t\treturn new OverlayContextKeyService(this, overlay);\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\tpublic abstract updateParent(parentContextKeyService?: IContextKeyService): 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\tpublic updateParent(_parentContextKeyService: IContextKeyService): void {\n\t\tthrow new Error('Cannot update parent of root ContextKeyService');\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\tpublic updateParent(parentContextKeyService: AbstractContextKeyService): void {\n\t\tif (this._parent === parentContextKeyService) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst thisContainer = this._parent.getContextValuesContainer(this._myContextId);\n\t\tconst oldAllValues = thisContainer.collectAllValues();\n\t\tthis._parent = parentContextKeyService;\n\t\tthis._updateParentChangeListener();\n\t\tconst newParentContainer = this._parent.getContextValuesContainer(this._parent.contextId);\n\t\tthisContainer.updateParent(newParentContainer);\n\n\t\tconst newAllValues = thisContainer.collectAllValues();\n\t\tconst allValuesDiff = {\n\t\t\t...distinct(oldAllValues, newAllValues),\n\t\t\t...distinct(newAllValues, oldAllValues)\n\t\t};\n\t\tconst changedKeys = Object.keys(allValuesDiff);\n\n\t\tthis._onDidChangeContext.fire(new ArrayContextKeyChangeEvent(changedKeys));\n\t}\n}\n\nclass OverlayContext implements IContext {\n\n\tconstructor(private parent: IContext, private overlay: ReadonlyMap) { }\n\n\tgetValue(key: string): T | undefined {\n\t\treturn this.overlay.has(key) ? this.overlay.get(key) : this.parent.getValue(key);\n\t}\n}\n\nclass OverlayContextKeyService implements IContextKeyService {\n\n\tdeclare _serviceBrand: undefined;\n\tprivate overlay: Map;\n\n\tget contextId(): number {\n\t\treturn this.parent.contextId;\n\t}\n\n\tget onDidChangeContext(): Event {\n\t\treturn this.parent.onDidChangeContext;\n\t}\n\n\tconstructor(private parent: AbstractContextKeyService | OverlayContextKeyService, overlay: Iterable<[string, any]>) {\n\t\tthis.overlay = new Map(overlay);\n\t}\n\n\tbufferChangeEvents(callback: Function): void {\n\t\tthis.parent.bufferChangeEvents(callback);\n\t}\n\n\tcreateKey(): IContextKey {\n\t\tthrow new Error('Not supported.');\n\t}\n\n\tgetContext(target: IContextKeyServiceTarget | null): IContext {\n\t\treturn new OverlayContext(this.parent.getContext(target), this.overlay);\n\t}\n\n\tgetContextValuesContainer(contextId: number): IContext {\n\t\tconst parentContext = this.parent.getContextValuesContainer(contextId);\n\t\treturn new OverlayContext(parentContext, this.overlay);\n\t}\n\n\tcontextMatchesRules(rules: ContextKeyExpression | undefined): boolean {\n\t\tconst context = this.getContextValuesContainer(this.contextId);\n\t\tconst result = (rules ? rules.evaluate(context) : true);\n\t\treturn result;\n\t}\n\n\tgetContextKeyValue(key: string): T | undefined {\n\t\treturn this.overlay.has(key) ? this.overlay.get(key) : this.parent.getContextKeyValue(key);\n\t}\n\n\tcreateScoped(): IScopedContextKeyService {\n\t\tthrow new Error('Not supported.');\n\t}\n\n\tcreateOverlay(overlay: Iterable<[string, any]> = Iterable.empty()): IContextKeyService {\n\t\treturn new OverlayContextKeyService(this, overlay);\n\t}\n\n\tupdateParent(): void {\n\t\tthrow new Error('Not supported.');\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): IDisposable;\n\thideContextView(data?: any): void;\n\tgetContextViewElement(): HTMLElement;\n\tlayout(): void;\n\tanchorAlignment?: AnchorAlignment;\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\tonDOMEvent?(e: any, activeElement: HTMLElement): void;\n\tonHide?(data?: any): void;\n\tfocus?(): void;\n\tanchorAlignment?: AnchorAlignment;\n\tanchorAxisAlignment?: AnchorAxisAlignment;\n}\n\nexport const IContextMenuService = createDecorator('contextMenuService');\n\nexport interface IContextMenuService {\n\n\treadonly _serviceBrand: undefined;\n\n\treadonly onDidShowContextMenu: Event;\n\treadonly onDidHideContextMenu: 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","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { createDecorator } from 'vs/platform/instantiation/common/instantiation';\n\nexport const IExtensionHostDebugService = createDecorator('extensionHostDebugService');\n\nexport interface IAttachSessionEvent {\n\tsessionId: string;\n\tsubId?: string;\n\tport: number;\n}\n\nexport interface ITerminateSessionEvent {\n\tsessionId: string;\n\tsubId?: string;\n}\n\nexport interface IReloadSessionEvent {\n\tsessionId: string;\n}\n\nexport interface ICloseSessionEvent {\n\tsessionId: string;\n}\n\nexport interface IOpenExtensionWindowResult {\n\trendererDebugPort?: number;\n\tsuccess: boolean;\n}\n\nexport interface IExtensionHostDebugService {\n\treadonly _serviceBrand: undefined;\n\n\treload(sessionId: string): void;\n\treadonly onReload: Event;\n\n\tclose(sessionId: string): void;\n\treadonly onClose: Event;\n\n\tattachSession(sessionId: string, port: number, subId?: string): void;\n\treadonly onAttachSession: Event;\n\n\tterminateSession(sessionId: string, subId?: string): void;\n\treadonly onTerminateSession: Event;\n\n\topenExtensionDevelopmentHostWindow(args: string[], debugRenderer: 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 { IStringDictionary } from 'vs/base/common/collections';\nimport { ProcessItem } from 'vs/base/common/processes';\nimport { UriComponents } from 'vs/base/common/uri';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\nimport { IWorkspace } from 'vs/platform/workspace/common/workspace';\n\nexport const ID = 'diagnosticsService';\nexport const IDiagnosticsService = createDecorator(ID);\n\nexport interface IDiagnosticsService {\n\treadonly _serviceBrand: undefined;\n\n\tgetPerformanceInfo(mainProcessInfo: IMainProcessDiagnostics, remoteInfo: (IRemoteDiagnosticInfo | IRemoteDiagnosticError)[]): Promise;\n\tgetSystemInfo(mainProcessInfo: IMainProcessDiagnostics, remoteInfo: (IRemoteDiagnosticInfo | IRemoteDiagnosticError)[]): Promise;\n\tgetDiagnostics(mainProcessInfo: IMainProcessDiagnostics, remoteInfo: (IRemoteDiagnosticInfo | IRemoteDiagnosticError)[]): Promise;\n\tgetWorkspaceFileExtensions(workspace: IWorkspace): Promise<{ extensions: string[] }>;\n\treportWorkspaceStats(workspace: IWorkspaceInformation): Promise;\n}\n\nexport interface IMachineInfo {\n\tos: string;\n\tcpus?: string;\n\tmemory: string;\n\tvmHint: string;\n\tlinuxEnv?: ILinuxEnv;\n}\n\nexport interface ILinuxEnv {\n\tdesktopSession?: string;\n\txdgSessionDesktop?: string;\n\txdgCurrentDesktop?: string;\n\txdgSessionType?: string;\n}\n\nexport interface IDiagnosticInfo {\n\tmachineInfo: IMachineInfo;\n\tworkspaceMetadata?: IStringDictionary;\n\tprocesses?: ProcessItem;\n}\nexport interface SystemInfo extends IMachineInfo {\n\tprocessArgs: string;\n\tgpuStatus: any;\n\tscreenReader: string;\n\tremoteData: (IRemoteDiagnosticInfo | IRemoteDiagnosticError)[];\n\tload?: string;\n}\n\nexport interface IRemoteDiagnosticInfo extends IDiagnosticInfo {\n\thostName: string;\n\tlatency?: {\n\t\tcurrent: number;\n\t\taverage: number;\n\t};\n}\n\nexport interface IRemoteDiagnosticError {\n\thostName: string;\n\terrorMessage: string;\n}\n\nexport interface IDiagnosticInfoOptions {\n\tincludeProcesses?: boolean;\n\tfolders?: UriComponents[];\n\tincludeExtensions?: boolean;\n}\n\nexport interface WorkspaceStatItem {\n\tname: string;\n\tcount: number;\n}\n\nexport interface WorkspaceStats {\n\tfileTypes: WorkspaceStatItem[];\n\tconfigFiles: WorkspaceStatItem[];\n\tfileCount: number;\n\tmaxFilesReached: boolean;\n\tlaunchConfigFiles: WorkspaceStatItem[];\n}\n\nexport interface PerformanceInfo {\n\tprocessInfo?: string;\n\tworkspaceInfo?: string;\n}\n\nexport interface IWorkspaceInformation extends IWorkspace {\n\ttelemetryId: string | undefined;\n\trendererSessionId: string;\n}\n\nexport function isRemoteDiagnosticError(x: any): x is IRemoteDiagnosticError {\n\treturn !!x.hostName && !!x.errorMessage;\n}\n\nexport class NullDiagnosticsService implements IDiagnosticsService {\n\t_serviceBrand: undefined;\n\n\tasync getPerformanceInfo(mainProcessInfo: IMainProcessDiagnostics, remoteInfo: (IRemoteDiagnosticInfo | IRemoteDiagnosticError)[]): Promise {\n\t\treturn {};\n\t}\n\n\tasync getSystemInfo(mainProcessInfo: IMainProcessDiagnostics, remoteInfo: (IRemoteDiagnosticInfo | IRemoteDiagnosticError)[]): Promise {\n\t\treturn {\n\t\t\tprocessArgs: 'nullProcessArgs',\n\t\t\tgpuStatus: 'nullGpuStatus',\n\t\t\tscreenReader: 'nullScreenReader',\n\t\t\tremoteData: [],\n\t\t\tos: 'nullOs',\n\t\t\tmemory: 'nullMemory',\n\t\t\tvmHint: 'nullVmHint',\n\t\t};\n\t}\n\n\tasync getDiagnostics(mainProcessInfo: IMainProcessDiagnostics, remoteInfo: (IRemoteDiagnosticInfo | IRemoteDiagnosticError)[]): Promise {\n\t\treturn '';\n\t}\n\n\tasync getWorkspaceFileExtensions(workspace: IWorkspace): Promise<{ extensions: string[] }> {\n\t\treturn { extensions: [] };\n\t}\n\n\tasync reportWorkspaceStats(workspace: IWorkspaceInformation): Promise { }\n\n}\n\nexport interface IWindowDiagnostics {\n\treadonly id: number;\n\treadonly pid: number;\n\treadonly title: string;\n\treadonly folderURIs: UriComponents[];\n\treadonly remoteAuthority?: string;\n}\n\nexport interface IProcessDiagnostics {\n\treadonly pid: number;\n\treadonly name: string;\n}\n\nexport interface IMainProcessDiagnostics {\n\treadonly mainPID: number;\n\treadonly mainArguments: string[]; // All arguments after argv[0], the exec path\n\treadonly windows: IWindowDiagnostics[];\n\treadonly pidToNames: IProcessDiagnostics[];\n\treadonly screenReader: boolean;\n\treadonly gpuFeatureStatus: any;\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { ThemeIcon } from 'vs/base/common/themables';\nimport { IMarkdownString } from 'vs/base/common/htmlContent';\nimport { basename } from 'vs/base/common/resources';\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';\nimport { ITelemetryData } from 'vs/platform/telemetry/common/telemetry';\nimport { MessageBoxOptions } from 'vs/base/parts/sandbox/common/electronTypes';\nimport { mnemonicButtonLabel } from 'vs/base/common/labels';\nimport { isLinux, isMacintosh, isWindows } from 'vs/base/common/platform';\nimport { IProductService } from 'vs/platform/product/common/productService';\nimport { deepClone } from 'vs/base/common/objects';\n\nexport interface IDialogArgs {\n\treadonly confirmArgs?: IConfirmDialogArgs;\n\treadonly inputArgs?: IInputDialogArgs;\n\treadonly promptArgs?: IPromptDialogArgs;\n}\n\nexport interface IBaseDialogOptions {\n\treadonly type?: Severity | DialogType;\n\n\treadonly title?: string;\n\treadonly message: string;\n\treadonly detail?: string;\n\n\treadonly checkbox?: ICheckbox;\n\n\t/**\n\t * Allows to enforce use of custom dialog even in native environments.\n\t */\n\treadonly custom?: boolean | ICustomDialogOptions;\n}\n\nexport interface IConfirmDialogArgs {\n\treadonly confirmation: IConfirmation;\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 IInputDialogArgs {\n\treadonly input: IInput;\n}\n\nexport interface IInput extends IConfirmation {\n\treadonly inputs: IInputElement[];\n\n\t/**\n\t * If not provided, defaults to `Ok`.\n\t */\n\treadonly primaryButton?: string;\n}\n\nexport interface IInputElement {\n\treadonly type?: 'text' | 'password';\n\treadonly value?: string;\n\treadonly placeholder?: string;\n}\n\nexport interface IInputResult extends IConfirmationResult {\n\n\t/**\n\t * Values for the input fields as provided by the user or `undefined` if none.\n\t */\n\treadonly values?: string[];\n}\n\nexport interface IPromptDialogArgs {\n\treadonly prompt: IPrompt;\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\t/**\n\t * The cancel button to show in the prompt. Defaults to\n\t * `Cancel` if not provided.\n\t */\n\treadonly label?: string;\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\treadonly cancelButton: true | string;\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 interface IAsyncPromptResult extends ICheckboxResult {\n\n\t/**\n\t * The result of the `IPromptButton` that was pressed or `undefined` if none.\n\t */\n\treadonly result?: Promise;\n}\n\nexport interface IAsyncPromptResultWithCancel extends IAsyncPromptResult {\n\treadonly result: Promise;\n}\n\nexport type IDialogResult = IConfirmationResult | IInputResult | IAsyncPromptResult;\n\nexport type DialogType = 'none' | 'info' | 'error' | 'question' | 'warning';\n\nexport interface ICheckbox {\n\treadonly label: string;\n\treadonly checked?: boolean;\n}\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 interface IPickAndOpenOptions {\n\treadonly forceNewWindow?: boolean;\n\tdefaultUri?: URI;\n\treadonly telemetryExtraData?: ITelemetryData;\n\tavailableFileSystems?: string[];\n\tremoteAuthority?: string | null;\n}\n\nexport interface FileFilter {\n\treadonly extensions: string[];\n\treadonly name: string;\n}\n\nexport interface ISaveDialogOptions {\n\n\t/**\n\t * A human-readable string for the dialog title\n\t */\n\ttitle?: string;\n\n\t/**\n\t * The resource the dialog shows when opened.\n\t */\n\tdefaultUri?: URI;\n\n\t/**\n\t * A set of file filters that are used by the dialog. Each entry is a human readable label,\n\t * like \"TypeScript\", and an array of extensions.\n\t */\n\tfilters?: FileFilter[];\n\n\t/**\n\t * A human-readable string for the ok button\n\t */\n\treadonly saveLabel?: string;\n\n\t/**\n\t * Specifies a list of schemas for the file systems the user can save to. If not specified, uses the schema of the defaultURI or, if also not specified,\n\t * the schema of the current window.\n\t */\n\tavailableFileSystems?: readonly string[];\n}\n\nexport interface IOpenDialogOptions {\n\n\t/**\n\t * A human-readable string for the dialog title\n\t */\n\treadonly title?: string;\n\n\t/**\n\t * The resource the dialog shows when opened.\n\t */\n\tdefaultUri?: URI;\n\n\t/**\n\t * A human-readable string for the open button.\n\t */\n\treadonly openLabel?: string;\n\n\t/**\n\t * Allow to select files, defaults to `true`.\n\t */\n\tcanSelectFiles?: boolean;\n\n\t/**\n\t * Allow to select folders, defaults to `false`.\n\t */\n\tcanSelectFolders?: boolean;\n\n\t/**\n\t * Allow to select many files or folders.\n\t */\n\treadonly canSelectMany?: boolean;\n\n\t/**\n\t * A set of file filters that are used by the dialog. Each entry is a human readable label,\n\t * like \"TypeScript\", and an array of extensions.\n\t */\n\tfilters?: FileFilter[];\n\n\t/**\n\t * Specifies a list of schemas for the file systems the user can load from. If not specified, uses the schema of the defaultURI or, if also not available,\n\t * the schema of the current window.\n\t */\n\tavailableFileSystems?: readonly string[];\n}\n\nexport const IDialogService = createDecorator('dialogService');\n\nexport interface ICustomDialogOptions {\n\treadonly buttonDetails?: string[];\n\treadonly markdownDetails?: ICustomDialogMarkdown[];\n\treadonly classes?: string[];\n\treadonly icon?: ThemeIcon;\n\treadonly disableCloseAction?: boolean;\n}\n\nexport interface ICustomDialogMarkdown {\n\treadonly markdown: IMarkdownString;\n\treadonly classes?: string[];\n}\n\n/**\n * A handler to bring up modal dialogs.\n */\nexport interface IDialogHandler {\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.\n\t */\n\tprompt(prompt: IPrompt): Promise>;\n\n\t/**\n\t * Present a modal dialog to the user asking for input.\n\t */\n\tinput(input: IInput): Promise;\n\n\t/**\n\t * Present the about dialog to the user.\n\t */\n\tabout(): Promise;\n}\n\nenum DialogKind {\n\tConfirmation = 1,\n\tPrompt,\n\tInput\n}\n\nexport abstract class AbstractDialogHandler implements IDialogHandler {\n\n\tprotected getConfirmationButtons(dialog: IConfirmation): string[] {\n\t\treturn this.getButtons(dialog, DialogKind.Confirmation);\n\t}\n\n\tprotected getPromptButtons(dialog: IPrompt): string[] {\n\t\treturn this.getButtons(dialog, DialogKind.Prompt);\n\t}\n\n\tprotected getInputButtons(dialog: IInput): string[] {\n\t\treturn this.getButtons(dialog, DialogKind.Input);\n\t}\n\n\tprivate getButtons(dialog: IConfirmation, kind: DialogKind.Confirmation): string[];\n\tprivate getButtons(dialog: IPrompt, kind: DialogKind.Prompt): string[];\n\tprivate getButtons(dialog: IInput, kind: DialogKind.Input): string[];\n\tprivate getButtons(dialog: IConfirmation | IInput | IPrompt, kind: DialogKind): string[] {\n\n\t\t// We put buttons in the order of \"default\" button first and \"cancel\"\n\t\t// button last. There maybe later processing when presenting the buttons\n\t\t// based on OS standards.\n\n\t\tconst buttons: string[] = [];\n\n\t\tswitch (kind) {\n\t\t\tcase DialogKind.Confirmation: {\n\t\t\t\tconst confirmationDialog = dialog as IConfirmation;\n\n\t\t\t\tif (confirmationDialog.primaryButton) {\n\t\t\t\t\tbuttons.push(confirmationDialog.primaryButton);\n\t\t\t\t} else {\n\t\t\t\t\tbuttons.push(localize({ key: 'yesButton', comment: ['&& denotes a mnemonic'] }, \"&&Yes\"));\n\t\t\t\t}\n\n\t\t\t\tif (confirmationDialog.cancelButton) {\n\t\t\t\t\tbuttons.push(confirmationDialog.cancelButton);\n\t\t\t\t} else {\n\t\t\t\t\tbuttons.push(localize('cancelButton', \"Cancel\"));\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase DialogKind.Prompt: {\n\t\t\t\tconst promptDialog = dialog as IPrompt;\n\n\t\t\t\tif (Array.isArray(promptDialog.buttons) && promptDialog.buttons.length > 0) {\n\t\t\t\t\tbuttons.push(...promptDialog.buttons.map(button => button.label));\n\t\t\t\t}\n\n\t\t\t\tif (promptDialog.cancelButton) {\n\t\t\t\t\tif (promptDialog.cancelButton === true) {\n\t\t\t\t\t\tbuttons.push(localize('cancelButton', \"Cancel\"));\n\t\t\t\t\t} else if (typeof promptDialog.cancelButton === 'string') {\n\t\t\t\t\t\tbuttons.push(promptDialog.cancelButton);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (promptDialog.cancelButton.label) {\n\t\t\t\t\t\t\tbuttons.push(promptDialog.cancelButton.label);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tbuttons.push(localize('cancelButton', \"Cancel\"));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (buttons.length === 0) {\n\t\t\t\t\tbuttons.push(localize({ key: 'okButton', comment: ['&& denotes a mnemonic'] }, \"&&OK\"));\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase DialogKind.Input: {\n\t\t\t\tconst inputDialog = dialog as IInput;\n\n\t\t\t\tif (inputDialog.primaryButton) {\n\t\t\t\t\tbuttons.push(inputDialog.primaryButton);\n\t\t\t\t} else {\n\t\t\t\t\tbuttons.push(localize({ key: 'okButton', comment: ['&& denotes a mnemonic'] }, \"&&OK\"));\n\t\t\t\t}\n\n\t\t\t\tif (inputDialog.cancelButton) {\n\t\t\t\t\tbuttons.push(inputDialog.cancelButton);\n\t\t\t\t} else {\n\t\t\t\t\tbuttons.push(localize('cancelButton', \"Cancel\"));\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn buttons;\n\t}\n\n\tprotected getDialogType(type: Severity | DialogType | undefined): DialogType | undefined {\n\t\tif (typeof type === 'string') {\n\t\t\treturn type;\n\t\t}\n\n\t\tif (typeof type === 'number') {\n\t\t\treturn (type === Severity.Info) ? 'info' : (type === Severity.Error) ? 'error' : (type === Severity.Warning) ? 'warning' : 'none';\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tprotected getPromptResult(prompt: IPrompt, buttonIndex: number, checkboxChecked: boolean | undefined): IAsyncPromptResult {\n\t\tconst promptButtons: IPromptBaseButton[] = [...(prompt.buttons ?? [])];\n\t\tif (prompt.cancelButton && typeof prompt.cancelButton !== 'string' && typeof prompt.cancelButton !== 'boolean') {\n\t\t\tpromptButtons.push(prompt.cancelButton);\n\t\t}\n\n\t\tlet result = promptButtons[buttonIndex]?.run({ checkboxChecked });\n\t\tif (!(result instanceof Promise)) {\n\t\t\tresult = Promise.resolve(result);\n\t\t}\n\n\t\treturn { result, checkboxChecked };\n\t}\n\n\tabstract confirm(confirmation: IConfirmation): Promise;\n\tabstract input(input: IInput): Promise;\n\tabstract prompt(prompt: IPrompt): Promise>;\n\tabstract about(): Promise;\n}\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 * An event that fires when a dialog is about to show.\n\t */\n\tonWillShowDialog: Event;\n\n\t/**\n\t * An event that fires when a dialog did show (closed).\n\t */\n\tonDidShowDialog: Event;\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 * Present a modal dialog to the user asking for input.\n\t */\n\tinput(input: IInput): Promise;\n\n\t/**\n\t * Show a modal info dialog.\n\t */\n\tinfo(message: string, detail?: string): Promise;\n\n\t/**\n\t * Show a modal warning dialog.\n\t */\n\twarn(message: string, detail?: string): Promise;\n\n\t/**\n\t * Show a modal error dialog.\n\t */\n\terror(message: string, detail?: string): Promise;\n\n\t/**\n\t * Present the about dialog to the user.\n\t */\n\tabout(): Promise;\n}\n\nexport const IFileDialogService = createDecorator('fileDialogService');\n\n/**\n * A service to bring up file dialogs.\n */\nexport interface IFileDialogService {\n\n\treadonly _serviceBrand: undefined;\n\n\t/**\n\t * The default path for a new file based on previously used files.\n\t * @param schemeFilter The scheme of the file path. If no filter given, the scheme of the current window is used.\n\t * Falls back to user home in the absence of enough information to find a better URI.\n\t */\n\tdefaultFilePath(schemeFilter?: string): Promise;\n\n\t/**\n\t * The default path for a new folder based on previously used folders.\n\t * @param schemeFilter The scheme of the folder path. If no filter given, the scheme of the current window is used.\n\t * Falls back to user home in the absence of enough information to find a better URI.\n\t */\n\tdefaultFolderPath(schemeFilter?: string): Promise;\n\n\t/**\n\t * The default path for a new workspace based on previously used workspaces.\n\t * @param schemeFilter The scheme of the workspace path. If no filter given, the scheme of the current window is used.\n\t * Falls back to user home in the absence of enough information to find a better URI.\n\t */\n\tdefaultWorkspacePath(schemeFilter?: string): Promise;\n\n\t/**\n\t * Shows a file-folder selection dialog and opens the selected entry.\n\t */\n\tpickFileFolderAndOpen(options: IPickAndOpenOptions): Promise;\n\n\t/**\n\t * Shows a file selection dialog and opens the selected entry.\n\t */\n\tpickFileAndOpen(options: IPickAndOpenOptions): Promise;\n\n\t/**\n\t * Shows a folder selection dialog and opens the selected entry.\n\t */\n\tpickFolderAndOpen(options: IPickAndOpenOptions): Promise;\n\n\t/**\n\t * Shows a workspace selection dialog and opens the selected entry.\n\t */\n\tpickWorkspaceAndOpen(options: IPickAndOpenOptions): Promise;\n\n\t/**\n\t * Shows a save file dialog and save the file at the chosen file URI.\n\t */\n\tpickFileToSave(defaultUri: URI, availableFileSystems?: string[]): Promise;\n\n\t/**\n\t * The preferred folder path to open the dialog at.\n\t * @param schemeFilter The scheme of the file path. If no filter given, the scheme of the current window is used.\n\t * Falls back to user home in the absence of a setting.\n\t */\n\tpreferredHome(schemeFilter?: string): Promise;\n\n\t/**\n\t * Shows a save file dialog and returns the chosen file URI.\n\t */\n\tshowSaveDialog(options: ISaveDialogOptions): Promise;\n\n\t/**\n\t * Shows a confirm dialog for saving 1-N files.\n\t */\n\tshowSaveConfirm(fileNamesOrResources: (string | URI)[]): Promise;\n\n\t/**\n\t * Shows a open file dialog and returns the chosen file URI.\n\t */\n\tshowOpenDialog(options: IOpenDialogOptions): Promise;\n}\n\nexport const enum ConfirmResult {\n\tSAVE,\n\tDONT_SAVE,\n\tCANCEL\n}\n\nconst MAX_CONFIRM_FILES = 10;\nexport function getFileNamesMessage(fileNamesOrResources: readonly (string | URI)[]): string {\n\tconst message: string[] = [];\n\tmessage.push(...fileNamesOrResources.slice(0, MAX_CONFIRM_FILES).map(fileNameOrResource => typeof fileNameOrResource === 'string' ? fileNameOrResource : basename(fileNameOrResource)));\n\n\tif (fileNamesOrResources.length > MAX_CONFIRM_FILES) {\n\t\tif (fileNamesOrResources.length - MAX_CONFIRM_FILES === 1) {\n\t\t\tmessage.push(localize('moreFile', \"...1 additional file not shown\"));\n\t\t} else {\n\t\t\tmessage.push(localize('moreFiles', \"...{0} additional files not shown\", fileNamesOrResources.length - MAX_CONFIRM_FILES));\n\t\t}\n\t}\n\n\tmessage.push('');\n\treturn message.join('\\n');\n}\n\nexport interface INativeOpenDialogOptions {\n\treadonly forceNewWindow?: boolean;\n\n\treadonly defaultPath?: string;\n\n\treadonly telemetryEventName?: string;\n\treadonly telemetryExtraData?: ITelemetryData;\n}\n\nexport interface IMassagedMessageBoxOptions {\n\n\t/**\n\t * OS massaged message box options.\n\t */\n\treadonly options: MessageBoxOptions;\n\n\t/**\n\t * Since the massaged result of the message box options potentially\n\t * changes the order of buttons, we have to keep a map of these\n\t * changes so that we can still return the correct index to the caller.\n\t */\n\treadonly buttonIndeces: number[];\n}\n\n/**\n * A utility method to ensure the options for the message box dialog\n * are using properties that are consistent across all platforms and\n * specific to the platform where necessary.\n */\nexport function massageMessageBoxOptions(options: MessageBoxOptions, productService: IProductService): IMassagedMessageBoxOptions {\n\tconst massagedOptions = deepClone(options);\n\n\tlet buttons = (massagedOptions.buttons ?? []).map(button => mnemonicButtonLabel(button));\n\tlet buttonIndeces = (options.buttons || []).map((button, index) => index);\n\n\tlet defaultId = 0; // by default the first button is default button\n\tlet cancelId = massagedOptions.cancelId ?? buttons.length - 1; // by default the last button is cancel button\n\n\t// Apply HIG per OS when more than one button is used\n\tif (buttons.length > 1) {\n\t\tconst cancelButton = typeof cancelId === 'number' ? buttons[cancelId] : undefined;\n\n\t\tif (isLinux || isMacintosh) {\n\n\t\t\t// Linux: the GNOME HIG (https://developer.gnome.org/hig/patterns/feedback/dialogs.html?highlight=dialog)\n\t\t\t// recommend the following:\n\t\t\t// \"Always ensure that the cancel button appears first, before the affirmative button. In left-to-right\n\t\t\t// locales, this is on the left. This button order ensures that users become aware of, and are reminded\n\t\t\t// of, the ability to cancel prior to encountering the affirmative button.\"\n\t\t\t//\n\t\t\t// Electron APIs do not reorder buttons for us, so we ensure a reverse order of buttons and a position\n\t\t\t// of the cancel button (if provided) that matches the HIG\n\n\t\t\t// macOS: the HIG (https://developer.apple.com/design/human-interface-guidelines/components/presentation/alerts)\n\t\t\t// recommend the following:\n\t\t\t// \"Place buttons where people expect. In general, place the button people are most likely to choose on the trailing side in a\n\t\t\t// row of buttons or at the top in a stack of buttons. Always place the default button on the trailing side of a row or at the\n\t\t\t// top of a stack. Cancel buttons are typically on the leading side of a row or at the bottom of a stack.\"\n\t\t\t//\n\t\t\t// However: it seems that older macOS versions where 3 buttons were presented in a row differ from this\n\t\t\t// recommendation. In fact, cancel buttons were placed to the left of the default button and secondary\n\t\t\t// buttons on the far left. To support these older macOS versions we have to manually shuffle the cancel\n\t\t\t// button in the same way as we do on Linux. This will not have any impact on newer macOS versions where\n\t\t\t// shuffling is done for us.\n\n\t\t\tif (typeof cancelButton === 'string' && buttons.length > 1 && cancelId !== 1) {\n\t\t\t\tbuttons.splice(cancelId, 1);\n\t\t\t\tbuttons.splice(1, 0, cancelButton);\n\n\t\t\t\tconst cancelButtonIndex = buttonIndeces[cancelId];\n\t\t\t\tbuttonIndeces.splice(cancelId, 1);\n\t\t\t\tbuttonIndeces.splice(1, 0, cancelButtonIndex);\n\n\t\t\t\tcancelId = 1;\n\t\t\t}\n\n\t\t\tif (isLinux && buttons.length > 1) {\n\t\t\t\tbuttons = buttons.reverse();\n\t\t\t\tbuttonIndeces = buttonIndeces.reverse();\n\n\t\t\t\tdefaultId = buttons.length - 1;\n\t\t\t\tif (typeof cancelButton === 'string') {\n\t\t\t\t\tcancelId = defaultId - 1;\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (isWindows) {\n\n\t\t\t// Windows: the HIG (https://learn.microsoft.com/en-us/windows/win32/uxguide/win-dialog-box)\n\t\t\t// recommend the following:\n\t\t\t// \"One of the following sets of concise commands: Yes/No, Yes/No/Cancel, [Do it]/Cancel,\n\t\t\t// [Do it]/[Don't do it], [Do it]/[Don't do it]/Cancel.\"\n\t\t\t//\n\t\t\t// Electron APIs do not reorder buttons for us, so we ensure the position of the cancel button\n\t\t\t// (if provided) that matches the HIG\n\n\t\t\tif (typeof cancelButton === 'string' && buttons.length > 1 && cancelId !== buttons.length - 1 /* last action */) {\n\t\t\t\tbuttons.splice(cancelId, 1);\n\t\t\t\tbuttons.push(cancelButton);\n\n\t\t\t\tconst buttonIndex = buttonIndeces[cancelId];\n\t\t\t\tbuttonIndeces.splice(cancelId, 1);\n\t\t\t\tbuttonIndeces.push(buttonIndex);\n\n\t\t\t\tcancelId = buttons.length - 1;\n\t\t\t}\n\t\t}\n\t}\n\n\tmassagedOptions.buttons = buttons;\n\tmassagedOptions.defaultId = defaultId;\n\tmassagedOptions.cancelId = cancelId;\n\tmassagedOptions.noLink = true;\n\tmassagedOptions.title = massagedOptions.title || productService.nameLong;\n\n\treturn {\n\t\toptions: massagedOptions,\n\t\tbuttonIndeces\n\t};\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { URI } from 'vs/base/common/uri';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\n\nexport const IDownloadService = createDecorator('downloadService');\n\nexport interface IDownloadService {\n\n\treadonly _serviceBrand: undefined;\n\n\tdownload(uri: URI, to: URI, cancellationToken?: CancellationToken): Promise;\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 { createDecorator } from 'vs/platform/instantiation/common/instantiation';\n\nexport const IEncryptionService = createDecorator('encryptionService');\nexport interface IEncryptionService extends ICommonEncryptionService {\n\tsetUsePlainTextEncryption(): Promise;\n\tgetKeyStorageProvider(): Promise;\n}\n\nexport const IEncryptionMainService = createDecorator('encryptionMainService');\nexport interface IEncryptionMainService extends IEncryptionService { }\n\nexport interface ICommonEncryptionService {\n\n\treadonly _serviceBrand: undefined;\n\n\tencrypt(value: string): Promise;\n\n\tdecrypt(value: string): Promise;\n\n\tisEncryptionAvailable(): Promise;\n}\n\n// The values provided to the `password-store` command line switch.\n// Notice that they are not the same as the values returned by\n// `getSelectedStorageBackend` in the `safeStorage` API.\nexport const enum PasswordStoreCLIOption {\n\tkwallet = 'kwallet',\n\tkwallet5 = 'kwallet5',\n\tgnomeLibsecret = 'gnome-libsecret',\n\tbasic = 'basic'\n}\n\n// The values returned by `getSelectedStorageBackend` in the `safeStorage` API.\nexport const enum KnownStorageProvider {\n\tunknown = 'unknown',\n\tbasicText = 'basic_text',\n\n\t// Linux\n\tgnomeAny = 'gnome_any',\n\tgnomeLibsecret = 'gnome_libsecret',\n\tgnomeKeyring = 'gnome_keyring',\n\tkwallet = 'kwallet',\n\tkwallet5 = 'kwallet5',\n\tkwallet6 = 'kwallet6',\n\n\t// The rest of these are not returned by `getSelectedStorageBackend`\n\t// but these were added for platform completeness.\n\n\t// Windows\n\tdplib = 'dpapi',\n\n\t// macOS\n\tkeychainAccess = 'keychain_access',\n}\n\nexport function isKwallet(backend: string): boolean {\n\treturn backend === KnownStorageProvider.kwallet\n\t\t|| backend === KnownStorageProvider.kwallet5\n\t\t|| backend === KnownStorageProvider.kwallet6;\n}\n\nexport function isGnome(backend: string): boolean {\n\treturn backend === KnownStorageProvider.gnomeAny\n\t\t|| backend === KnownStorageProvider.gnomeLibsecret\n\t\t|| backend === KnownStorageProvider.gnomeKeyring;\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { NativeParsedArgs } from 'vs/platform/environment/common/argv';\nimport { createDecorator, refineServiceDecorator } from 'vs/platform/instantiation/common/instantiation';\n\nexport const IEnvironmentService = createDecorator('environmentService');\nexport const INativeEnvironmentService = refineServiceDecorator(IEnvironmentService);\n\nexport interface IDebugParams {\n\tport: number | null;\n\tbreak: boolean;\n}\n\nexport interface IExtensionHostDebugParams extends IDebugParams {\n\tdebugId?: string;\n\tenv?: Record;\n}\n\n/**\n * Type of extension.\n *\n * **NOTE**: This is defined in `platform/environment` because it can appear as a CLI argument.\n */\nexport type ExtensionKind = 'ui' | 'workspace' | 'web';\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\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\t// --- user roaming data\n\tstateResource: URI;\n\tuserRoamingDataHome: URI;\n\tkeyboardLayoutResource: URI;\n\targvResource: URI;\n\n\t// --- data paths\n\tuntitledWorkspacesHome: URI;\n\tworkspaceStorageHome: URI;\n\tlocalHistoryHome: URI;\n\tcacheHome: URI;\n\n\t// --- settings sync\n\tuserDataSyncHome: URI;\n\tsync: 'on' | 'off' | undefined;\n\n\t// --- continue edit session\n\tcontinueOn?: string;\n\teditSessionId?: string;\n\n\t// --- extension development\n\tdebugExtensionHost: IExtensionHostDebugParams;\n\tisExtensionDevelopment: boolean;\n\tdisableExtensions: boolean | string[];\n\tenableExtensions?: readonly string[];\n\textensionDevelopmentLocationURI?: URI[];\n\textensionDevelopmentKind?: ExtensionKind[];\n\textensionTestsLocationURI?: URI;\n\n\t// --- logging\n\tlogsHome: URI;\n\tlogLevel?: string;\n\textensionLogLevel?: [string, string][];\n\tverbose: boolean;\n\tisBuilt: boolean;\n\n\t// --- telemetry\n\tdisableTelemetry: boolean;\n\tserviceMachineIdResource: URI;\n\n\t// --- Policy\n\tpolicyFile?: URI;\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/**\n * A subclass of the `IEnvironmentService` to be used only in native\n * environments (Windows, Linux, macOS) but not e.g. web.\n */\nexport interface INativeEnvironmentService extends IEnvironmentService {\n\n\t// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\t//\n\t// NOTE: KEEP THIS INTERFACE AS SMALL AS POSSIBLE.\n\t//\n\t// AS SUCH:\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\t// --- CLI Arguments\n\targs: NativeParsedArgs;\n\n\t// --- data paths\n\t/**\n\t * Root path of the JavaScript sources.\n\t *\n\t * Note: This is NOT the installation root\n\t * directory itself but contained in it at\n\t * a level that is platform dependent.\n\t */\n\tappRoot: string;\n\tuserHome: URI;\n\tappSettingsHome: URI;\n\ttmpDir: URI;\n\tuserDataPath: string;\n\tmachineSettingsResource: URI;\n\n\t// --- extensions\n\textensionsPath: string;\n\textensionsDownloadLocation: URI;\n\tbuiltinExtensionsPath: string;\n\n\t// --- use in-memory Secret Storage\n\tuseInMemorySecretStorage?: boolean;\n\n\tcrossOriginIsolated?: 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 { CancellationToken } from 'vs/base/common/cancellation';\nimport { IStringDictionary } from 'vs/base/common/collections';\nimport { Event } from 'vs/base/common/event';\nimport { IPager } from 'vs/base/common/paging';\nimport { Platform } from 'vs/base/common/platform';\nimport { URI } from 'vs/base/common/uri';\nimport { localize2 } from 'vs/nls';\nimport { ExtensionType, IExtension, IExtensionManifest, TargetPlatform } from 'vs/platform/extensions/common/extensions';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\n\nexport const EXTENSION_IDENTIFIER_PATTERN = '^([a-z0-9A-Z][a-z0-9-A-Z]*)\\\\.([a-z0-9A-Z][a-z0-9-A-Z]*)$';\nexport const EXTENSION_IDENTIFIER_REGEX = new RegExp(EXTENSION_IDENTIFIER_PATTERN);\nexport const WEB_EXTENSION_TAG = '__web_extension';\nexport const EXTENSION_INSTALL_SKIP_WALKTHROUGH_CONTEXT = 'skipWalkthrough';\nexport const EXTENSION_INSTALL_SYNC_CONTEXT = 'extensionsSync';\nexport const EXTENSION_INSTALL_DEP_PACK_CONTEXT = 'dependecyOrPackExtensionInstall';\n\nexport function TargetPlatformToString(targetPlatform: TargetPlatform) {\n\tswitch (targetPlatform) {\n\t\tcase TargetPlatform.WIN32_X64: return 'Windows 64 bit';\n\t\tcase TargetPlatform.WIN32_ARM64: return 'Windows ARM';\n\n\t\tcase TargetPlatform.LINUX_X64: return 'Linux 64 bit';\n\t\tcase TargetPlatform.LINUX_ARM64: return 'Linux ARM 64';\n\t\tcase TargetPlatform.LINUX_ARMHF: return 'Linux ARM';\n\n\t\tcase TargetPlatform.ALPINE_X64: return 'Alpine Linux 64 bit';\n\t\tcase TargetPlatform.ALPINE_ARM64: return 'Alpine ARM 64';\n\n\t\tcase TargetPlatform.DARWIN_X64: return 'Mac';\n\t\tcase TargetPlatform.DARWIN_ARM64: return 'Mac Silicon';\n\n\t\tcase TargetPlatform.WEB: return 'Web';\n\n\t\tcase TargetPlatform.UNIVERSAL: return TargetPlatform.UNIVERSAL;\n\t\tcase TargetPlatform.UNKNOWN: return TargetPlatform.UNKNOWN;\n\t\tcase TargetPlatform.UNDEFINED: return TargetPlatform.UNDEFINED;\n\t}\n}\n\nexport function toTargetPlatform(targetPlatform: string): TargetPlatform {\n\tswitch (targetPlatform) {\n\t\tcase TargetPlatform.WIN32_X64: return TargetPlatform.WIN32_X64;\n\t\tcase TargetPlatform.WIN32_ARM64: return TargetPlatform.WIN32_ARM64;\n\n\t\tcase TargetPlatform.LINUX_X64: return TargetPlatform.LINUX_X64;\n\t\tcase TargetPlatform.LINUX_ARM64: return TargetPlatform.LINUX_ARM64;\n\t\tcase TargetPlatform.LINUX_ARMHF: return TargetPlatform.LINUX_ARMHF;\n\n\t\tcase TargetPlatform.ALPINE_X64: return TargetPlatform.ALPINE_X64;\n\t\tcase TargetPlatform.ALPINE_ARM64: return TargetPlatform.ALPINE_ARM64;\n\n\t\tcase TargetPlatform.DARWIN_X64: return TargetPlatform.DARWIN_X64;\n\t\tcase TargetPlatform.DARWIN_ARM64: return TargetPlatform.DARWIN_ARM64;\n\n\t\tcase TargetPlatform.WEB: return TargetPlatform.WEB;\n\n\t\tcase TargetPlatform.UNIVERSAL: return TargetPlatform.UNIVERSAL;\n\t\tdefault: return TargetPlatform.UNKNOWN;\n\t}\n}\n\nexport function getTargetPlatform(platform: Platform | 'alpine', arch: string | undefined): TargetPlatform {\n\tswitch (platform) {\n\t\tcase Platform.Windows:\n\t\t\tif (arch === 'x64') {\n\t\t\t\treturn TargetPlatform.WIN32_X64;\n\t\t\t}\n\t\t\tif (arch === 'arm64') {\n\t\t\t\treturn TargetPlatform.WIN32_ARM64;\n\t\t\t}\n\t\t\treturn TargetPlatform.UNKNOWN;\n\n\t\tcase Platform.Linux:\n\t\t\tif (arch === 'x64') {\n\t\t\t\treturn TargetPlatform.LINUX_X64;\n\t\t\t}\n\t\t\tif (arch === 'arm64') {\n\t\t\t\treturn TargetPlatform.LINUX_ARM64;\n\t\t\t}\n\t\t\tif (arch === 'arm') {\n\t\t\t\treturn TargetPlatform.LINUX_ARMHF;\n\t\t\t}\n\t\t\treturn TargetPlatform.UNKNOWN;\n\n\t\tcase 'alpine':\n\t\t\tif (arch === 'x64') {\n\t\t\t\treturn TargetPlatform.ALPINE_X64;\n\t\t\t}\n\t\t\tif (arch === 'arm64') {\n\t\t\t\treturn TargetPlatform.ALPINE_ARM64;\n\t\t\t}\n\t\t\treturn TargetPlatform.UNKNOWN;\n\n\t\tcase Platform.Mac:\n\t\t\tif (arch === 'x64') {\n\t\t\t\treturn TargetPlatform.DARWIN_X64;\n\t\t\t}\n\t\t\tif (arch === 'arm64') {\n\t\t\t\treturn TargetPlatform.DARWIN_ARM64;\n\t\t\t}\n\t\t\treturn TargetPlatform.UNKNOWN;\n\n\t\tcase Platform.Web: return TargetPlatform.WEB;\n\t}\n}\n\nexport function isNotWebExtensionInWebTargetPlatform(allTargetPlatforms: TargetPlatform[], productTargetPlatform: TargetPlatform): boolean {\n\t// Not a web extension in web target platform\n\treturn productTargetPlatform === TargetPlatform.WEB && !allTargetPlatforms.includes(TargetPlatform.WEB);\n}\n\nexport function isTargetPlatformCompatible(extensionTargetPlatform: TargetPlatform, allTargetPlatforms: TargetPlatform[], productTargetPlatform: TargetPlatform): boolean {\n\t// Not compatible when extension is not a web extension in web target platform\n\tif (isNotWebExtensionInWebTargetPlatform(allTargetPlatforms, productTargetPlatform)) {\n\t\treturn false;\n\t}\n\n\t// Compatible when extension target platform is not defined\n\tif (extensionTargetPlatform === TargetPlatform.UNDEFINED) {\n\t\treturn true;\n\t}\n\n\t// Compatible when extension target platform is universal\n\tif (extensionTargetPlatform === TargetPlatform.UNIVERSAL) {\n\t\treturn true;\n\t}\n\n\t// Not compatible when extension target platform is unknown\n\tif (extensionTargetPlatform === TargetPlatform.UNKNOWN) {\n\t\treturn false;\n\t}\n\n\t// Compatible when extension and product target platforms matches\n\tif (extensionTargetPlatform === productTargetPlatform) {\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\nexport interface IGalleryExtensionProperties {\n\tdependencies?: string[];\n\textensionPack?: string[];\n\tengine?: string;\n\tlocalizedLanguages?: string[];\n\ttargetPlatform: TargetPlatform;\n\tisPreReleaseVersion: boolean;\n}\n\nexport interface IGalleryExtensionAsset {\n\turi: string;\n\tfallbackUri: string;\n}\n\nexport interface IGalleryExtensionAssets {\n\tmanifest: IGalleryExtensionAsset | null;\n\treadme: IGalleryExtensionAsset | null;\n\tchangelog: IGalleryExtensionAsset | null;\n\tlicense: IGalleryExtensionAsset | null;\n\trepository: IGalleryExtensionAsset | null;\n\tdownload: IGalleryExtensionAsset;\n\ticon: IGalleryExtensionAsset | null;\n\tsignature: IGalleryExtensionAsset | null;\n\tcoreTranslations: [string, IGalleryExtensionAsset][];\n}\n\nexport function isIExtensionIdentifier(thing: any): thing is IExtensionIdentifier {\n\treturn thing\n\t\t&& typeof thing === 'object'\n\t\t&& typeof thing.id === 'string'\n\t\t&& (!thing.uuid || typeof thing.uuid === 'string');\n}\n\nexport interface IExtensionIdentifier {\n\tid: string;\n\tuuid?: string;\n}\n\nexport interface IGalleryExtensionIdentifier extends IExtensionIdentifier {\n\tuuid: string;\n}\n\nexport interface IGalleryExtensionVersion {\n\tversion: string;\n\tdate: string;\n\tisPreReleaseVersion: boolean;\n}\n\nexport interface IGalleryExtension {\n\tname: string;\n\tidentifier: IGalleryExtensionIdentifier;\n\tversion: string;\n\tdisplayName: string;\n\tpublisherId: string;\n\tpublisher: string;\n\tpublisherDisplayName: string;\n\tpublisherDomain?: { link: string; verified: boolean };\n\tpublisherSponsorLink?: string;\n\tdescription: string;\n\tinstallCount: number;\n\trating: number;\n\tratingCount: number;\n\tcategories: readonly string[];\n\ttags: readonly string[];\n\treleaseDate: number;\n\tlastUpdated: number;\n\tpreview: boolean;\n\thasPreReleaseVersion: boolean;\n\thasReleaseVersion: boolean;\n\tisSigned: boolean;\n\tallTargetPlatforms: TargetPlatform[];\n\tassets: IGalleryExtensionAssets;\n\tproperties: IGalleryExtensionProperties;\n\ttelemetryData?: any;\n\tqueryContext?: IStringDictionary;\n\tsupportLink?: string;\n}\n\nexport interface IGalleryMetadata {\n\tid: string;\n\tpublisherId: string;\n\tpublisherDisplayName: string;\n\tisPreReleaseVersion: boolean;\n\ttargetPlatform?: TargetPlatform;\n}\n\nexport type Metadata = Partial;\n\nexport interface ILocalExtension extends IExtension {\n\tisMachineScoped: boolean;\n\tisApplicationScoped: boolean;\n\tpublisherId: string | null;\n\tpublisherDisplayName: string | null;\n\tinstalledTimestamp?: number;\n\tisPreReleaseVersion: boolean;\n\thasPreReleaseVersion: boolean;\n\tpreRelease: boolean;\n\tupdated: boolean;\n\tpinned: boolean;\n}\n\nexport const enum SortBy {\n\tNoneOrRelevance = 0,\n\tLastUpdatedDate = 1,\n\tTitle = 2,\n\tPublisherName = 3,\n\tInstallCount = 4,\n\tPublishedDate = 10,\n\tAverageRating = 6,\n\tWeightedRating = 12\n}\n\nexport const enum SortOrder {\n\tDefault = 0,\n\tAscending = 1,\n\tDescending = 2\n}\n\nexport interface IQueryOptions {\n\ttext?: string;\n\tids?: string[];\n\tnames?: string[];\n\tpageSize?: number;\n\tsortBy?: SortBy;\n\tsortOrder?: SortOrder;\n\tsource?: string;\n\tincludePreRelease?: boolean;\n}\n\nexport const enum StatisticType {\n\tInstall = 'install',\n\tUninstall = 'uninstall'\n}\n\nexport interface IDeprecationInfo {\n\treadonly disallowInstall?: boolean;\n\treadonly extension?: {\n\t\treadonly id: string;\n\t\treadonly displayName: string;\n\t\treadonly autoMigrate?: { readonly storage: boolean };\n\t\treadonly preRelease?: boolean;\n\t};\n\treadonly settings?: readonly string[];\n\treadonly additionalInfo?: string;\n}\n\nexport interface ISearchPrefferedResults {\n\treadonly query?: string;\n\treadonly preferredResults?: string[];\n}\n\nexport interface IExtensionsControlManifest {\n\treadonly malicious: IExtensionIdentifier[];\n\treadonly deprecated: IStringDictionary;\n\treadonly search: ISearchPrefferedResults[];\n}\n\nexport const enum InstallOperation {\n\tNone = 1,\n\tInstall,\n\tUpdate,\n\tMigrate,\n}\n\nexport interface ITranslation {\n\tcontents: { [key: string]: {} };\n}\n\nexport interface IExtensionInfo extends IExtensionIdentifier {\n\tversion?: string;\n\tpreRelease?: boolean;\n\thasPreRelease?: boolean;\n}\n\nexport interface IExtensionQueryOptions {\n\ttargetPlatform?: TargetPlatform;\n\tcompatible?: boolean;\n\tqueryAllVersions?: boolean;\n\tsource?: string;\n}\n\nexport const IExtensionGalleryService = createDecorator('extensionGalleryService');\n\n/**\n * Service to interact with the Visual Studio Code Marketplace to get extensions.\n * @throws Error if the Marketplace is not enabled or not reachable.\n */\nexport interface IExtensionGalleryService {\n\treadonly _serviceBrand: undefined;\n\tisEnabled(): boolean;\n\tquery(options: IQueryOptions, token: CancellationToken): Promise>;\n\tgetExtensions(extensionInfos: ReadonlyArray, token: CancellationToken): Promise;\n\tgetExtensions(extensionInfos: ReadonlyArray, options: IExtensionQueryOptions, token: CancellationToken): Promise;\n\tisExtensionCompatible(extension: IGalleryExtension, includePreRelease: boolean, targetPlatform: TargetPlatform): Promise;\n\tgetCompatibleExtension(extension: IGalleryExtension, includePreRelease: boolean, targetPlatform: TargetPlatform): Promise;\n\tgetAllCompatibleVersions(extension: IGalleryExtension, includePreRelease: boolean, targetPlatform: TargetPlatform): Promise;\n\tdownload(extension: IGalleryExtension, location: URI, operation: InstallOperation): Promise;\n\tdownloadSignatureArchive(extension: IGalleryExtension, location: URI): Promise;\n\treportStatistic(publisher: string, name: string, version: string, type: StatisticType): Promise;\n\tgetReadme(extension: IGalleryExtension, token: CancellationToken): Promise;\n\tgetManifest(extension: IGalleryExtension, token: CancellationToken): Promise;\n\tgetChangelog(extension: IGalleryExtension, token: CancellationToken): Promise;\n\tgetCoreTranslation(extension: IGalleryExtension, languageId: string): Promise;\n\tgetExtensionsControlManifest(): Promise;\n}\n\nexport interface InstallExtensionEvent {\n\treadonly identifier: IExtensionIdentifier;\n\treadonly source: URI | IGalleryExtension;\n\treadonly profileLocation?: URI;\n\treadonly applicationScoped?: boolean;\n}\n\nexport interface InstallExtensionResult {\n\treadonly identifier: IExtensionIdentifier;\n\treadonly operation: InstallOperation;\n\treadonly source?: URI | IGalleryExtension;\n\treadonly local?: ILocalExtension;\n\treadonly error?: Error;\n\treadonly context?: IStringDictionary;\n\treadonly profileLocation?: URI;\n\treadonly applicationScoped?: boolean;\n}\n\nexport interface UninstallExtensionEvent {\n\treadonly identifier: IExtensionIdentifier;\n\treadonly profileLocation?: URI;\n\treadonly applicationScoped?: boolean;\n}\n\nexport interface DidUninstallExtensionEvent {\n\treadonly identifier: IExtensionIdentifier;\n\treadonly error?: string;\n\treadonly profileLocation?: URI;\n\treadonly applicationScoped?: boolean;\n}\n\nexport enum ExtensionManagementErrorCode {\n\tUnsupported = 'Unsupported',\n\tDeprecated = 'Deprecated',\n\tMalicious = 'Malicious',\n\tIncompatible = 'Incompatible',\n\tIncompatibleTargetPlatform = 'IncompatibleTargetPlatform',\n\tReleaseVersionNotFound = 'ReleaseVersionNotFound',\n\tInvalid = 'Invalid',\n\tDownload = 'Download',\n\tDownloadSignature = 'DownloadSignature',\n\tUpdateMetadata = 'UpdateMetadata',\n\tExtract = 'Extract',\n\tScanning = 'Scanning',\n\tDelete = 'Delete',\n\tRename = 'Rename',\n\tCorruptZip = 'CorruptZip',\n\tIncompleteZip = 'IncompleteZip',\n\tSignature = 'Signature',\n\tNotAllowed = 'NotAllowed',\n\tGallery = 'Gallery',\n\tUnknown = 'Unknown',\n\tInternal = 'Internal',\n}\n\nexport enum ExtensionSignaturetErrorCode {\n\tUnknownError = 'UnknownError',\n\tPackageIsInvalidZip = 'PackageIsInvalidZip',\n\tSignatureArchiveIsInvalidZip = 'SignatureArchiveIsInvalidZip',\n}\n\nexport class ExtensionManagementError extends Error {\n\tconstructor(message: string, readonly code: ExtensionManagementErrorCode) {\n\t\tsuper(message);\n\t\tthis.name = code;\n\t}\n}\n\nexport enum ExtensionGalleryErrorCode {\n\tTimeout = 'Timeout',\n\tCancelled = 'Cancelled',\n\tFailed = 'Failed'\n}\n\nexport class ExtensionGalleryError extends Error {\n\tconstructor(message: string, readonly code: ExtensionGalleryErrorCode) {\n\t\tsuper(message);\n\t\tthis.name = code;\n\t}\n}\n\nexport type InstallOptions = {\n\tisBuiltin?: boolean;\n\tisMachineScoped?: boolean;\n\tisApplicationScoped?: boolean;\n\tpinned?: boolean;\n\tdonotIncludePackAndDependencies?: boolean;\n\tinstallGivenVersion?: boolean;\n\tpreRelease?: boolean;\n\tinstallPreReleaseVersion?: boolean;\n\tdonotVerifySignature?: boolean;\n\toperation?: InstallOperation;\n\tprofileLocation?: URI;\n\t/**\n\t * Context passed through to InstallExtensionResult\n\t */\n\tcontext?: IStringDictionary;\n};\nexport type InstallVSIXOptions = InstallOptions & { installOnlyNewlyAddedFromExtensionPack?: boolean };\nexport type UninstallOptions = { readonly donotIncludePack?: boolean; readonly donotCheckDependents?: boolean; readonly versionOnly?: boolean; readonly remove?: boolean; readonly profileLocation?: URI };\n\nexport interface IExtensionManagementParticipant {\n\tpostInstall(local: ILocalExtension, source: URI | IGalleryExtension, options: InstallOptions | InstallVSIXOptions, token: CancellationToken): Promise;\n\tpostUninstall(local: ILocalExtension, options: UninstallOptions, token: CancellationToken): Promise;\n}\n\nexport type InstallExtensionInfo = { readonly extension: IGalleryExtension; readonly options: InstallOptions };\n\nexport const IExtensionManagementService = createDecorator('extensionManagementService');\nexport interface IExtensionManagementService {\n\treadonly _serviceBrand: undefined;\n\n\tonInstallExtension: Event;\n\tonDidInstallExtensions: Event;\n\tonUninstallExtension: Event;\n\tonDidUninstallExtension: Event;\n\tonDidUpdateExtensionMetadata: Event;\n\n\tzip(extension: ILocalExtension): Promise;\n\tunzip(zipLocation: URI): Promise;\n\tgetManifest(vsix: URI): Promise;\n\tinstall(vsix: URI, options?: InstallVSIXOptions): Promise;\n\tcanInstall(extension: IGalleryExtension): Promise;\n\tinstallFromGallery(extension: IGalleryExtension, options?: InstallOptions): Promise;\n\tinstallGalleryExtensions(extensions: InstallExtensionInfo[]): Promise;\n\tinstallFromLocation(location: URI, profileLocation: URI): Promise;\n\tinstallExtensionsFromProfile(extensions: IExtensionIdentifier[], fromProfileLocation: URI, toProfileLocation: URI): Promise;\n\tuninstall(extension: ILocalExtension, options?: UninstallOptions): Promise;\n\ttoggleAppliationScope(extension: ILocalExtension, fromProfileLocation: URI): Promise;\n\treinstallFromGallery(extension: ILocalExtension): Promise;\n\tgetInstalled(type?: ExtensionType, profileLocation?: URI): Promise;\n\tgetExtensionsControlManifest(): Promise;\n\tcopyExtensions(fromProfileLocation: URI, toProfileLocation: URI): Promise;\n\tupdateMetadata(local: ILocalExtension, metadata: Partial, profileLocation?: URI): Promise;\n\n\tdownload(extension: IGalleryExtension, operation: InstallOperation, donotVerifySignature: boolean): Promise;\n\n\tregisterParticipant(pariticipant: IExtensionManagementParticipant): void;\n\tgetTargetPlatform(): Promise;\n\n\tcleanUp(): Promise;\n}\n\nexport const DISABLED_EXTENSIONS_STORAGE_PATH = 'extensionsIdentifiers/disabled';\nexport const ENABLED_EXTENSIONS_STORAGE_PATH = 'extensionsIdentifiers/enabled';\nexport const IGlobalExtensionEnablementService = createDecorator('IGlobalExtensionEnablementService');\n\nexport interface IGlobalExtensionEnablementService {\n\treadonly _serviceBrand: undefined;\n\treadonly onDidChangeEnablement: Event<{ readonly extensions: IExtensionIdentifier[]; readonly source?: string }>;\n\n\tgetDisabledExtensions(): IExtensionIdentifier[];\n\tenableExtension(extension: IExtensionIdentifier, source?: string): Promise;\n\tdisableExtension(extension: IExtensionIdentifier, source?: string): Promise;\n\n}\n\nexport type IConfigBasedExtensionTip = {\n\treadonly extensionId: string;\n\treadonly extensionName: string;\n\treadonly isExtensionPack: boolean;\n\treadonly configName: string;\n\treadonly important: boolean;\n\treadonly whenNotInstalled?: string[];\n};\n\nexport type IExecutableBasedExtensionTip = {\n\treadonly extensionId: string;\n\treadonly extensionName: string;\n\treadonly isExtensionPack: boolean;\n\treadonly exeName: string;\n\treadonly exeFriendlyName: string;\n\treadonly windowsPath?: string;\n\treadonly whenNotInstalled?: string[];\n};\n\nexport const IExtensionTipsService = createDecorator('IExtensionTipsService');\nexport interface IExtensionTipsService {\n\treadonly _serviceBrand: undefined;\n\n\tgetConfigBasedTips(folder: URI): Promise;\n\tgetImportantExecutableBasedTips(): Promise;\n\tgetOtherExecutableBasedTips(): Promise;\n}\n\nexport const ExtensionsLocalizedLabel = localize2('extensions', \"Extensions\");\nexport const PreferencesLocalizedLabel = localize2('preferences', 'Preferences');\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { cloneAndChange } from 'vs/base/common/objects';\nimport { URI, UriComponents } from 'vs/base/common/uri';\nimport { DefaultURITransformer, IURITransformer, transformAndReviveIncomingURIs } from 'vs/base/common/uriIpc';\nimport { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';\nimport { IExtensionIdentifier, IExtensionTipsService, IGalleryExtension, ILocalExtension, IExtensionsControlManifest, isTargetPlatformCompatible, InstallOptions, InstallVSIXOptions, UninstallOptions, Metadata, IExtensionManagementService, DidUninstallExtensionEvent, InstallExtensionEvent, InstallExtensionResult, UninstallExtensionEvent, InstallOperation, InstallExtensionInfo } from 'vs/platform/extensionManagement/common/extensionManagement';\nimport { ExtensionType, IExtensionManifest, TargetPlatform } from 'vs/platform/extensions/common/extensions';\n\nfunction transformIncomingURI(uri: UriComponents, transformer: IURITransformer | null): URI;\nfunction transformIncomingURI(uri: UriComponents | undefined, transformer: IURITransformer | null): URI | undefined;\nfunction transformIncomingURI(uri: UriComponents | undefined, transformer: IURITransformer | null): URI | undefined {\n\treturn uri ? URI.revive(transformer ? transformer.transformIncoming(uri) : uri) : undefined;\n}\n\nfunction transformOutgoingURI(uri: URI, transformer: IURITransformer | null): URI {\n\treturn transformer ? transformer.transformOutgoingURI(uri) : uri;\n}\n\nfunction transformIncomingExtension(extension: ILocalExtension, transformer: IURITransformer | null): ILocalExtension {\n\ttransformer = transformer ? transformer : DefaultURITransformer;\n\tconst manifest = extension.manifest;\n\tconst transformed = transformAndReviveIncomingURIs({ ...extension, ...{ manifest: undefined } }, transformer);\n\treturn { ...transformed, ...{ manifest } };\n}\n\nfunction transformIncomingOptions(options: O | undefined, transformer: IURITransformer | null): O | undefined {\n\treturn options?.profileLocation ? transformAndReviveIncomingURIs(options, transformer ?? DefaultURITransformer) : options;\n}\n\nfunction transformOutgoingExtension(extension: ILocalExtension, transformer: IURITransformer | null): ILocalExtension {\n\treturn transformer ? cloneAndChange(extension, value => value instanceof URI ? transformer.transformOutgoingURI(value) : undefined) : extension;\n}\n\nexport class ExtensionManagementChannel implements IServerChannel {\n\n\tonInstallExtension: Event;\n\tonDidInstallExtensions: Event;\n\tonUninstallExtension: Event;\n\tonDidUninstallExtension: Event;\n\tonDidUpdateExtensionMetadata: Event;\n\n\tconstructor(private service: IExtensionManagementService, private getUriTransformer: (requestContext: any) => IURITransformer | null) {\n\t\tthis.onInstallExtension = Event.buffer(service.onInstallExtension, true);\n\t\tthis.onDidInstallExtensions = Event.buffer(service.onDidInstallExtensions, true);\n\t\tthis.onUninstallExtension = Event.buffer(service.onUninstallExtension, true);\n\t\tthis.onDidUninstallExtension = Event.buffer(service.onDidUninstallExtension, true);\n\t\tthis.onDidUpdateExtensionMetadata = Event.buffer(service.onDidUpdateExtensionMetadata, true);\n\t}\n\n\tlisten(context: any, event: string): Event {\n\t\tconst uriTransformer = this.getUriTransformer(context);\n\t\tswitch (event) {\n\t\t\tcase 'onInstallExtension': {\n\t\t\t\treturn Event.map(this.onInstallExtension, e => {\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...e,\n\t\t\t\t\t\tprofileLocation: e.profileLocation ? transformOutgoingURI(e.profileLocation, uriTransformer) : e.profileLocation\n\t\t\t\t\t};\n\t\t\t\t});\n\t\t\t}\n\t\t\tcase 'onDidInstallExtensions': {\n\t\t\t\treturn Event.map(this.onDidInstallExtensions, results =>\n\t\t\t\t\tresults.map(i => ({\n\t\t\t\t\t\t...i,\n\t\t\t\t\t\tlocal: i.local ? transformOutgoingExtension(i.local, uriTransformer) : i.local,\n\t\t\t\t\t\tprofileLocation: i.profileLocation ? transformOutgoingURI(i.profileLocation, uriTransformer) : i.profileLocation\n\t\t\t\t\t})));\n\t\t\t}\n\t\t\tcase 'onUninstallExtension': {\n\t\t\t\treturn Event.map(this.onUninstallExtension, e => {\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...e,\n\t\t\t\t\t\tprofileLocation: e.profileLocation ? transformOutgoingURI(e.profileLocation, uriTransformer) : e.profileLocation\n\t\t\t\t\t};\n\t\t\t\t});\n\t\t\t}\n\t\t\tcase 'onDidUninstallExtension': {\n\t\t\t\treturn Event.map(this.onDidUninstallExtension, e => {\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...e,\n\t\t\t\t\t\tprofileLocation: e.profileLocation ? transformOutgoingURI(e.profileLocation, uriTransformer) : e.profileLocation\n\t\t\t\t\t};\n\t\t\t\t});\n\t\t\t}\n\t\t\tcase 'onDidUpdateExtensionMetadata': {\n\t\t\t\treturn Event.map(this.onDidUpdateExtensionMetadata, e => transformOutgoingExtension(e, uriTransformer));\n\t\t\t}\n\t\t}\n\n\t\tthrow new Error('Invalid listen');\n\t}\n\n\tasync call(context: any, command: string, args?: any): Promise {\n\t\tconst uriTransformer: IURITransformer | null = this.getUriTransformer(context);\n\t\tswitch (command) {\n\t\t\tcase 'zip': {\n\t\t\t\tconst extension = transformIncomingExtension(args[0], uriTransformer);\n\t\t\t\tconst uri = await this.service.zip(extension);\n\t\t\t\treturn transformOutgoingURI(uri, uriTransformer);\n\t\t\t}\n\t\t\tcase 'unzip': {\n\t\t\t\treturn this.service.unzip(transformIncomingURI(args[0], uriTransformer));\n\t\t\t}\n\t\t\tcase 'install': {\n\t\t\t\treturn this.service.install(transformIncomingURI(args[0], uriTransformer), transformIncomingOptions(args[1], uriTransformer));\n\t\t\t}\n\t\t\tcase 'installFromLocation': {\n\t\t\t\treturn this.service.installFromLocation(transformIncomingURI(args[0], uriTransformer), transformIncomingURI(args[1], uriTransformer));\n\t\t\t}\n\t\t\tcase 'installExtensionsFromProfile': {\n\t\t\t\treturn this.service.installExtensionsFromProfile(args[0], transformIncomingURI(args[1], uriTransformer), transformIncomingURI(args[2], uriTransformer));\n\t\t\t}\n\t\t\tcase 'getManifest': {\n\t\t\t\treturn this.service.getManifest(transformIncomingURI(args[0], uriTransformer));\n\t\t\t}\n\t\t\tcase 'getTargetPlatform': {\n\t\t\t\treturn this.service.getTargetPlatform();\n\t\t\t}\n\t\t\tcase 'canInstall': {\n\t\t\t\treturn this.service.canInstall(args[0]);\n\t\t\t}\n\t\t\tcase 'installFromGallery': {\n\t\t\t\treturn this.service.installFromGallery(args[0], transformIncomingOptions(args[1], uriTransformer));\n\t\t\t}\n\t\t\tcase 'installGalleryExtensions': {\n\t\t\t\tconst arg: InstallExtensionInfo[] = args[0];\n\t\t\t\treturn this.service.installGalleryExtensions(arg.map(({ extension, options }) => ({ extension, options: transformIncomingOptions(options, uriTransformer) ?? {} })));\n\t\t\t}\n\t\t\tcase 'uninstall': {\n\t\t\t\treturn this.service.uninstall(transformIncomingExtension(args[0], uriTransformer), transformIncomingOptions(args[1], uriTransformer));\n\t\t\t}\n\t\t\tcase 'reinstallFromGallery': {\n\t\t\t\treturn this.service.reinstallFromGallery(transformIncomingExtension(args[0], uriTransformer));\n\t\t\t}\n\t\t\tcase 'getInstalled': {\n\t\t\t\tconst extensions = await this.service.getInstalled(args[0], transformIncomingURI(args[1], uriTransformer));\n\t\t\t\treturn extensions.map(e => transformOutgoingExtension(e, uriTransformer));\n\t\t\t}\n\t\t\tcase 'toggleAppliationScope': {\n\t\t\t\tconst extension = await this.service.toggleAppliationScope(transformIncomingExtension(args[0], uriTransformer), transformIncomingURI(args[1], uriTransformer));\n\t\t\t\treturn transformOutgoingExtension(extension, uriTransformer);\n\t\t\t}\n\t\t\tcase 'copyExtensions': {\n\t\t\t\treturn this.service.copyExtensions(transformIncomingURI(args[0], uriTransformer), transformIncomingURI(args[1], uriTransformer));\n\t\t\t}\n\t\t\tcase 'updateMetadata': {\n\t\t\t\tconst e = await this.service.updateMetadata(transformIncomingExtension(args[0], uriTransformer), args[1], transformIncomingURI(args[2], uriTransformer));\n\t\t\t\treturn transformOutgoingExtension(e, uriTransformer);\n\t\t\t}\n\t\t\tcase 'getExtensionsControlManifest': {\n\t\t\t\treturn this.service.getExtensionsControlManifest();\n\t\t\t}\n\t\t\tcase 'download': {\n\t\t\t\treturn this.service.download(args[0], args[1], args[2]);\n\t\t\t}\n\t\t\tcase 'cleanUp': {\n\t\t\t\treturn this.service.cleanUp();\n\t\t\t}\n\t\t}\n\n\t\tthrow new Error('Invalid call');\n\t}\n}\n\nexport type ExtensionEventResult = InstallExtensionEvent | InstallExtensionResult | UninstallExtensionEvent | DidUninstallExtensionEvent;\n\nexport class ExtensionManagementChannelClient extends Disposable implements IExtensionManagementService {\n\n\tdeclare readonly _serviceBrand: undefined;\n\n\tprivate readonly _onInstallExtension = this._register(new Emitter());\n\tget onInstallExtension() { return this._onInstallExtension.event; }\n\n\tprivate readonly _onDidInstallExtensions = this._register(new Emitter());\n\tget onDidInstallExtensions() { return this._onDidInstallExtensions.event; }\n\n\tprivate readonly _onUninstallExtension = this._register(new Emitter());\n\tget onUninstallExtension() { return this._onUninstallExtension.event; }\n\n\tprivate readonly _onDidUninstallExtension = this._register(new Emitter());\n\tget onDidUninstallExtension() { return this._onDidUninstallExtension.event; }\n\n\tprivate readonly _onDidUpdateExtensionMetadata = this._register(new Emitter());\n\tget onDidUpdateExtensionMetadata() { return this._onDidUpdateExtensionMetadata.event; }\n\n\tconstructor(private readonly channel: IChannel) {\n\t\tsuper();\n\t\tthis._register(this.channel.listen('onInstallExtension')(e => this.fireEvent(this._onInstallExtension, { ...e, source: this.isUriComponents(e.source) ? URI.revive(e.source) : e.source, profileLocation: URI.revive(e.profileLocation) })));\n\t\tthis._register(this.channel.listen('onDidInstallExtensions')(results => this.fireEvent(this._onDidInstallExtensions, results.map(e => ({ ...e, local: e.local ? transformIncomingExtension(e.local, null) : e.local, source: this.isUriComponents(e.source) ? URI.revive(e.source) : e.source, profileLocation: URI.revive(e.profileLocation) })))));\n\t\tthis._register(this.channel.listen('onUninstallExtension')(e => this.fireEvent(this._onUninstallExtension, { ...e, profileLocation: URI.revive(e.profileLocation) })));\n\t\tthis._register(this.channel.listen('onDidUninstallExtension')(e => this.fireEvent(this._onDidUninstallExtension, { ...e, profileLocation: URI.revive(e.profileLocation) })));\n\t\tthis._register(this.channel.listen('onDidUpdateExtensionMetadata')(e => this._onDidUpdateExtensionMetadata.fire(transformIncomingExtension(e, null))));\n\t}\n\n\tprotected fireEvent(event: Emitter, data: InstallExtensionEvent): void;\n\tprotected fireEvent(event: Emitter, data: InstallExtensionResult[]): void;\n\tprotected fireEvent(event: Emitter, data: UninstallExtensionEvent): void;\n\tprotected fireEvent(event: Emitter, data: DidUninstallExtensionEvent): void;\n\tprotected fireEvent(event: Emitter, data: ExtensionEventResult): void;\n\tprotected fireEvent(event: Emitter, data: ExtensionEventResult[]): void;\n\tprotected fireEvent(event: Emitter, data: E): void {\n\t\tevent.fire(data);\n\t}\n\n\tprivate isUriComponents(thing: unknown): thing is UriComponents {\n\t\tif (!thing) {\n\t\t\treturn false;\n\t\t}\n\t\treturn typeof (thing).path === 'string' &&\n\t\t\ttypeof (thing).scheme === 'string';\n\t}\n\n\tprotected _targetPlatformPromise: Promise | undefined;\n\tgetTargetPlatform(): Promise {\n\t\tif (!this._targetPlatformPromise) {\n\t\t\tthis._targetPlatformPromise = this.channel.call('getTargetPlatform');\n\t\t}\n\t\treturn this._targetPlatformPromise;\n\t}\n\n\tasync canInstall(extension: IGalleryExtension): Promise {\n\t\tconst currentTargetPlatform = await this.getTargetPlatform();\n\t\treturn extension.allTargetPlatforms.some(targetPlatform => isTargetPlatformCompatible(targetPlatform, extension.allTargetPlatforms, currentTargetPlatform));\n\t}\n\n\tzip(extension: ILocalExtension): Promise {\n\t\treturn Promise.resolve(this.channel.call('zip', [extension]).then(result => URI.revive(result)));\n\t}\n\n\tunzip(zipLocation: URI): Promise {\n\t\treturn Promise.resolve(this.channel.call('unzip', [zipLocation]));\n\t}\n\n\tinstall(vsix: URI, options?: InstallVSIXOptions): Promise {\n\t\treturn Promise.resolve(this.channel.call('install', [vsix, options])).then(local => transformIncomingExtension(local, null));\n\t}\n\n\tinstallFromLocation(location: URI, profileLocation: URI): Promise {\n\t\treturn Promise.resolve(this.channel.call('installFromLocation', [location, profileLocation])).then(local => transformIncomingExtension(local, null));\n\t}\n\n\tasync installExtensionsFromProfile(extensions: IExtensionIdentifier[], fromProfileLocation: URI, toProfileLocation: URI): Promise {\n\t\tconst result = await this.channel.call('installExtensionsFromProfile', [extensions, fromProfileLocation, toProfileLocation]);\n\t\treturn result.map(local => transformIncomingExtension(local, null));\n\t}\n\n\tgetManifest(vsix: URI): Promise {\n\t\treturn Promise.resolve(this.channel.call('getManifest', [vsix]));\n\t}\n\n\tinstallFromGallery(extension: IGalleryExtension, installOptions?: InstallOptions): Promise {\n\t\treturn Promise.resolve(this.channel.call('installFromGallery', [extension, installOptions])).then(local => transformIncomingExtension(local, null));\n\t}\n\n\tasync installGalleryExtensions(extensions: InstallExtensionInfo[]): Promise {\n\t\tconst results = await this.channel.call('installGalleryExtensions', [extensions]);\n\t\treturn results.map(e => ({ ...e, local: e.local ? transformIncomingExtension(e.local, null) : e.local, source: this.isUriComponents(e.source) ? URI.revive(e.source) : e.source, profileLocation: URI.revive(e.profileLocation) }));\n\t}\n\n\tuninstall(extension: ILocalExtension, options?: UninstallOptions): Promise {\n\t\treturn Promise.resolve(this.channel.call('uninstall', [extension, options]));\n\t}\n\n\treinstallFromGallery(extension: ILocalExtension): Promise {\n\t\treturn Promise.resolve(this.channel.call('reinstallFromGallery', [extension])).then(local => transformIncomingExtension(local, null));\n\t}\n\n\tgetInstalled(type: ExtensionType | null = null, extensionsProfileResource?: URI): Promise {\n\t\treturn Promise.resolve(this.channel.call('getInstalled', [type, extensionsProfileResource]))\n\t\t\t.then(extensions => extensions.map(extension => transformIncomingExtension(extension, null)));\n\t}\n\n\tupdateMetadata(local: ILocalExtension, metadata: Partial, extensionsProfileResource?: URI): Promise {\n\t\treturn Promise.resolve(this.channel.call('updateMetadata', [local, metadata, extensionsProfileResource]))\n\t\t\t.then(extension => transformIncomingExtension(extension, null));\n\t}\n\n\ttoggleAppliationScope(local: ILocalExtension, fromProfileLocation: URI): Promise {\n\t\treturn this.channel.call('toggleAppliationScope', [local, fromProfileLocation])\n\t\t\t.then(extension => transformIncomingExtension(extension, null));\n\t}\n\n\tcopyExtensions(fromProfileLocation: URI, toProfileLocation: URI): Promise {\n\t\treturn this.channel.call('copyExtensions', [fromProfileLocation, toProfileLocation]);\n\t}\n\n\tgetExtensionsControlManifest(): Promise {\n\t\treturn Promise.resolve(this.channel.call('getExtensionsControlManifest'));\n\t}\n\n\tasync download(extension: IGalleryExtension, operation: InstallOperation, donotVerifySignature: boolean): Promise {\n\t\tconst result = await this.channel.call('download', [extension, operation, donotVerifySignature]);\n\t\treturn URI.revive(result);\n\t}\n\n\tasync cleanUp(): Promise {\n\t\treturn this.channel.call('cleanUp');\n\t}\n\n\tregisterParticipant() { throw new Error('Not Supported'); }\n}\n\nexport class ExtensionTipsChannel implements IServerChannel {\n\n\tconstructor(private service: IExtensionTipsService) {\n\t}\n\n\tlisten(context: any, event: string): Event {\n\t\tthrow new Error('Invalid listen');\n\t}\n\n\tcall(context: any, command: string, args?: any): Promise {\n\t\tswitch (command) {\n\t\t\tcase 'getConfigBasedTips': return this.service.getConfigBasedTips(URI.revive(args[0]));\n\t\t\tcase 'getImportantExecutableBasedTips': return this.service.getImportantExecutableBasedTips();\n\t\t\tcase 'getOtherExecutableBasedTips': return this.service.getOtherExecutableBasedTips();\n\t\t}\n\n\t\tthrow new Error('Invalid call');\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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';\n\nexport const enum RecommendationSource {\n\tFILE = 1,\n\tWORKSPACE = 2,\n\tEXE = 3\n}\n\nexport interface IExtensionRecommendations {\n\tsource: RecommendationSource;\n\textensions: string[];\n\tname: string;\n\tsearchValue?: string;\n}\n\nexport function RecommendationSourceToString(source: RecommendationSource) {\n\tswitch (source) {\n\t\tcase RecommendationSource.FILE: return 'file';\n\t\tcase RecommendationSource.WORKSPACE: return 'workspace';\n\t\tcase RecommendationSource.EXE: return 'exe';\n\t}\n}\n\nexport const enum RecommendationsNotificationResult {\n\tIgnored = 'ignored',\n\tCancelled = 'cancelled',\n\tTooMany = 'toomany',\n\tIncompatibleWindow = 'incompatibleWindow',\n\tAccepted = 'reacted',\n}\n\nexport const IExtensionRecommendationNotificationService = createDecorator('IExtensionRecommendationNotificationService');\n\nexport interface IExtensionRecommendationNotificationService {\n\treadonly _serviceBrand: undefined;\n\n\treadonly ignoredRecommendations: string[];\n\thasToIgnoreRecommendationNotifications(): boolean;\n\n\tpromptImportantExtensionsInstallNotification(recommendations: IExtensionRecommendations): Promise;\n\tpromptWorkspaceRecommendations(recommendations: string[]): Promise;\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 { createDecorator } from 'vs/platform/instantiation/common/instantiation';\nimport { ITerminalEnvironment } from 'vs/platform/terminal/common/terminal';\n\nexport const IExternalTerminalService = createDecorator('externalTerminal');\n\nexport interface IExternalTerminalSettings {\n\tlinuxExec?: string;\n\tosxExec?: string;\n\twindowsExec?: string;\n}\n\nexport interface ITerminalForPlatform {\n\twindows: string;\n\tlinux: string;\n\tosx: string;\n}\n\nexport interface IExternalTerminalService {\n\treadonly _serviceBrand: undefined;\n\topenTerminal(configuration: IExternalTerminalSettings, cwd: string | undefined): Promise;\n\trunInTerminal(title: string, cwd: string, args: string[], env: ITerminalEnvironment, settings: IExternalTerminalSettings): Promise;\n\tgetDefaultTerminalForPlatforms(): Promise;\n}\n\nexport interface IExternalTerminalConfiguration {\n\tterminal: {\n\t\texplorerKind: 'integrated' | 'external' | 'both';\n\t\texternal: IExternalTerminalSettings;\n\t};\n}\n\nexport const DEFAULT_TERMINAL_OSX = 'Terminal.app';\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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, VSBufferReadable, VSBufferReadableStream } from 'vs/base/common/buffer';\nimport { CancellationToken } from 'vs/base/common/cancellation';\nimport { Event } from 'vs/base/common/event';\nimport { IExpression, IRelativePattern } from 'vs/base/common/glob';\nimport { IDisposable } from 'vs/base/common/lifecycle';\nimport { TernarySearchTree } from 'vs/base/common/ternarySearchTree';\nimport { sep } from 'vs/base/common/path';\nimport { ReadableStreamEvents } from 'vs/base/common/stream';\nimport { startsWithIgnoreCase } from 'vs/base/common/strings';\nimport { isNumber } from 'vs/base/common/types';\nimport { URI } from 'vs/base/common/uri';\nimport { localize } from 'vs/nls';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\nimport { isWeb } from 'vs/base/common/platform';\nimport { Schemas } from 'vs/base/common/network';\nimport { IMarkdownString } from 'vs/base/common/htmlContent';\nimport { Lazy } from 'vs/base/common/lazy';\n\n//#region file service & providers\n\nexport const IFileService = createDecorator('fileService');\n\nexport interface IFileService {\n\n\treadonly _serviceBrand: undefined;\n\n\t/**\n\t * An event that is fired when a file system provider is added or removed\n\t */\n\treadonly onDidChangeFileSystemProviderRegistrations: Event;\n\n\t/**\n\t * An event that is fired when a registered file system provider changes its capabilities.\n\t */\n\treadonly onDidChangeFileSystemProviderCapabilities: Event;\n\n\t/**\n\t * An event that is fired when a file system provider is about to be activated. Listeners\n\t * can join this event with a long running promise to help in the activation process.\n\t */\n\treadonly onWillActivateFileSystemProvider: Event;\n\n\t/**\n\t * Registers a file system provider for a certain scheme.\n\t */\n\tregisterProvider(scheme: string, provider: IFileSystemProvider): IDisposable;\n\n\t/**\n\t * Returns a file system provider for a certain scheme.\n\t */\n\tgetProvider(scheme: string): IFileSystemProvider | undefined;\n\n\t/**\n\t * Tries to activate a provider with the given scheme.\n\t */\n\tactivateProvider(scheme: string): Promise;\n\n\t/**\n\t * Checks if this file service can handle the given resource by\n\t * first activating any extension that wants to be activated\n\t * on the provided resource scheme to include extensions that\n\t * contribute file system providers for the given resource.\n\t */\n\tcanHandleResource(resource: URI): Promise;\n\n\t/**\n\t * Checks if the file service has a registered provider for the\n\t * provided resource.\n\t *\n\t * Note: this does NOT account for contributed providers from\n\t * extensions that have not been activated yet. To include those,\n\t * consider to call `await fileService.canHandleResource(resource)`.\n\t */\n\thasProvider(resource: URI): boolean;\n\n\t/**\n\t * Checks if the provider for the provided resource has the provided file system capability.\n\t */\n\thasCapability(resource: URI, capability: FileSystemProviderCapabilities): boolean;\n\n\t/**\n\t * List the schemes and capabilities for registered file system providers\n\t */\n\tlistCapabilities(): Iterable<{ scheme: string; capabilities: FileSystemProviderCapabilities }>;\n\n\t/**\n\t * Allows to listen for file changes. The event will fire for every file within the opened workspace\n\t * (if any) as well as all files that have been watched explicitly using the #watch() API.\n\t */\n\treadonly onDidFilesChange: Event;\n\n\t/**\n\t * An event that is fired upon successful completion of a certain file operation.\n\t */\n\treadonly onDidRunOperation: Event;\n\n\t/**\n\t * Resolve the properties of a file/folder identified by the resource. For a folder, children\n\t * information is resolved as well depending on the provided options. Use `stat()` method if\n\t * you do not need children information.\n\t *\n\t * If the optional parameter \"resolveTo\" is specified in options, the stat service is asked\n\t * to provide a stat object that should contain the full graph of folders up to all of the\n\t * target resources.\n\t *\n\t * If the optional parameter \"resolveSingleChildDescendants\" is specified in options,\n\t * the stat service is asked to automatically resolve child folders that only\n\t * contain a single element.\n\t *\n\t * If the optional parameter \"resolveMetadata\" is specified in options,\n\t * the stat will contain metadata information such as size, mtime and etag.\n\t */\n\tresolve(resource: URI, options: IResolveMetadataFileOptions): Promise;\n\tresolve(resource: URI, options?: IResolveFileOptions): Promise;\n\n\t/**\n\t * Same as `resolve()` but supports resolving multiple resources in parallel.\n\t *\n\t * If one of the resolve targets fails to resolve returns a fake `IFileStat` instead of\n\t * making the whole call fail.\n\t */\n\tresolveAll(toResolve: { resource: URI; options: IResolveMetadataFileOptions }[]): Promise;\n\tresolveAll(toResolve: { resource: URI; options?: IResolveFileOptions }[]): Promise;\n\n\t/**\n\t * Same as `resolve()` but without resolving the children of a folder if the\n\t * resource is pointing to a folder.\n\t */\n\tstat(resource: URI): Promise;\n\n\t/**\n\t * Finds out if a file/folder identified by the resource exists.\n\t */\n\texists(resource: URI): Promise;\n\n\t/**\n\t * Read the contents of the provided resource unbuffered.\n\t */\n\treadFile(resource: URI, options?: IReadFileOptions, token?: CancellationToken): Promise;\n\n\t/**\n\t * Read the contents of the provided resource buffered as stream.\n\t */\n\treadFileStream(resource: URI, options?: IReadFileStreamOptions, token?: CancellationToken): Promise;\n\n\t/**\n\t * Updates the content replacing its previous value.\n\t *\n\t * Emits a `FileOperation.WRITE` file operation event when successful.\n\t */\n\twriteFile(resource: URI, bufferOrReadableOrStream: VSBuffer | VSBufferReadable | VSBufferReadableStream, options?: IWriteFileOptions): Promise;\n\n\t/**\n\t * Moves the file/folder to a new path identified by the resource.\n\t *\n\t * The optional parameter overwrite can be set to replace an existing file at the location.\n\t *\n\t * Emits a `FileOperation.MOVE` file operation event when successful.\n\t */\n\tmove(source: URI, target: URI, overwrite?: boolean): Promise;\n\n\t/**\n\t * Find out if a move operation is possible given the arguments. No changes on disk will\n\t * be performed. Returns an Error if the operation cannot be done.\n\t */\n\tcanMove(source: URI, target: URI, overwrite?: boolean): Promise;\n\n\t/**\n\t * Copies the file/folder to a path identified by the resource. A folder is copied\n\t * recursively.\n\t *\n\t * Emits a `FileOperation.COPY` file operation event when successful.\n\t */\n\tcopy(source: URI, target: URI, overwrite?: boolean): Promise;\n\n\t/**\n\t * Find out if a copy operation is possible given the arguments. No changes on disk will\n\t * be performed. Returns an Error if the operation cannot be done.\n\t */\n\tcanCopy(source: URI, target: URI, overwrite?: boolean): Promise;\n\n\t/**\n\t * Clones a file to a path identified by the resource. Folders are not supported.\n\t *\n\t * If the target path exists, it will be overwritten.\n\t */\n\tcloneFile(source: URI, target: URI): Promise;\n\n\t/**\n\t * Creates a new file with the given path and optional contents. The returned promise\n\t * will have the stat model object as a result.\n\t *\n\t * The optional parameter content can be used as value to fill into the new file.\n\t *\n\t * Emits a `FileOperation.CREATE` file operation event when successful.\n\t */\n\tcreateFile(resource: URI, bufferOrReadableOrStream?: VSBuffer | VSBufferReadable | VSBufferReadableStream, options?: ICreateFileOptions): Promise;\n\n\t/**\n\t * Find out if a file create operation is possible given the arguments. No changes on disk will\n\t * be performed. Returns an Error if the operation cannot be done.\n\t */\n\tcanCreateFile(resource: URI, options?: ICreateFileOptions): Promise;\n\n\t/**\n\t * Creates a new folder with the given path. The returned promise\n\t * will have the stat model object as a result.\n\t *\n\t * Emits a `FileOperation.CREATE` file operation event when successful.\n\t */\n\tcreateFolder(resource: URI): Promise;\n\n\t/**\n\t * Deletes the provided file. The optional useTrash parameter allows to\n\t * move the file to trash. The optional recursive parameter allows to delete\n\t * non-empty folders recursively.\n\t *\n\t * Emits a `FileOperation.DELETE` file operation event when successful.\n\t */\n\tdel(resource: URI, options?: Partial): Promise;\n\n\t/**\n\t * Find out if a delete operation is possible given the arguments. No changes on disk will\n\t * be performed. Returns an Error if the operation cannot be done.\n\t */\n\tcanDelete(resource: URI, options?: Partial): Promise;\n\n\t/**\n\t * An event that signals an error when watching for file changes.\n\t */\n\treadonly onDidWatchError: Event;\n\n\t/**\n\t * Allows to start a watcher that reports file/folder change events on the provided resource.\n\t *\n\t * The watcher runs correlated and thus, file events will be reported on the returned\n\t * `IFileSystemWatcher` and not on the generic `IFileService.onDidFilesChange` event.\n\t */\n\tcreateWatcher(resource: URI, options: IWatchOptionsWithoutCorrelation): IFileSystemWatcher;\n\n\t/**\n\t * Allows to start a watcher that reports file/folder change events on the provided resource.\n\t *\n\t * The watcher runs correlated and thus, file events will be reported on the returned\n\t * `IFileSystemWatcher` and not on the generic `IFileService.onDidFilesChange` event.\n\t */\n\twatch(resource: URI, options: IWatchOptionsWithCorrelation): IFileSystemWatcher;\n\n\t/**\n\t * Allows to start a watcher that reports file/folder change events on the provided resource.\n\t *\n\t * The watcher runs uncorrelated and thus will report all events from `IFileService.onDidFilesChange`.\n\t * This means, most listeners in the application will receive your events. It is encouraged to\n\t * use correlated watchers (via `IWatchOptionsWithCorrelation`) to limit events to your listener.\n\t*/\n\twatch(resource: URI, options?: IWatchOptionsWithoutCorrelation): IDisposable;\n\n\t/**\n\t * Frees up any resources occupied by this service.\n\t */\n\tdispose(): void;\n}\n\nexport interface IFileOverwriteOptions {\n\n\t/**\n\t * Set to `true` to overwrite a file if it exists. Will\n\t * throw an error otherwise if the file does exist.\n\t */\n\treadonly overwrite: boolean;\n}\n\nexport interface IFileUnlockOptions {\n\n\t/**\n\t * Set to `true` to try to remove any write locks the file might\n\t * have. A file that is write locked will throw an error for any\n\t * attempt to write to unless `unlock: true` is provided.\n\t */\n\treadonly unlock: boolean;\n}\n\nexport interface IFileAtomicReadOptions {\n\n\t/**\n\t * The optional `atomic` flag can be used to make sure\n\t * the `readFile` method is not running in parallel with\n\t * any `write` operations in the same process.\n\t *\n\t * Typically you should not need to use this flag but if\n\t * for example you are quickly reading a file right after\n\t * a file event occurred and the file changes a lot, there\n\t * is a chance that a read returns an empty or partial file\n\t * because a pending write has not finished yet.\n\t *\n\t * Note: this does not prevent the file from being written\n\t * to from a different process. If you need such atomic\n\t * operations, you better use a real database as storage.\n\t */\n\treadonly atomic: boolean;\n}\n\nexport interface IFileAtomicOptions {\n\n\t/**\n\t * The postfix is used to create a temporary file based\n\t * on the original resource. The resulting temporary\n\t * file will be in the same folder as the resource and\n\t * have `postfix` appended to the resource name.\n\t *\n\t * Example: given a file resource `file:///some/path/foo.txt`\n\t * and a postfix `.vsctmp`, the temporary file will be\n\t * created as `file:///some/path/foo.txt.vsctmp`.\n\t */\n\treadonly postfix: string;\n}\n\nexport interface IFileAtomicWriteOptions {\n\n\t/**\n\t * The optional `atomic` flag can be used to make sure\n\t * the `writeFile` method updates the target file atomically\n\t * by first writing to a temporary file in the same folder\n\t * and then renaming it over the target.\n\t */\n\treadonly atomic: IFileAtomicOptions | false;\n}\n\nexport interface IFileAtomicDeleteOptions {\n\n\t/**\n\t * The optional `atomic` flag can be used to make sure\n\t * the `delete` method deletes the target atomically by\n\t * first renaming it to a temporary resource in the same\n\t * folder and then deleting it.\n\t */\n\treadonly atomic: IFileAtomicOptions | false;\n}\n\nexport interface IFileReadLimits {\n\n\t/**\n\t * If the file exceeds the given size, an error of kind\n\t * `FILE_TOO_LARGE` will be thrown.\n\t */\n\tsize?: number;\n}\n\nexport interface IFileReadStreamOptions {\n\n\t/**\n\t * Is an integer specifying where to begin reading from in the file. If position is undefined,\n\t * data will be read from the current file position.\n\t */\n\treadonly position?: number;\n\n\t/**\n\t * Is an integer specifying how many bytes to read from the file. By default, all bytes\n\t * will be read.\n\t */\n\treadonly length?: number;\n\n\t/**\n\t * If provided, the size of the file will be checked against the limits\n\t * and an error will be thrown if any limit is exceeded.\n\t */\n\treadonly limits?: IFileReadLimits;\n}\n\nexport interface IFileWriteOptions extends IFileOverwriteOptions, IFileUnlockOptions, IFileAtomicWriteOptions {\n\n\t/**\n\t * Set to `true` to create a file when it does not exist. Will\n\t * throw an error otherwise if the file does not exist.\n\t */\n\treadonly create: boolean;\n}\n\nexport type IFileOpenOptions = IFileOpenForReadOptions | IFileOpenForWriteOptions;\n\nexport function isFileOpenForWriteOptions(options: IFileOpenOptions): options is IFileOpenForWriteOptions {\n\treturn options.create === true;\n}\n\nexport interface IFileOpenForReadOptions {\n\n\t/**\n\t * A hint that the file should be opened for reading only.\n\t */\n\treadonly create: false;\n}\n\nexport interface IFileOpenForWriteOptions extends IFileUnlockOptions {\n\n\t/**\n\t * A hint that the file should be opened for reading and writing.\n\t */\n\treadonly create: true;\n}\n\nexport interface IFileDeleteOptions {\n\n\t/**\n\t * Set to `true` to recursively delete any children of the file. This\n\t * only applies to folders and can lead to an error unless provided\n\t * if the folder is not empty.\n\t */\n\treadonly recursive: boolean;\n\n\t/**\n\t * Set to `true` to attempt to move the file to trash\n\t * instead of deleting it permanently from disk.\n\t *\n\t * This option maybe not be supported on all providers.\n\t */\n\treadonly useTrash: boolean;\n\n\t/**\n\t * The optional `atomic` flag can be used to make sure\n\t * the `delete` method deletes the target atomically by\n\t * first renaming it to a temporary resource in the same\n\t * folder and then deleting it.\n\t *\n\t * This option maybe not be supported on all providers.\n\t */\n\treadonly atomic: IFileAtomicOptions | false;\n}\n\nexport enum FileType {\n\n\t/**\n\t * File is unknown (neither file, directory nor symbolic link).\n\t */\n\tUnknown = 0,\n\n\t/**\n\t * File is a normal file.\n\t */\n\tFile = 1,\n\n\t/**\n\t * File is a directory.\n\t */\n\tDirectory = 2,\n\n\t/**\n\t * File is a symbolic link.\n\t *\n\t * Note: even when the file is a symbolic link, you can test for\n\t * `FileType.File` and `FileType.Directory` to know the type of\n\t * the target the link points to.\n\t */\n\tSymbolicLink = 64\n}\n\nexport enum FilePermission {\n\n\t/**\n\t * File is readonly. Components like editors should not\n\t * offer to edit the contents.\n\t */\n\tReadonly = 1,\n\n\t/**\n\t * File is locked. Components like editors should offer\n\t * to edit the contents and ask the user upon saving to\n\t * remove the lock.\n\t */\n\tLocked = 2\n}\n\nexport interface IStat {\n\n\t/**\n\t * The file type.\n\t */\n\treadonly type: FileType;\n\n\t/**\n\t * The last modification date represented as millis from unix epoch.\n\t */\n\treadonly mtime: number;\n\n\t/**\n\t * The creation date represented as millis from unix epoch.\n\t */\n\treadonly ctime: number;\n\n\t/**\n\t * The size of the file in bytes.\n\t */\n\treadonly size: number;\n\n\t/**\n\t * The file permissions.\n\t */\n\treadonly permissions?: FilePermission;\n}\n\nexport interface IWatchOptionsWithoutCorrelation {\n\n\t/**\n\t * Set to `true` to watch for changes recursively in a folder\n\t * and all of its children.\n\t */\n\trecursive: boolean;\n\n\t/**\n\t * A set of glob patterns or paths to exclude from watching.\n\t * Paths can be relative or absolute and when relative are\n\t * resolved against the watched folder. Glob patterns are\n\t * always matched relative to the watched folder.\n\t */\n\texcludes: string[];\n\n\t/**\n\t * An optional set of glob patterns or paths to include for\n\t * watching. If not provided, all paths are considered for\n\t * events.\n\t * Paths can be relative or absolute and when relative are\n\t * resolved against the watched folder. Glob patterns are\n\t * always matched relative to the watched folder.\n\t */\n\tincludes?: Array;\n}\n\nexport interface IWatchOptions extends IWatchOptionsWithoutCorrelation {\n\n\t/**\n\t * If provided, file change events from the watcher that\n\t * are a result of this watch request will carry the same\n\t * id.\n\t */\n\treadonly correlationId?: number;\n}\n\nexport interface IWatchOptionsWithCorrelation extends IWatchOptions {\n\treadonly correlationId: number;\n}\n\nexport interface IFileSystemWatcher extends IDisposable {\n\n\t/**\n\t * An event which fires on file/folder change only for changes\n\t * that correlate to the watch request with matching correlation\n\t * identifier.\n\t */\n\treadonly onDidChange: Event;\n}\n\nexport function isFileSystemWatcher(thing: unknown): thing is IFileSystemWatcher {\n\tconst candidate = thing as IFileSystemWatcher | undefined;\n\n\treturn !!candidate && typeof candidate.onDidChange === 'function';\n}\n\nexport const enum FileSystemProviderCapabilities {\n\n\t/**\n\t * No capabilities.\n\t */\n\tNone = 0,\n\n\t/**\n\t * Provider supports unbuffered read/write.\n\t */\n\tFileReadWrite = 1 << 1,\n\n\t/**\n\t * Provider supports open/read/write/close low level file operations.\n\t */\n\tFileOpenReadWriteClose = 1 << 2,\n\n\t/**\n\t * Provider supports stream based reading.\n\t */\n\tFileReadStream = 1 << 4,\n\n\t/**\n\t * Provider supports copy operation.\n\t */\n\tFileFolderCopy = 1 << 3,\n\n\t/**\n\t * Provider is path case sensitive.\n\t */\n\tPathCaseSensitive = 1 << 10,\n\n\t/**\n\t * All files of the provider are readonly.\n\t */\n\tReadonly = 1 << 11,\n\n\t/**\n\t * Provider supports to delete via trash.\n\t */\n\tTrash = 1 << 12,\n\n\t/**\n\t * Provider support to unlock files for writing.\n\t */\n\tFileWriteUnlock = 1 << 13,\n\n\t/**\n\t * Provider support to read files atomically. This implies the\n\t * provider provides the `FileReadWrite` capability too.\n\t */\n\tFileAtomicRead = 1 << 14,\n\n\t/**\n\t * Provider support to write files atomically. This implies the\n\t * provider provides the `FileReadWrite` capability too.\n\t */\n\tFileAtomicWrite = 1 << 15,\n\n\t/**\n\t * Provider support to delete atomically.\n\t */\n\tFileAtomicDelete = 1 << 16,\n\n\t/**\n\t * Provider support to clone files atomically.\n\t */\n\tFileClone = 1 << 17\n}\n\nexport interface IFileSystemProvider {\n\n\treadonly capabilities: FileSystemProviderCapabilities;\n\treadonly onDidChangeCapabilities: Event;\n\n\treadonly onDidChangeFile: Event;\n\treadonly onDidWatchError?: Event;\n\twatch(resource: URI, opts: IWatchOptions): IDisposable;\n\n\tstat(resource: URI): Promise;\n\tmkdir(resource: URI): Promise;\n\treaddir(resource: URI): Promise<[string, FileType][]>;\n\tdelete(resource: URI, opts: IFileDeleteOptions): Promise;\n\n\trename(from: URI, to: URI, opts: IFileOverwriteOptions): Promise;\n\tcopy?(from: URI, to: URI, opts: IFileOverwriteOptions): Promise;\n\n\treadFile?(resource: URI): Promise;\n\twriteFile?(resource: URI, content: Uint8Array, opts: IFileWriteOptions): Promise;\n\n\treadFileStream?(resource: URI, opts: IFileReadStreamOptions, token: CancellationToken): ReadableStreamEvents;\n\n\topen?(resource: URI, opts: IFileOpenOptions): Promise;\n\tclose?(fd: number): Promise;\n\tread?(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise;\n\twrite?(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise;\n\n\tcloneFile?(from: URI, to: URI): Promise;\n}\n\nexport interface IFileSystemProviderWithFileReadWriteCapability extends IFileSystemProvider {\n\treadFile(resource: URI): Promise;\n\twriteFile(resource: URI, content: Uint8Array, opts: IFileWriteOptions): Promise;\n}\n\nexport function hasReadWriteCapability(provider: IFileSystemProvider): provider is IFileSystemProviderWithFileReadWriteCapability {\n\treturn !!(provider.capabilities & FileSystemProviderCapabilities.FileReadWrite);\n}\n\nexport interface IFileSystemProviderWithFileFolderCopyCapability extends IFileSystemProvider {\n\tcopy(from: URI, to: URI, opts: IFileOverwriteOptions): Promise;\n}\n\nexport function hasFileFolderCopyCapability(provider: IFileSystemProvider): provider is IFileSystemProviderWithFileFolderCopyCapability {\n\treturn !!(provider.capabilities & FileSystemProviderCapabilities.FileFolderCopy);\n}\n\nexport interface IFileSystemProviderWithFileCloneCapability extends IFileSystemProvider {\n\tcloneFile(from: URI, to: URI): Promise;\n}\n\nexport function hasFileCloneCapability(provider: IFileSystemProvider): provider is IFileSystemProviderWithFileCloneCapability {\n\treturn !!(provider.capabilities & FileSystemProviderCapabilities.FileClone);\n}\n\nexport interface IFileSystemProviderWithOpenReadWriteCloseCapability extends IFileSystemProvider {\n\topen(resource: URI, opts: IFileOpenOptions): Promise;\n\tclose(fd: number): Promise;\n\tread(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise;\n\twrite(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise;\n}\n\nexport function hasOpenReadWriteCloseCapability(provider: IFileSystemProvider): provider is IFileSystemProviderWithOpenReadWriteCloseCapability {\n\treturn !!(provider.capabilities & FileSystemProviderCapabilities.FileOpenReadWriteClose);\n}\n\nexport interface IFileSystemProviderWithFileReadStreamCapability extends IFileSystemProvider {\n\treadFileStream(resource: URI, opts: IFileReadStreamOptions, token: CancellationToken): ReadableStreamEvents;\n}\n\nexport function hasFileReadStreamCapability(provider: IFileSystemProvider): provider is IFileSystemProviderWithFileReadStreamCapability {\n\treturn !!(provider.capabilities & FileSystemProviderCapabilities.FileReadStream);\n}\n\nexport interface IFileSystemProviderWithFileAtomicReadCapability extends IFileSystemProvider {\n\treadFile(resource: URI, opts?: IFileAtomicReadOptions): Promise;\n\tenforceAtomicReadFile?(resource: URI): boolean;\n}\n\nexport function hasFileAtomicReadCapability(provider: IFileSystemProvider): provider is IFileSystemProviderWithFileAtomicReadCapability {\n\tif (!hasReadWriteCapability(provider)) {\n\t\treturn false; // we require the `FileReadWrite` capability too\n\t}\n\n\treturn !!(provider.capabilities & FileSystemProviderCapabilities.FileAtomicRead);\n}\n\nexport interface IFileSystemProviderWithFileAtomicWriteCapability extends IFileSystemProvider {\n\twriteFile(resource: URI, contents: Uint8Array, opts?: IFileAtomicWriteOptions): Promise;\n\tenforceAtomicWriteFile?(resource: URI): IFileAtomicOptions | false;\n}\n\nexport function hasFileAtomicWriteCapability(provider: IFileSystemProvider): provider is IFileSystemProviderWithFileAtomicWriteCapability {\n\tif (!hasReadWriteCapability(provider)) {\n\t\treturn false; // we require the `FileReadWrite` capability too\n\t}\n\n\treturn !!(provider.capabilities & FileSystemProviderCapabilities.FileAtomicWrite);\n}\n\nexport interface IFileSystemProviderWithFileAtomicDeleteCapability extends IFileSystemProvider {\n\tdelete(resource: URI, opts: IFileAtomicDeleteOptions): Promise;\n\tenforceAtomicDelete?(resource: URI): IFileAtomicOptions | false;\n}\n\nexport function hasFileAtomicDeleteCapability(provider: IFileSystemProvider): provider is IFileSystemProviderWithFileAtomicDeleteCapability {\n\treturn !!(provider.capabilities & FileSystemProviderCapabilities.FileAtomicDelete);\n}\n\nexport interface IFileSystemProviderWithReadonlyCapability extends IFileSystemProvider {\n\n\treadonly capabilities: FileSystemProviderCapabilities.Readonly & FileSystemProviderCapabilities;\n\n\t/**\n\t * An optional message to show in the UI to explain why the file system is readonly.\n\t */\n\treadonly readOnlyMessage?: IMarkdownString;\n}\n\nexport function hasReadonlyCapability(provider: IFileSystemProvider): provider is IFileSystemProviderWithReadonlyCapability {\n\treturn !!(provider.capabilities & FileSystemProviderCapabilities.Readonly);\n}\n\nexport enum FileSystemProviderErrorCode {\n\tFileExists = 'EntryExists',\n\tFileNotFound = 'EntryNotFound',\n\tFileNotADirectory = 'EntryNotADirectory',\n\tFileIsADirectory = 'EntryIsADirectory',\n\tFileExceedsStorageQuota = 'EntryExceedsStorageQuota',\n\tFileTooLarge = 'EntryTooLarge',\n\tFileWriteLocked = 'EntryWriteLocked',\n\tNoPermissions = 'NoPermissions',\n\tUnavailable = 'Unavailable',\n\tUnknown = 'Unknown'\n}\n\nexport interface IFileSystemProviderError extends Error {\n\treadonly name: string;\n\treadonly code: FileSystemProviderErrorCode;\n}\n\nexport class FileSystemProviderError extends Error implements IFileSystemProviderError {\n\n\tstatic create(error: Error | string, code: FileSystemProviderErrorCode): FileSystemProviderError {\n\t\tconst providerError = new FileSystemProviderError(error.toString(), code);\n\t\tmarkAsFileSystemProviderError(providerError, code);\n\n\t\treturn providerError;\n\t}\n\n\tprivate constructor(message: string, readonly code: FileSystemProviderErrorCode) {\n\t\tsuper(message);\n\t}\n}\n\nexport function createFileSystemProviderError(error: Error | string, code: FileSystemProviderErrorCode): FileSystemProviderError {\n\treturn FileSystemProviderError.create(error, code);\n}\n\nexport function ensureFileSystemProviderError(error?: Error): Error {\n\tif (!error) {\n\t\treturn createFileSystemProviderError(localize('unknownError', \"Unknown Error\"), FileSystemProviderErrorCode.Unknown); // https://github.com/microsoft/vscode/issues/72798\n\t}\n\n\treturn error;\n}\n\nexport function markAsFileSystemProviderError(error: Error, code: FileSystemProviderErrorCode): Error {\n\terror.name = code ? `${code} (FileSystemError)` : `FileSystemError`;\n\n\treturn error;\n}\n\nexport function toFileSystemProviderErrorCode(error: Error | undefined | null): FileSystemProviderErrorCode {\n\n\t// Guard against abuse\n\tif (!error) {\n\t\treturn FileSystemProviderErrorCode.Unknown;\n\t}\n\n\t// FileSystemProviderError comes with the code\n\tif (error instanceof FileSystemProviderError) {\n\t\treturn error.code;\n\t}\n\n\t// Any other error, check for name match by assuming that the error\n\t// went through the markAsFileSystemProviderError() method\n\tconst match = /^(.+) \\(FileSystemError\\)$/.exec(error.name);\n\tif (!match) {\n\t\treturn FileSystemProviderErrorCode.Unknown;\n\t}\n\n\tswitch (match[1]) {\n\t\tcase FileSystemProviderErrorCode.FileExists: return FileSystemProviderErrorCode.FileExists;\n\t\tcase FileSystemProviderErrorCode.FileIsADirectory: return FileSystemProviderErrorCode.FileIsADirectory;\n\t\tcase FileSystemProviderErrorCode.FileNotADirectory: return FileSystemProviderErrorCode.FileNotADirectory;\n\t\tcase FileSystemProviderErrorCode.FileNotFound: return FileSystemProviderErrorCode.FileNotFound;\n\t\tcase FileSystemProviderErrorCode.FileTooLarge: return FileSystemProviderErrorCode.FileTooLarge;\n\t\tcase FileSystemProviderErrorCode.FileWriteLocked: return FileSystemProviderErrorCode.FileWriteLocked;\n\t\tcase FileSystemProviderErrorCode.NoPermissions: return FileSystemProviderErrorCode.NoPermissions;\n\t\tcase FileSystemProviderErrorCode.Unavailable: return FileSystemProviderErrorCode.Unavailable;\n\t}\n\n\treturn FileSystemProviderErrorCode.Unknown;\n}\n\nexport function toFileOperationResult(error: Error): FileOperationResult {\n\n\t// FileSystemProviderError comes with the result already\n\tif (error instanceof FileOperationError) {\n\t\treturn error.fileOperationResult;\n\t}\n\n\t// Otherwise try to find from code\n\tswitch (toFileSystemProviderErrorCode(error)) {\n\t\tcase FileSystemProviderErrorCode.FileNotFound:\n\t\t\treturn FileOperationResult.FILE_NOT_FOUND;\n\t\tcase FileSystemProviderErrorCode.FileIsADirectory:\n\t\t\treturn FileOperationResult.FILE_IS_DIRECTORY;\n\t\tcase FileSystemProviderErrorCode.FileNotADirectory:\n\t\t\treturn FileOperationResult.FILE_NOT_DIRECTORY;\n\t\tcase FileSystemProviderErrorCode.FileWriteLocked:\n\t\t\treturn FileOperationResult.FILE_WRITE_LOCKED;\n\t\tcase FileSystemProviderErrorCode.NoPermissions:\n\t\t\treturn FileOperationResult.FILE_PERMISSION_DENIED;\n\t\tcase FileSystemProviderErrorCode.FileExists:\n\t\t\treturn FileOperationResult.FILE_MOVE_CONFLICT;\n\t\tcase FileSystemProviderErrorCode.FileTooLarge:\n\t\t\treturn FileOperationResult.FILE_TOO_LARGE;\n\t\tdefault:\n\t\t\treturn FileOperationResult.FILE_OTHER_ERROR;\n\t}\n}\n\nexport interface IFileSystemProviderRegistrationEvent {\n\treadonly added: boolean;\n\treadonly scheme: string;\n\treadonly provider?: IFileSystemProvider;\n}\n\nexport interface IFileSystemProviderCapabilitiesChangeEvent {\n\treadonly provider: IFileSystemProvider;\n\treadonly scheme: string;\n}\n\nexport interface IFileSystemProviderActivationEvent {\n\treadonly scheme: string;\n\tjoin(promise: Promise): void;\n}\n\nexport const enum FileOperation {\n\tCREATE,\n\tDELETE,\n\tMOVE,\n\tCOPY,\n\tWRITE\n}\n\nexport interface IFileOperationEvent {\n\n\treadonly resource: URI;\n\treadonly operation: FileOperation;\n\n\tisOperation(operation: FileOperation.DELETE | FileOperation.WRITE): boolean;\n\tisOperation(operation: FileOperation.CREATE | FileOperation.MOVE | FileOperation.COPY): this is IFileOperationEventWithMetadata;\n}\n\nexport interface IFileOperationEventWithMetadata extends IFileOperationEvent {\n\treadonly target: IFileStatWithMetadata;\n}\n\nexport class FileOperationEvent implements IFileOperationEvent {\n\n\tconstructor(resource: URI, operation: FileOperation.DELETE | FileOperation.WRITE);\n\tconstructor(resource: URI, operation: FileOperation.CREATE | FileOperation.MOVE | FileOperation.COPY, target: IFileStatWithMetadata);\n\tconstructor(readonly resource: URI, readonly operation: FileOperation, readonly target?: IFileStatWithMetadata) { }\n\n\tisOperation(operation: FileOperation.DELETE | FileOperation.WRITE): boolean;\n\tisOperation(operation: FileOperation.CREATE | FileOperation.MOVE | FileOperation.COPY): this is IFileOperationEventWithMetadata;\n\tisOperation(operation: FileOperation): boolean {\n\t\treturn this.operation === operation;\n\t}\n}\n\n/**\n * Possible changes that can occur to a file.\n */\nexport const enum FileChangeType {\n\tUPDATED,\n\tADDED,\n\tDELETED\n}\n\n/**\n * Identifies a single change in a file.\n */\nexport interface IFileChange {\n\n\t/**\n\t * The type of change that occurred to the file.\n\t */\n\ttype: FileChangeType;\n\n\t/**\n\t * The unified resource identifier of the file that changed.\n\t */\n\treadonly resource: URI;\n\n\t/**\n\t * If provided when starting the file watcher, the correlation\n\t * identifier will match the original file watching request as\n\t * a way to identify the original component that is interested\n\t * in the change.\n\t */\n\treadonly cId?: number;\n}\n\nexport class FileChangesEvent {\n\n\tprivate static readonly MIXED_CORRELATION = null;\n\n\tprivate readonly correlationId: number | undefined | typeof FileChangesEvent.MIXED_CORRELATION = undefined;\n\n\tconstructor(changes: readonly IFileChange[], private readonly ignorePathCasing: boolean) {\n\t\tfor (const change of changes) {\n\n\t\t\t// Split by type\n\t\t\tswitch (change.type) {\n\t\t\t\tcase FileChangeType.ADDED:\n\t\t\t\t\tthis.rawAdded.push(change.resource);\n\t\t\t\t\tbreak;\n\t\t\t\tcase FileChangeType.UPDATED:\n\t\t\t\t\tthis.rawUpdated.push(change.resource);\n\t\t\t\t\tbreak;\n\t\t\t\tcase FileChangeType.DELETED:\n\t\t\t\t\tthis.rawDeleted.push(change.resource);\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// Figure out events correlation\n\t\t\tif (this.correlationId !== FileChangesEvent.MIXED_CORRELATION) {\n\t\t\t\tif (typeof change.cId === 'number') {\n\t\t\t\t\tif (this.correlationId === undefined) {\n\t\t\t\t\t\tthis.correlationId = change.cId; \t\t\t\t\t\t\t// correlation not yet set, just take it\n\t\t\t\t\t} else if (this.correlationId !== change.cId) {\n\t\t\t\t\t\tthis.correlationId = FileChangesEvent.MIXED_CORRELATION;\t// correlation mismatch, we have mixed correlation\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif (this.correlationId !== undefined) {\n\t\t\t\t\t\tthis.correlationId = FileChangesEvent.MIXED_CORRELATION;\t// correlation mismatch, we have mixed correlation\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate readonly added = new Lazy(() => {\n\t\tconst added = TernarySearchTree.forUris(() => this.ignorePathCasing);\n\t\tadded.fill(this.rawAdded.map(resource => [resource, true]));\n\n\t\treturn added;\n\t});\n\n\tprivate readonly updated = new Lazy(() => {\n\t\tconst updated = TernarySearchTree.forUris(() => this.ignorePathCasing);\n\t\tupdated.fill(this.rawUpdated.map(resource => [resource, true]));\n\n\t\treturn updated;\n\t});\n\n\tprivate readonly deleted = new Lazy(() => {\n\t\tconst deleted = TernarySearchTree.forUris(() => this.ignorePathCasing);\n\t\tdeleted.fill(this.rawDeleted.map(resource => [resource, true]));\n\n\t\treturn deleted;\n\t});\n\n\t/**\n\t * Find out if the file change events match the provided resource.\n\t *\n\t * Note: when passing `FileChangeType.DELETED`, we consider a match\n\t * also when the parent of the resource got deleted.\n\t */\n\tcontains(resource: URI, ...types: FileChangeType[]): boolean {\n\t\treturn this.doContains(resource, { includeChildren: false }, ...types);\n\t}\n\n\t/**\n\t * Find out if the file change events either match the provided\n\t * resource, or contain a child of this resource.\n\t */\n\taffects(resource: URI, ...types: FileChangeType[]): boolean {\n\t\treturn this.doContains(resource, { includeChildren: true }, ...types);\n\t}\n\n\tprivate doContains(resource: URI, options: { includeChildren: boolean }, ...types: FileChangeType[]): boolean {\n\t\tif (!resource) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst hasTypesFilter = types.length > 0;\n\n\t\t// Added\n\t\tif (!hasTypesFilter || types.includes(FileChangeType.ADDED)) {\n\t\t\tif (this.added.value.get(resource)) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tif (options.includeChildren && this.added.value.findSuperstr(resource)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\t// Updated\n\t\tif (!hasTypesFilter || types.includes(FileChangeType.UPDATED)) {\n\t\t\tif (this.updated.value.get(resource)) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tif (options.includeChildren && this.updated.value.findSuperstr(resource)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\t// Deleted\n\t\tif (!hasTypesFilter || types.includes(FileChangeType.DELETED)) {\n\t\t\tif (this.deleted.value.findSubstr(resource) /* deleted also considers parent folders */) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tif (options.includeChildren && this.deleted.value.findSuperstr(resource)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Returns if this event contains added files.\n\t */\n\tgotAdded(): boolean {\n\t\treturn this.rawAdded.length > 0;\n\t}\n\n\t/**\n\t * Returns if this event contains deleted files.\n\t */\n\tgotDeleted(): boolean {\n\t\treturn this.rawDeleted.length > 0;\n\t}\n\n\t/**\n\t * Returns if this event contains updated files.\n\t */\n\tgotUpdated(): boolean {\n\t\treturn this.rawUpdated.length > 0;\n\t}\n\n\t/**\n\t * Returns if this event contains changes that correlate to the\n\t * provided `correlationId`.\n\t *\n\t * File change event correlation is an advanced watch feature that\n\t * allows to identify from which watch request the events originate\n\t * from. This correlation allows to route events specifically\n\t * only to the requestor and not emit them to all listeners.\n\t */\n\tcorrelates(correlationId: number): boolean {\n\t\treturn this.correlationId === correlationId;\n\t}\n\n\t/**\n\t * Figure out if the event contains changes that correlate to one\n\t * correlation identifier.\n\t *\n\t * File change event correlation is an advanced watch feature that\n\t * allows to identify from which watch request the events originate\n\t * from. This correlation allows to route events specifically\n\t * only to the requestor and not emit them to all listeners.\n\t */\n\thasCorrelation(): boolean {\n\t\treturn typeof this.correlationId === 'number';\n\t}\n\n\t/**\n\t * @deprecated use the `contains` or `affects` method to efficiently find\n\t * out if the event relates to a given resource. these methods ensure:\n\t * - that there is no expensive lookup needed (by using a `TernarySearchTree`)\n\t * - correctly handles `FileChangeType.DELETED` events\n\t */\n\treadonly rawAdded: URI[] = [];\n\n\t/**\n\t* @deprecated use the `contains` or `affects` method to efficiently find\n\t* out if the event relates to a given resource. these methods ensure:\n\t* - that there is no expensive lookup needed (by using a `TernarySearchTree`)\n\t* - correctly handles `FileChangeType.DELETED` events\n\t*/\n\treadonly rawUpdated: URI[] = [];\n\n\t/**\n\t* @deprecated use the `contains` or `affects` method to efficiently find\n\t* out if the event relates to a given resource. these methods ensure:\n\t* - that there is no expensive lookup needed (by using a `TernarySearchTree`)\n\t* - correctly handles `FileChangeType.DELETED` events\n\t*/\n\treadonly rawDeleted: URI[] = [];\n}\n\nexport function isParent(path: string, candidate: string, ignoreCase?: boolean): boolean {\n\tif (!path || !candidate || path === candidate) {\n\t\treturn false;\n\t}\n\n\tif (candidate.length > path.length) {\n\t\treturn false;\n\t}\n\n\tif (candidate.charAt(candidate.length - 1) !== sep) {\n\t\tcandidate += sep;\n\t}\n\n\tif (ignoreCase) {\n\t\treturn startsWithIgnoreCase(path, candidate);\n\t}\n\n\treturn path.indexOf(candidate) === 0;\n}\n\nexport interface IBaseFileStat {\n\n\t/**\n\t * The unified resource identifier of this file or folder.\n\t */\n\treadonly resource: URI;\n\n\t/**\n\t * The name which is the last segment\n\t * of the {{path}}.\n\t */\n\treadonly name: string;\n\n\t/**\n\t * The size of the file.\n\t *\n\t * The value may or may not be resolved as\n\t * it is optional.\n\t */\n\treadonly size?: number;\n\n\t/**\n\t * The last modification date represented as millis from unix epoch.\n\t *\n\t * The value may or may not be resolved as\n\t * it is optional.\n\t */\n\treadonly mtime?: number;\n\n\t/**\n\t * The creation date represented as millis from unix epoch.\n\t *\n\t * The value may or may not be resolved as\n\t * it is optional.\n\t */\n\treadonly ctime?: number;\n\n\t/**\n\t * A unique identifier that represents the\n\t * current state of the file or directory.\n\t *\n\t * The value may or may not be resolved as\n\t * it is optional.\n\t */\n\treadonly etag?: string;\n\n\t/**\n\t * File is readonly. Components like editors should not\n\t * offer to edit the contents.\n\t */\n\treadonly readonly?: boolean;\n\n\t/**\n\t * File is locked. Components like editors should offer\n\t * to edit the contents and ask the user upon saving to\n\t * remove the lock.\n\t */\n\treadonly locked?: boolean;\n}\n\nexport interface IBaseFileStatWithMetadata extends Required { }\n\n/**\n * A file resource with meta information and resolved children if any.\n */\nexport interface IFileStat extends IBaseFileStat {\n\n\t/**\n\t * The resource is a file.\n\t */\n\treadonly isFile: boolean;\n\n\t/**\n\t * The resource is a directory.\n\t */\n\treadonly isDirectory: boolean;\n\n\t/**\n\t * The resource is a symbolic link. Note: even when the\n\t * file is a symbolic link, you can test for `FileType.File`\n\t * and `FileType.Directory` to know the type of the target\n\t * the link points to.\n\t */\n\treadonly isSymbolicLink: boolean;\n\n\t/**\n\t * The children of the file stat or undefined if none.\n\t */\n\tchildren: IFileStat[] | undefined;\n}\n\nexport interface IFileStatWithMetadata extends IFileStat, IBaseFileStatWithMetadata {\n\treadonly mtime: number;\n\treadonly ctime: number;\n\treadonly etag: string;\n\treadonly size: number;\n\treadonly readonly: boolean;\n\treadonly locked: boolean;\n\treadonly children: IFileStatWithMetadata[] | undefined;\n}\n\nexport interface IFileStatResult {\n\treadonly stat?: IFileStat;\n\treadonly success: boolean;\n}\n\nexport interface IFileStatResultWithMetadata extends IFileStatResult {\n\treadonly stat?: IFileStatWithMetadata;\n}\n\nexport interface IFileStatWithPartialMetadata extends Omit { }\n\nexport interface IFileContent extends IBaseFileStatWithMetadata {\n\n\t/**\n\t * The content of a file as buffer.\n\t */\n\treadonly value: VSBuffer;\n}\n\nexport interface IFileStreamContent extends IBaseFileStatWithMetadata {\n\n\t/**\n\t * The content of a file as stream.\n\t */\n\treadonly value: VSBufferReadableStream;\n}\n\nexport interface IBaseReadFileOptions extends IFileReadStreamOptions {\n\n\t/**\n\t * The optional etag parameter allows to return early from resolving the resource if\n\t * the contents on disk match the etag. This prevents accumulated reading of resources\n\t * that have been read already with the same etag.\n\t * It is the task of the caller to makes sure to handle this error case from the promise.\n\t */\n\treadonly etag?: string;\n}\n\nexport interface IReadFileStreamOptions extends IBaseReadFileOptions { }\n\nexport interface IReadFileOptions extends IBaseReadFileOptions {\n\n\t/**\n\t * The optional `atomic` flag can be used to make sure\n\t * the `readFile` method is not running in parallel with\n\t * any `write` operations in the same process.\n\t *\n\t * Typically you should not need to use this flag but if\n\t * for example you are quickly reading a file right after\n\t * a file event occurred and the file changes a lot, there\n\t * is a chance that a read returns an empty or partial file\n\t * because a pending write has not finished yet.\n\t *\n\t * Note: this does not prevent the file from being written\n\t * to from a different process. If you need such atomic\n\t * operations, you better use a real database as storage.\n\t */\n\treadonly atomic?: boolean;\n}\n\nexport interface IWriteFileOptions {\n\n\t/**\n\t * The last known modification time of the file. This can be used to prevent dirty writes.\n\t */\n\treadonly mtime?: number;\n\n\t/**\n\t * The etag of the file. This can be used to prevent dirty writes.\n\t */\n\treadonly etag?: string;\n\n\t/**\n\t * Whether to attempt to unlock a file before writing.\n\t */\n\treadonly unlock?: boolean;\n\n\t/**\n\t * The optional `atomic` flag can be used to make sure\n\t * the `writeFile` method updates the target file atomically\n\t * by first writing to a temporary file in the same folder\n\t * and then renaming it over the target.\n\t */\n\treadonly atomic?: IFileAtomicOptions | false;\n}\n\nexport interface IResolveFileOptions {\n\n\t/**\n\t * Automatically continue resolving children of a directory until the provided resources\n\t * are found.\n\t */\n\treadonly resolveTo?: readonly URI[];\n\n\t/**\n\t * Automatically continue resolving children of a directory if the number of children is 1.\n\t */\n\treadonly resolveSingleChildDescendants?: boolean;\n\n\t/**\n\t * Will resolve mtime, ctime, size and etag of files if enabled. This can have a negative impact\n\t * on performance and thus should only be used when these values are required.\n\t */\n\treadonly resolveMetadata?: boolean;\n}\n\nexport interface IResolveMetadataFileOptions extends IResolveFileOptions {\n\treadonly resolveMetadata: true;\n}\n\nexport interface ICreateFileOptions {\n\n\t/**\n\t * Overwrite the file to create if it already exists on disk. Otherwise\n\t * an error will be thrown (FILE_MODIFIED_SINCE).\n\t */\n\treadonly overwrite?: boolean;\n}\n\nexport class FileOperationError extends Error {\n\tconstructor(\n\t\tmessage: string,\n\t\treadonly fileOperationResult: FileOperationResult,\n\t\treadonly options?: IReadFileOptions | IWriteFileOptions | ICreateFileOptions\n\t) {\n\t\tsuper(message);\n\t}\n}\n\nexport class TooLargeFileOperationError extends FileOperationError {\n\tconstructor(\n\t\tmessage: string,\n\t\toverride readonly fileOperationResult: FileOperationResult.FILE_TOO_LARGE,\n\t\treadonly size: number,\n\t\toptions?: IReadFileOptions\n\t) {\n\t\tsuper(message, fileOperationResult, options);\n\t}\n}\n\nexport class NotModifiedSinceFileOperationError extends FileOperationError {\n\n\tconstructor(\n\t\tmessage: string,\n\t\treadonly stat: IFileStatWithMetadata,\n\t\toptions?: IReadFileOptions\n\t) {\n\t\tsuper(message, FileOperationResult.FILE_NOT_MODIFIED_SINCE, options);\n\t}\n}\n\nexport const enum FileOperationResult {\n\tFILE_IS_DIRECTORY,\n\tFILE_NOT_FOUND,\n\tFILE_NOT_MODIFIED_SINCE,\n\tFILE_MODIFIED_SINCE,\n\tFILE_MOVE_CONFLICT,\n\tFILE_WRITE_LOCKED,\n\tFILE_PERMISSION_DENIED,\n\tFILE_TOO_LARGE,\n\tFILE_INVALID_PATH,\n\tFILE_NOT_DIRECTORY,\n\tFILE_OTHER_ERROR\n}\n\n//#endregion\n\n//#region Settings\n\nexport const AutoSaveConfiguration = {\n\tOFF: 'off',\n\tAFTER_DELAY: 'afterDelay',\n\tON_FOCUS_CHANGE: 'onFocusChange',\n\tON_WINDOW_CHANGE: 'onWindowChange'\n};\n\nexport const HotExitConfiguration = {\n\tOFF: 'off',\n\tON_EXIT: 'onExit',\n\tON_EXIT_AND_WINDOW_CLOSE: 'onExitAndWindowClose'\n};\n\nexport const FILES_ASSOCIATIONS_CONFIG = 'files.associations';\nexport const FILES_EXCLUDE_CONFIG = 'files.exclude';\nexport const FILES_READONLY_INCLUDE_CONFIG = 'files.readonlyInclude';\nexport const FILES_READONLY_EXCLUDE_CONFIG = 'files.readonlyExclude';\nexport const FILES_READONLY_FROM_PERMISSIONS_CONFIG = 'files.readonlyFromPermissions';\n\nexport interface IGlobPatterns {\n\t[filepattern: string]: boolean;\n}\n\nexport interface IFilesConfiguration {\n\tfiles: IFilesConfigurationNode;\n}\n\nexport interface IFilesConfigurationNode {\n\tassociations: { [filepattern: string]: string };\n\texclude: IExpression;\n\twatcherExclude: IGlobPatterns;\n\twatcherInclude: string[];\n\tencoding: string;\n\tautoGuessEncoding: boolean;\n\tdefaultLanguage: string;\n\ttrimTrailingWhitespace: boolean;\n\tautoSave: string;\n\tautoSaveDelay: number;\n\tautoSaveWorkspaceFilesOnly: boolean;\n\tautoSaveWhenNoErrors: boolean;\n\teol: string;\n\tenableTrash: boolean;\n\thotExit: string;\n\tsaveConflictResolution: 'askUser' | 'overwriteFileOnDisk';\n\treadonlyInclude: IGlobPatterns;\n\treadonlyExclude: IGlobPatterns;\n\treadonlyFromPermissions: boolean;\n}\n\n//#endregion\n\n//#region Utilities\n\nexport enum FileKind {\n\tFILE,\n\tFOLDER,\n\tROOT_FOLDER\n}\n\n/**\n * A hint to disable etag checking for reading/writing.\n */\nexport const ETAG_DISABLED = '';\n\nexport function etag(stat: { mtime: number; size: number }): string;\nexport function etag(stat: { mtime: number | undefined; size: number | undefined }): string | undefined;\nexport function etag(stat: { mtime: number | undefined; size: number | undefined }): string | undefined {\n\tif (typeof stat.size !== 'number' || typeof stat.mtime !== 'number') {\n\t\treturn undefined;\n\t}\n\n\treturn stat.mtime.toString(29) + stat.size.toString(31);\n}\n\nexport async function whenProviderRegistered(file: URI, fileService: IFileService): Promise {\n\tif (fileService.hasProvider(URI.from({ scheme: file.scheme }))) {\n\t\treturn;\n\t}\n\n\treturn new Promise(resolve => {\n\t\tconst disposable = fileService.onDidChangeFileSystemProviderRegistrations(e => {\n\t\t\tif (e.scheme === file.scheme && e.added) {\n\t\t\t\tdisposable.dispose();\n\t\t\t\tresolve();\n\t\t\t}\n\t\t});\n\t});\n}\n\n/**\n * Helper to format a raw byte size into a human readable label.\n */\nexport class ByteSize {\n\n\tstatic readonly KB = 1024;\n\tstatic readonly MB = ByteSize.KB * ByteSize.KB;\n\tstatic readonly GB = ByteSize.MB * ByteSize.KB;\n\tstatic readonly TB = ByteSize.GB * ByteSize.KB;\n\n\tstatic formatSize(size: number): string {\n\t\tif (!isNumber(size)) {\n\t\t\tsize = 0;\n\t\t}\n\n\t\tif (size < ByteSize.KB) {\n\t\t\treturn localize('sizeB', \"{0}B\", size.toFixed(0));\n\t\t}\n\n\t\tif (size < ByteSize.MB) {\n\t\t\treturn localize('sizeKB', \"{0}KB\", (size / ByteSize.KB).toFixed(2));\n\t\t}\n\n\t\tif (size < ByteSize.GB) {\n\t\t\treturn localize('sizeMB', \"{0}MB\", (size / ByteSize.MB).toFixed(2));\n\t\t}\n\n\t\tif (size < ByteSize.TB) {\n\t\t\treturn localize('sizeGB', \"{0}GB\", (size / ByteSize.GB).toFixed(2));\n\t\t}\n\n\t\treturn localize('sizeTB', \"{0}TB\", (size / ByteSize.TB).toFixed(2));\n\t}\n}\n\n// File limits\n\nexport function getLargeFileConfirmationLimit(remoteAuthority?: string): number;\nexport function getLargeFileConfirmationLimit(uri?: URI): number;\nexport function getLargeFileConfirmationLimit(arg?: string | URI): number {\n\tconst isRemote = typeof arg === 'string' || arg?.scheme === Schemas.vscodeRemote;\n\tconst isLocal = typeof arg !== 'string' && arg?.scheme === Schemas.file;\n\n\tif (isLocal) {\n\t\t// Local almost has no limit in file size\n\t\treturn 1024 * ByteSize.MB;\n\t}\n\n\tif (isRemote) {\n\t\t// With a remote, pick a low limit to avoid\n\t\t// potentially costly file transfers\n\t\treturn 10 * ByteSize.MB;\n\t}\n\n\tif (isWeb) {\n\t\t// Web: we cannot know for sure if a cost\n\t\t// is associated with the file transfer\n\t\t// so we pick a reasonably small limit\n\t\treturn 50 * ByteSize.MB;\n\t}\n\n\t// Local desktop: almost no limit in file size\n\treturn 1024 * ByteSize.MB;\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 { localize } from 'vs/nls';\nimport { URI } from 'vs/base/common/uri';\nimport { VSBuffer } from 'vs/base/common/buffer';\nimport { CancellationToken } from 'vs/base/common/cancellation';\nimport { Event } from 'vs/base/common/event';\nimport { Disposable, IDisposable } from 'vs/base/common/lifecycle';\nimport { Schemas } from 'vs/base/common/network';\nimport { basename, extname, normalize } from 'vs/base/common/path';\nimport { isLinux } from 'vs/base/common/platform';\nimport { extUri, extUriIgnorePathCase } from 'vs/base/common/resources';\nimport { newWriteableStream, ReadableStreamEvents } from 'vs/base/common/stream';\nimport { createFileSystemProviderError, IFileDeleteOptions, IFileOverwriteOptions, IFileReadStreamOptions, FileSystemProviderCapabilities, FileSystemProviderError, FileSystemProviderErrorCode, FileType, IFileWriteOptions, IFileSystemProviderWithFileReadStreamCapability, IFileSystemProviderWithFileReadWriteCapability, IStat, IWatchOptions } from 'vs/platform/files/common/files';\nimport { WebFileSystemAccess } from 'vs/platform/files/browser/webFileSystemAccess';\nimport { IndexedDB } from 'vs/base/browser/indexedDB';\nimport { ILogService } from 'vs/platform/log/common/log';\n\nexport class HTMLFileSystemProvider implements IFileSystemProviderWithFileReadWriteCapability, IFileSystemProviderWithFileReadStreamCapability {\n\n\t//#region Events (unsupported)\n\n\treadonly onDidChangeCapabilities = Event.None;\n\treadonly onDidChangeFile = Event.None;\n\n\t//#endregion\n\n\t//#region File Capabilities\n\n\tprivate extUri = isLinux ? extUri : extUriIgnorePathCase;\n\n\tprivate _capabilities: FileSystemProviderCapabilities | undefined;\n\tget capabilities(): FileSystemProviderCapabilities {\n\t\tif (!this._capabilities) {\n\t\t\tthis._capabilities =\n\t\t\t\tFileSystemProviderCapabilities.FileReadWrite |\n\t\t\t\tFileSystemProviderCapabilities.FileReadStream;\n\n\t\t\tif (isLinux) {\n\t\t\t\tthis._capabilities |= FileSystemProviderCapabilities.PathCaseSensitive;\n\t\t\t}\n\t\t}\n\n\t\treturn this._capabilities;\n\t}\n\n\t//#endregion\n\n\n\tconstructor(\n\t\tprivate indexedDB: IndexedDB | undefined,\n\t\tprivate readonly store: string,\n\t\tprivate logService: ILogService\n\t) { }\n\n\t//#region File Metadata Resolving\n\n\tasync stat(resource: URI): Promise {\n\t\ttry {\n\t\t\tconst handle = await this.getHandle(resource);\n\t\t\tif (!handle) {\n\t\t\t\tthrow this.createFileSystemProviderError(resource, 'No such file or directory, stat', FileSystemProviderErrorCode.FileNotFound);\n\t\t\t}\n\n\t\t\tif (WebFileSystemAccess.isFileSystemFileHandle(handle)) {\n\t\t\t\tconst file = await handle.getFile();\n\n\t\t\t\treturn {\n\t\t\t\t\ttype: FileType.File,\n\t\t\t\t\tmtime: file.lastModified,\n\t\t\t\t\tctime: 0,\n\t\t\t\t\tsize: file.size\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\ttype: FileType.Directory,\n\t\t\t\tmtime: 0,\n\t\t\t\tctime: 0,\n\t\t\t\tsize: 0\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tthrow this.toFileSystemProviderError(error);\n\t\t}\n\t}\n\n\tasync readdir(resource: URI): Promise<[string, FileType][]> {\n\t\ttry {\n\t\t\tconst handle = await this.getDirectoryHandle(resource);\n\t\t\tif (!handle) {\n\t\t\t\tthrow this.createFileSystemProviderError(resource, 'No such file or directory, readdir', FileSystemProviderErrorCode.FileNotFound);\n\t\t\t}\n\n\t\t\tconst result: [string, FileType][] = [];\n\n\t\t\tfor await (const [name, child] of handle) {\n\t\t\t\tresult.push([name, WebFileSystemAccess.isFileSystemFileHandle(child) ? FileType.File : FileType.Directory]);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t} catch (error) {\n\t\t\tthrow this.toFileSystemProviderError(error);\n\t\t}\n\t}\n\n\t//#endregion\n\n\t//#region File Reading/Writing\n\n\treadFileStream(resource: URI, opts: IFileReadStreamOptions, token: CancellationToken): ReadableStreamEvents {\n\t\tconst stream = newWriteableStream(data => VSBuffer.concat(data.map(data => VSBuffer.wrap(data))).buffer, {\n\t\t\t// Set a highWaterMark to prevent the stream\n\t\t\t// for file upload to produce large buffers\n\t\t\t// in-memory\n\t\t\thighWaterMark: 10\n\t\t});\n\n\t\t(async () => {\n\t\t\ttry {\n\t\t\t\tconst handle = await this.getFileHandle(resource);\n\t\t\t\tif (!handle) {\n\t\t\t\t\tthrow this.createFileSystemProviderError(resource, 'No such file or directory, readFile', FileSystemProviderErrorCode.FileNotFound);\n\t\t\t\t}\n\n\t\t\t\tconst file = await handle.getFile();\n\n\t\t\t\t// Partial file: implemented simply via `readFile`\n\t\t\t\tif (typeof opts.length === 'number' || typeof opts.position === 'number') {\n\t\t\t\t\tlet buffer = new Uint8Array(await file.arrayBuffer());\n\n\t\t\t\t\tif (typeof opts?.position === 'number') {\n\t\t\t\t\t\tbuffer = buffer.slice(opts.position);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (typeof opts?.length === 'number') {\n\t\t\t\t\t\tbuffer = buffer.slice(0, opts.length);\n\t\t\t\t\t}\n\n\t\t\t\t\tstream.end(buffer);\n\t\t\t\t}\n\n\t\t\t\t// Entire file\n\t\t\t\telse {\n\t\t\t\t\tconst reader: ReadableStreamDefaultReader = file.stream().getReader();\n\n\t\t\t\t\tlet res = await reader.read();\n\t\t\t\t\twhile (!res.done) {\n\t\t\t\t\t\tif (token.isCancellationRequested) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Write buffer into stream but make sure to wait\n\t\t\t\t\t\t// in case the `highWaterMark` is reached\n\t\t\t\t\t\tawait stream.write(res.value);\n\n\t\t\t\t\t\tif (token.isCancellationRequested) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tres = await reader.read();\n\t\t\t\t\t}\n\t\t\t\t\tstream.end(undefined);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tstream.error(this.toFileSystemProviderError(error));\n\t\t\t\tstream.end();\n\t\t\t}\n\t\t})();\n\n\t\treturn stream;\n\t}\n\n\tasync readFile(resource: URI): Promise {\n\t\ttry {\n\t\t\tconst handle = await this.getFileHandle(resource);\n\t\t\tif (!handle) {\n\t\t\t\tthrow this.createFileSystemProviderError(resource, 'No such file or directory, readFile', FileSystemProviderErrorCode.FileNotFound);\n\t\t\t}\n\n\t\t\tconst file = await handle.getFile();\n\n\t\t\treturn new Uint8Array(await file.arrayBuffer());\n\t\t} catch (error) {\n\t\t\tthrow this.toFileSystemProviderError(error);\n\t\t}\n\t}\n\n\tasync writeFile(resource: URI, content: Uint8Array, opts: IFileWriteOptions): Promise {\n\t\ttry {\n\t\t\tlet handle = await this.getFileHandle(resource);\n\n\t\t\t// Validate target unless { create: true, overwrite: true }\n\t\t\tif (!opts.create || !opts.overwrite) {\n\t\t\t\tif (handle) {\n\t\t\t\t\tif (!opts.overwrite) {\n\t\t\t\t\t\tthrow this.createFileSystemProviderError(resource, 'File already exists, writeFile', FileSystemProviderErrorCode.FileExists);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif (!opts.create) {\n\t\t\t\t\t\tthrow this.createFileSystemProviderError(resource, 'No such file, writeFile', FileSystemProviderErrorCode.FileNotFound);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Create target as needed\n\t\t\tif (!handle) {\n\t\t\t\tconst parent = await this.getDirectoryHandle(this.extUri.dirname(resource));\n\t\t\t\tif (!parent) {\n\t\t\t\t\tthrow this.createFileSystemProviderError(resource, 'No such parent directory, writeFile', FileSystemProviderErrorCode.FileNotFound);\n\t\t\t\t}\n\n\t\t\t\thandle = await parent.getFileHandle(this.extUri.basename(resource), { create: true });\n\t\t\t\tif (!handle) {\n\t\t\t\t\tthrow this.createFileSystemProviderError(resource, 'Unable to create file , writeFile', FileSystemProviderErrorCode.Unknown);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Write to target overwriting any existing contents\n\t\t\tconst writable = await handle.createWritable();\n\t\t\tawait writable.write(content);\n\t\t\tawait writable.close();\n\t\t} catch (error) {\n\t\t\tthrow this.toFileSystemProviderError(error);\n\t\t}\n\t}\n\n\t//#endregion\n\n\t//#region Move/Copy/Delete/Create Folder\n\n\tasync mkdir(resource: URI): Promise {\n\t\ttry {\n\t\t\tconst parent = await this.getDirectoryHandle(this.extUri.dirname(resource));\n\t\t\tif (!parent) {\n\t\t\t\tthrow this.createFileSystemProviderError(resource, 'No such parent directory, mkdir', FileSystemProviderErrorCode.FileNotFound);\n\t\t\t}\n\n\t\t\tawait parent.getDirectoryHandle(this.extUri.basename(resource), { create: true });\n\t\t} catch (error) {\n\t\t\tthrow this.toFileSystemProviderError(error);\n\t\t}\n\t}\n\n\tasync delete(resource: URI, opts: IFileDeleteOptions): Promise {\n\t\ttry {\n\t\t\tconst parent = await this.getDirectoryHandle(this.extUri.dirname(resource));\n\t\t\tif (!parent) {\n\t\t\t\tthrow this.createFileSystemProviderError(resource, 'No such parent directory, delete', FileSystemProviderErrorCode.FileNotFound);\n\t\t\t}\n\n\t\t\treturn parent.removeEntry(this.extUri.basename(resource), { recursive: opts.recursive });\n\t\t} catch (error) {\n\t\t\tthrow this.toFileSystemProviderError(error);\n\t\t}\n\t}\n\n\tasync rename(from: URI, to: URI, opts: IFileOverwriteOptions): Promise {\n\t\ttry {\n\t\t\tif (this.extUri.isEqual(from, to)) {\n\t\t\t\treturn; // no-op if the paths are the same\n\t\t\t}\n\n\t\t\t// Implement file rename by write + delete\n\t\t\tconst fileHandle = await this.getFileHandle(from);\n\t\t\tif (fileHandle) {\n\t\t\t\tconst file = await fileHandle.getFile();\n\t\t\t\tconst contents = new Uint8Array(await file.arrayBuffer());\n\n\t\t\t\tawait this.writeFile(to, contents, { create: true, overwrite: opts.overwrite, unlock: false, atomic: false });\n\t\t\t\tawait this.delete(from, { recursive: false, useTrash: false, atomic: false });\n\t\t\t}\n\n\t\t\t// File API does not support any real rename otherwise\n\t\t\telse {\n\t\t\t\tthrow this.createFileSystemProviderError(from, localize('fileSystemRenameError', \"Rename is only supported for files.\"), FileSystemProviderErrorCode.Unavailable);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tthrow this.toFileSystemProviderError(error);\n\t\t}\n\t}\n\n\t//#endregion\n\n\t//#region File Watching (unsupported)\n\n\twatch(resource: URI, opts: IWatchOptions): IDisposable {\n\t\treturn Disposable.None;\n\t}\n\n\t//#endregion\n\n\t//#region File/Directoy Handle Registry\n\n\tprivate readonly _files = new Map();\n\tprivate readonly _directories = new Map();\n\n\tregisterFileHandle(handle: FileSystemFileHandle): Promise {\n\t\treturn this.registerHandle(handle, this._files);\n\t}\n\n\tregisterDirectoryHandle(handle: FileSystemDirectoryHandle): Promise {\n\t\treturn this.registerHandle(handle, this._directories);\n\t}\n\n\tget directories(): Iterable {\n\t\treturn this._directories.values();\n\t}\n\n\tprivate async registerHandle(handle: FileSystemHandle, map: Map): Promise {\n\t\tlet handleId = `/${handle.name}`;\n\n\t\t// Compute a valid handle ID in case this exists already\n\t\tif (map.has(handleId) && !await map.get(handleId)?.isSameEntry(handle)) {\n\t\t\tconst fileExt = extname(handle.name);\n\t\t\tconst fileName = basename(handle.name, fileExt);\n\n\t\t\tlet handleIdCounter = 1;\n\t\t\tdo {\n\t\t\t\thandleId = `/${fileName}-${handleIdCounter++}${fileExt}`;\n\t\t\t} while (map.has(handleId) && !await map.get(handleId)?.isSameEntry(handle));\n\t\t}\n\n\t\tmap.set(handleId, handle);\n\n\t\t// Remember in IndexDB for future lookup\n\t\ttry {\n\t\t\tawait this.indexedDB?.runInTransaction(this.store, 'readwrite', objectStore => objectStore.put(handle, handleId));\n\t\t} catch (error) {\n\t\t\tthis.logService.error(error);\n\t\t}\n\n\t\treturn URI.from({ scheme: Schemas.file, path: handleId });\n\t}\n\n\tasync getHandle(resource: URI): Promise {\n\n\t\t// First: try to find a well known handle first\n\t\tlet handle = await this.doGetHandle(resource);\n\n\t\t// Second: walk up parent directories and resolve handle if possible\n\t\tif (!handle) {\n\t\t\tconst parent = await this.getDirectoryHandle(this.extUri.dirname(resource));\n\t\t\tif (parent) {\n\t\t\t\tconst name = extUri.basename(resource);\n\t\t\t\ttry {\n\t\t\t\t\thandle = await parent.getFileHandle(name);\n\t\t\t\t} catch (error) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\thandle = await parent.getDirectoryHandle(name);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t// Ignore\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn handle;\n\t}\n\n\tprivate async getFileHandle(resource: URI): Promise {\n\t\tconst handle = await this.doGetHandle(resource);\n\t\tif (handle instanceof FileSystemFileHandle) {\n\t\t\treturn handle;\n\t\t}\n\n\t\tconst parent = await this.getDirectoryHandle(this.extUri.dirname(resource));\n\n\t\ttry {\n\t\t\treturn await parent?.getFileHandle(extUri.basename(resource));\n\t\t} catch (error) {\n\t\t\treturn undefined; // guard against possible DOMException\n\t\t}\n\t}\n\n\tprivate async getDirectoryHandle(resource: URI): Promise {\n\t\tconst handle = await this.doGetHandle(resource);\n\t\tif (handle instanceof FileSystemDirectoryHandle) {\n\t\t\treturn handle;\n\t\t}\n\n\t\tconst parentUri = this.extUri.dirname(resource);\n\t\tif (this.extUri.isEqual(parentUri, resource)) {\n\t\t\treturn undefined; // return when root is reached to prevent infinite recursion\n\t\t}\n\n\t\tconst parent = await this.getDirectoryHandle(parentUri);\n\n\t\ttry {\n\t\t\treturn await parent?.getDirectoryHandle(extUri.basename(resource));\n\t\t} catch (error) {\n\t\t\treturn undefined; // guard against possible DOMException\n\t\t}\n\t}\n\n\tprivate async doGetHandle(resource: URI): Promise {\n\n\t\t// We store file system handles with the `handle.name`\n\t\t// and as such require the resource to be on the root\n\t\tif (this.extUri.dirname(resource).path !== '/') {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst handleId = resource.path.replace(/\\/$/, ''); // remove potential slash from the end of the path\n\n\t\t// First: check if we have a known handle stored in memory\n\t\tconst inMemoryHandle = this._files.get(handleId) ?? this._directories.get(handleId);\n\t\tif (inMemoryHandle) {\n\t\t\treturn inMemoryHandle;\n\t\t}\n\n\t\t// Second: check if we have a persisted handle in IndexedDB\n\t\tconst persistedHandle = await this.indexedDB?.runInTransaction(this.store, 'readonly', store => store.get(handleId));\n\t\tif (WebFileSystemAccess.isFileSystemHandle(persistedHandle)) {\n\t\t\tlet hasPermissions = await persistedHandle.queryPermission() === 'granted';\n\t\t\ttry {\n\t\t\t\tif (!hasPermissions) {\n\t\t\t\t\thasPermissions = await persistedHandle.requestPermission() === 'granted';\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthis.logService.error(error); // this can fail with a DOMException\n\t\t\t}\n\n\t\t\tif (hasPermissions) {\n\t\t\t\tif (WebFileSystemAccess.isFileSystemFileHandle(persistedHandle)) {\n\t\t\t\t\tthis._files.set(handleId, persistedHandle);\n\t\t\t\t} else if (WebFileSystemAccess.isFileSystemDirectoryHandle(persistedHandle)) {\n\t\t\t\t\tthis._directories.set(handleId, persistedHandle);\n\t\t\t\t}\n\n\t\t\t\treturn persistedHandle;\n\t\t\t}\n\t\t}\n\n\t\t// Third: fail with an error\n\t\tthrow this.createFileSystemProviderError(resource, 'No file system handle registered', FileSystemProviderErrorCode.Unavailable);\n\t}\n\n\t//#endregion\n\n\tprivate toFileSystemProviderError(error: Error): FileSystemProviderError {\n\t\tif (error instanceof FileSystemProviderError) {\n\t\t\treturn error; // avoid double conversion\n\t\t}\n\n\t\tlet code = FileSystemProviderErrorCode.Unknown;\n\t\tif (error.name === 'NotAllowedError') {\n\t\t\terror = new Error(localize('fileSystemNotAllowedError', \"Insufficient permissions. Please retry and allow the operation.\"));\n\t\t\tcode = FileSystemProviderErrorCode.Unavailable;\n\t\t}\n\n\t\treturn createFileSystemProviderError(error, code);\n\t}\n\n\tprivate createFileSystemProviderError(resource: URI, msg: string, code: FileSystemProviderErrorCode): FileSystemProviderError {\n\t\treturn createFileSystemProviderError(new Error(`${msg} (${normalize(resource.path)})`), code);\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { Throttler } from 'vs/base/common/async';\nimport { VSBuffer } from 'vs/base/common/buffer';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { Disposable, IDisposable } from 'vs/base/common/lifecycle';\nimport { ExtUri } from 'vs/base/common/resources';\nimport { isString } from 'vs/base/common/types';\nimport { URI, UriDto } from 'vs/base/common/uri';\nimport { localize } from 'vs/nls';\nimport { createFileSystemProviderError, FileChangeType, IFileDeleteOptions, IFileOverwriteOptions, FileSystemProviderCapabilities, FileSystemProviderError, FileSystemProviderErrorCode, FileType, IFileWriteOptions, IFileChange, IFileSystemProviderWithFileReadWriteCapability, IStat, IWatchOptions } from 'vs/platform/files/common/files';\nimport { DBClosedError, IndexedDB } from 'vs/base/browser/indexedDB';\nimport { BroadcastDataChannel } from 'vs/base/browser/broadcast';\n\nexport type IndexedDBFileSystemProviderErrorDataClassification = {\n\towner: 'sandy081';\n\tcomment: 'Information about errors that occur in the IndexedDB file system provider';\n\treadonly scheme: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'IndexedDB file system provider scheme for which this error occurred' };\n\treadonly operation: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'operation during which this error occurred' };\n\treadonly code: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'error code' };\n};\n\nexport type IndexedDBFileSystemProviderErrorData = {\n\treadonly scheme: string;\n\treadonly operation: string;\n\treadonly code: string;\n};\n\n// Standard FS Errors (expected to be thrown in production when invalid FS operations are requested)\nconst ERR_FILE_NOT_FOUND = createFileSystemProviderError(localize('fileNotExists', \"File does not exist\"), FileSystemProviderErrorCode.FileNotFound);\nconst ERR_FILE_IS_DIR = createFileSystemProviderError(localize('fileIsDirectory', \"File is Directory\"), FileSystemProviderErrorCode.FileIsADirectory);\nconst ERR_FILE_NOT_DIR = createFileSystemProviderError(localize('fileNotDirectory', \"File is not a directory\"), FileSystemProviderErrorCode.FileNotADirectory);\nconst ERR_DIR_NOT_EMPTY = createFileSystemProviderError(localize('dirIsNotEmpty', \"Directory is not empty\"), FileSystemProviderErrorCode.Unknown);\nconst ERR_FILE_EXCEEDS_STORAGE_QUOTA = createFileSystemProviderError(localize('fileExceedsStorageQuota', \"File exceeds available storage quota\"), FileSystemProviderErrorCode.FileExceedsStorageQuota);\n\n// Arbitrary Internal Errors\nconst ERR_UNKNOWN_INTERNAL = (message: string) => createFileSystemProviderError(localize('internal', \"Internal error occurred in IndexedDB File System Provider. ({0})\", message), FileSystemProviderErrorCode.Unknown);\n\ntype DirEntry = [string, FileType];\n\ntype IndexedDBFileSystemEntry =\n\t| {\n\t\tpath: string;\n\t\ttype: FileType.Directory;\n\t\tchildren: Map;\n\t}\n\t| {\n\t\tpath: string;\n\t\ttype: FileType.File;\n\t\tsize: number | undefined;\n\t};\n\nclass IndexedDBFileSystemNode {\n\tpublic type: FileType;\n\n\tconstructor(private entry: IndexedDBFileSystemEntry) {\n\t\tthis.type = entry.type;\n\t}\n\n\tread(path: string): IndexedDBFileSystemEntry | undefined {\n\t\treturn this.doRead(path.split('/').filter(p => p.length));\n\t}\n\n\tprivate doRead(pathParts: string[]): IndexedDBFileSystemEntry | undefined {\n\t\tif (pathParts.length === 0) { return this.entry; }\n\t\tif (this.entry.type !== FileType.Directory) {\n\t\t\tthrow ERR_UNKNOWN_INTERNAL('Internal error reading from IndexedDBFSNode -- expected directory at ' + this.entry.path);\n\t\t}\n\t\tconst next = this.entry.children.get(pathParts[0]);\n\n\t\tif (!next) { return undefined; }\n\t\treturn next.doRead(pathParts.slice(1));\n\t}\n\n\tdelete(path: string): void {\n\t\tconst toDelete = path.split('/').filter(p => p.length);\n\t\tif (toDelete.length === 0) {\n\t\t\tif (this.entry.type !== FileType.Directory) {\n\t\t\t\tthrow ERR_UNKNOWN_INTERNAL(`Internal error deleting from IndexedDBFSNode. Expected root entry to be directory`);\n\t\t\t}\n\t\t\tthis.entry.children.clear();\n\t\t} else {\n\t\t\treturn this.doDelete(toDelete, path);\n\t\t}\n\t}\n\n\tprivate doDelete(pathParts: string[], originalPath: string): void {\n\t\tif (pathParts.length === 0) {\n\t\t\tthrow ERR_UNKNOWN_INTERNAL(`Internal error deleting from IndexedDBFSNode -- got no deletion path parts (encountered while deleting ${originalPath})`);\n\t\t}\n\t\telse if (this.entry.type !== FileType.Directory) {\n\t\t\tthrow ERR_UNKNOWN_INTERNAL('Internal error deleting from IndexedDBFSNode -- expected directory at ' + this.entry.path);\n\t\t}\n\t\telse if (pathParts.length === 1) {\n\t\t\tthis.entry.children.delete(pathParts[0]);\n\t\t}\n\t\telse {\n\t\t\tconst next = this.entry.children.get(pathParts[0]);\n\t\t\tif (!next) {\n\t\t\t\tthrow ERR_UNKNOWN_INTERNAL('Internal error deleting from IndexedDBFSNode -- expected entry at ' + this.entry.path + '/' + next);\n\t\t\t}\n\t\t\tnext.doDelete(pathParts.slice(1), originalPath);\n\t\t}\n\t}\n\n\tadd(path: string, entry: { type: 'file'; size?: number } | { type: 'dir' }) {\n\t\tthis.doAdd(path.split('/').filter(p => p.length), entry, path);\n\t}\n\n\tprivate doAdd(pathParts: string[], entry: { type: 'file'; size?: number } | { type: 'dir' }, originalPath: string) {\n\t\tif (pathParts.length === 0) {\n\t\t\tthrow ERR_UNKNOWN_INTERNAL(`Internal error creating IndexedDBFSNode -- adding empty path (encountered while adding ${originalPath})`);\n\t\t}\n\t\telse if (this.entry.type !== FileType.Directory) {\n\t\t\tthrow ERR_UNKNOWN_INTERNAL(`Internal error creating IndexedDBFSNode -- parent is not a directory (encountered while adding ${originalPath})`);\n\t\t}\n\t\telse if (pathParts.length === 1) {\n\t\t\tconst next = pathParts[0];\n\t\t\tconst existing = this.entry.children.get(next);\n\t\t\tif (entry.type === 'dir') {\n\t\t\t\tif (existing?.entry.type === FileType.File) {\n\t\t\t\t\tthrow ERR_UNKNOWN_INTERNAL(`Internal error creating IndexedDBFSNode -- overwriting file with directory: ${this.entry.path}/${next} (encountered while adding ${originalPath})`);\n\t\t\t\t}\n\t\t\t\tthis.entry.children.set(next, existing ?? new IndexedDBFileSystemNode({\n\t\t\t\t\ttype: FileType.Directory,\n\t\t\t\t\tpath: this.entry.path + '/' + next,\n\t\t\t\t\tchildren: new Map(),\n\t\t\t\t}));\n\t\t\t} else {\n\t\t\t\tif (existing?.entry.type === FileType.Directory) {\n\t\t\t\t\tthrow ERR_UNKNOWN_INTERNAL(`Internal error creating IndexedDBFSNode -- overwriting directory with file: ${this.entry.path}/${next} (encountered while adding ${originalPath})`);\n\t\t\t\t}\n\t\t\t\tthis.entry.children.set(next, new IndexedDBFileSystemNode({\n\t\t\t\t\ttype: FileType.File,\n\t\t\t\t\tpath: this.entry.path + '/' + next,\n\t\t\t\t\tsize: entry.size,\n\t\t\t\t}));\n\t\t\t}\n\t\t}\n\t\telse if (pathParts.length > 1) {\n\t\t\tconst next = pathParts[0];\n\t\t\tlet childNode = this.entry.children.get(next);\n\t\t\tif (!childNode) {\n\t\t\t\tchildNode = new IndexedDBFileSystemNode({\n\t\t\t\t\tchildren: new Map(),\n\t\t\t\t\tpath: this.entry.path + '/' + next,\n\t\t\t\t\ttype: FileType.Directory\n\t\t\t\t});\n\t\t\t\tthis.entry.children.set(next, childNode);\n\t\t\t}\n\t\t\telse if (childNode.type === FileType.File) {\n\t\t\t\tthrow ERR_UNKNOWN_INTERNAL(`Internal error creating IndexedDBFSNode -- overwriting file entry with directory: ${this.entry.path}/${next} (encountered while adding ${originalPath})`);\n\t\t\t}\n\t\t\tchildNode.doAdd(pathParts.slice(1), entry, originalPath);\n\t\t}\n\t}\n\n\tprint(indentation = '') {\n\t\tconsole.log(indentation + this.entry.path);\n\t\tif (this.entry.type === FileType.Directory) {\n\t\t\tthis.entry.children.forEach(child => child.print(indentation + ' '));\n\t\t}\n\t}\n}\n\nexport class IndexedDBFileSystemProvider extends Disposable implements IFileSystemProviderWithFileReadWriteCapability {\n\n\treadonly capabilities: FileSystemProviderCapabilities =\n\t\tFileSystemProviderCapabilities.FileReadWrite\n\t\t| FileSystemProviderCapabilities.PathCaseSensitive;\n\treadonly onDidChangeCapabilities: Event = Event.None;\n\n\tprivate readonly extUri = new ExtUri(() => false) /* Case Sensitive */;\n\n\tprivate readonly changesBroadcastChannel: BroadcastDataChannel[]> | undefined;\n\tprivate readonly _onDidChangeFile = this._register(new Emitter());\n\treadonly onDidChangeFile: Event = this._onDidChangeFile.event;\n\n\tprivate readonly _onReportError = this._register(new Emitter());\n\treadonly onReportError = this._onReportError.event;\n\n\tprivate readonly mtimes = new Map();\n\n\tprivate cachedFiletree: Promise | undefined;\n\tprivate writeManyThrottler: Throttler;\n\n\tconstructor(readonly scheme: string, private indexedDB: IndexedDB, private readonly store: string, watchCrossWindowChanges: boolean) {\n\t\tsuper();\n\t\tthis.writeManyThrottler = new Throttler();\n\n\t\tif (watchCrossWindowChanges) {\n\t\t\tthis.changesBroadcastChannel = this._register(new BroadcastDataChannel[]>(`vscode.indexedDB.${scheme}.changes`));\n\t\t\tthis._register(this.changesBroadcastChannel.onDidReceiveData(changes => {\n\t\t\t\tthis._onDidChangeFile.fire(changes.map(c => ({ type: c.type, resource: URI.revive(c.resource) })));\n\t\t\t}));\n\t\t}\n\t}\n\n\twatch(resource: URI, opts: IWatchOptions): IDisposable {\n\t\treturn Disposable.None;\n\t}\n\n\tasync mkdir(resource: URI): Promise {\n\t\ttry {\n\t\t\tconst resourceStat = await this.stat(resource);\n\t\t\tif (resourceStat.type === FileType.File) {\n\t\t\t\tthrow ERR_FILE_NOT_DIR;\n\t\t\t}\n\t\t} catch (error) { /* Ignore */ }\n\t\t(await this.getFiletree()).add(resource.path, { type: 'dir' });\n\t}\n\n\tasync stat(resource: URI): Promise {\n\t\tconst entry = (await this.getFiletree()).read(resource.path);\n\n\t\tif (entry?.type === FileType.File) {\n\t\t\treturn {\n\t\t\t\ttype: FileType.File,\n\t\t\t\tctime: 0,\n\t\t\t\tmtime: this.mtimes.get(resource.toString()) || 0,\n\t\t\t\tsize: entry.size ?? (await this.readFile(resource)).byteLength\n\t\t\t};\n\t\t}\n\n\t\tif (entry?.type === FileType.Directory) {\n\t\t\treturn {\n\t\t\t\ttype: FileType.Directory,\n\t\t\t\tctime: 0,\n\t\t\t\tmtime: 0,\n\t\t\t\tsize: 0\n\t\t\t};\n\t\t}\n\n\t\tthrow ERR_FILE_NOT_FOUND;\n\t}\n\n\tasync readdir(resource: URI): Promise {\n\t\ttry {\n\t\t\tconst entry = (await this.getFiletree()).read(resource.path);\n\t\t\tif (!entry) {\n\t\t\t\t// Dirs aren't saved to disk, so empty dirs will be lost on reload.\n\t\t\t\t// Thus we have two options for what happens when you try to read a dir and nothing is found:\n\t\t\t\t// - Throw FileSystemProviderErrorCode.FileNotFound\n\t\t\t\t// - Return []\n\t\t\t\t// We choose to return [] as creating a dir then reading it (even after reload) should not throw an error.\n\t\t\t\treturn [];\n\t\t\t}\n\t\t\tif (entry.type !== FileType.Directory) {\n\t\t\t\tthrow ERR_FILE_NOT_DIR;\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn [...entry.children.entries()].map(([name, node]) => [name, node.type]);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tthis.reportError('readDir', error);\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tasync readFile(resource: URI): Promise {\n\t\ttry {\n\t\t\tconst result = await this.indexedDB.runInTransaction(this.store, 'readonly', objectStore => objectStore.get(resource.path));\n\t\t\tif (result === undefined) {\n\t\t\t\tthrow ERR_FILE_NOT_FOUND;\n\t\t\t}\n\t\t\tconst buffer = result instanceof Uint8Array ? result : isString(result) ? VSBuffer.fromString(result).buffer : undefined;\n\t\t\tif (buffer === undefined) {\n\t\t\t\tthrow ERR_UNKNOWN_INTERNAL(`IndexedDB entry at \"${resource.path}\" in unexpected format`);\n\t\t\t}\n\n\t\t\t// update cache\n\t\t\tconst fileTree = await this.getFiletree();\n\t\t\tfileTree.add(resource.path, { type: 'file', size: buffer.byteLength });\n\n\t\t\treturn buffer;\n\t\t} catch (error) {\n\t\t\tthis.reportError('readFile', error);\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tasync writeFile(resource: URI, content: Uint8Array, opts: IFileWriteOptions): Promise {\n\t\ttry {\n\t\t\tconst existing = await this.stat(resource).catch(() => undefined);\n\t\t\tif (existing?.type === FileType.Directory) {\n\t\t\t\tthrow ERR_FILE_IS_DIR;\n\t\t\t}\n\t\t\tawait this.bulkWrite([[resource, content]]);\n\t\t} catch (error) {\n\t\t\tthis.reportError('writeFile', error);\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tasync rename(from: URI, to: URI, opts: IFileOverwriteOptions): Promise {\n\t\tconst fileTree = await this.getFiletree();\n\t\tconst fromEntry = fileTree.read(from.path);\n\t\tif (!fromEntry) {\n\t\t\tthrow ERR_FILE_NOT_FOUND;\n\t\t}\n\n\t\tconst toEntry = fileTree.read(to.path);\n\t\tif (toEntry) {\n\t\t\tif (!opts.overwrite) {\n\t\t\t\tthrow createFileSystemProviderError('file exists already', FileSystemProviderErrorCode.FileExists);\n\t\t\t}\n\t\t\tif (toEntry.type !== fromEntry.type) {\n\t\t\t\tthrow createFileSystemProviderError('Cannot rename files with different types', FileSystemProviderErrorCode.Unknown);\n\t\t\t}\n\t\t\t// delete the target file if exists\n\t\t\tawait this.delete(to, { recursive: true, useTrash: false, atomic: false });\n\t\t}\n\n\t\tconst toTargetResource = (path: string): URI => this.extUri.joinPath(to, this.extUri.relativePath(from, from.with({ path })) || '');\n\n\t\tconst sourceEntries = await this.tree(from);\n\t\tconst sourceFiles: DirEntry[] = [];\n\t\tfor (const sourceEntry of sourceEntries) {\n\t\t\tif (sourceEntry[1] === FileType.File) {\n\t\t\t\tsourceFiles.push(sourceEntry);\n\t\t\t} else if (sourceEntry[1] === FileType.Directory) {\n\t\t\t\t// add directories to the tree\n\t\t\t\tfileTree.add(toTargetResource(sourceEntry[0]).path, { type: 'dir' });\n\t\t\t}\n\t\t}\n\n\t\tif (sourceFiles.length) {\n\t\t\tconst targetFiles: [URI, Uint8Array][] = [];\n\t\t\tconst sourceFilesContents = await this.indexedDB.runInTransaction(this.store, 'readonly', objectStore => sourceFiles.map(([path]) => objectStore.get(path)));\n\t\t\tfor (let index = 0; index < sourceFiles.length; index++) {\n\t\t\t\tconst content = sourceFilesContents[index] instanceof Uint8Array ? sourceFilesContents[index] : isString(sourceFilesContents[index]) ? VSBuffer.fromString(sourceFilesContents[index]).buffer : undefined;\n\t\t\t\tif (content) {\n\t\t\t\t\ttargetFiles.push([toTargetResource(sourceFiles[index][0]), content]);\n\t\t\t\t}\n\t\t\t}\n\t\t\tawait this.bulkWrite(targetFiles);\n\t\t}\n\n\t\tawait this.delete(from, { recursive: true, useTrash: false, atomic: false });\n\t}\n\n\tasync delete(resource: URI, opts: IFileDeleteOptions): Promise {\n\t\tlet stat: IStat;\n\t\ttry {\n\t\t\tstat = await this.stat(resource);\n\t\t} catch (e) {\n\t\t\tif (e.code === FileSystemProviderErrorCode.FileNotFound) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthrow e;\n\t\t}\n\n\t\tlet toDelete: string[];\n\t\tif (opts.recursive) {\n\t\t\tconst tree = await this.tree(resource);\n\t\t\ttoDelete = tree.map(([path]) => path);\n\t\t} else {\n\t\t\tif (stat.type === FileType.Directory && (await this.readdir(resource)).length) {\n\t\t\t\tthrow ERR_DIR_NOT_EMPTY;\n\t\t\t}\n\t\t\ttoDelete = [resource.path];\n\t\t}\n\t\tawait this.deleteKeys(toDelete);\n\t\t(await this.getFiletree()).delete(resource.path);\n\t\ttoDelete.forEach(key => this.mtimes.delete(key));\n\t\tthis.triggerChanges(toDelete.map(path => ({ resource: resource.with({ path }), type: FileChangeType.DELETED })));\n\t}\n\n\tprivate async tree(resource: URI): Promise {\n\t\tconst stat = await this.stat(resource);\n\t\tconst allEntries: DirEntry[] = [[resource.path, stat.type]];\n\t\tif (stat.type === FileType.Directory) {\n\t\t\tconst dirEntries = await this.readdir(resource);\n\t\t\tfor (const [key, type] of dirEntries) {\n\t\t\t\tconst childResource = this.extUri.joinPath(resource, key);\n\t\t\t\tallEntries.push([childResource.path, type]);\n\t\t\t\tif (type === FileType.Directory) {\n\t\t\t\t\tconst childEntries = await this.tree(childResource);\n\t\t\t\t\tallEntries.push(...childEntries);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn allEntries;\n\t}\n\n\tprivate triggerChanges(changes: IFileChange[]): void {\n\t\tif (changes.length) {\n\t\t\tthis._onDidChangeFile.fire(changes);\n\n\t\t\tthis.changesBroadcastChannel?.postData(changes);\n\t\t}\n\t}\n\n\tprivate getFiletree(): Promise {\n\t\tif (!this.cachedFiletree) {\n\t\t\tthis.cachedFiletree = (async () => {\n\t\t\t\tconst rootNode = new IndexedDBFileSystemNode({\n\t\t\t\t\tchildren: new Map(),\n\t\t\t\t\tpath: '',\n\t\t\t\t\ttype: FileType.Directory\n\t\t\t\t});\n\t\t\t\tconst result = await this.indexedDB.runInTransaction(this.store, 'readonly', objectStore => objectStore.getAllKeys());\n\t\t\t\tconst keys = result.map(key => key.toString());\n\t\t\t\tkeys.forEach(key => rootNode.add(key, { type: 'file' }));\n\t\t\t\treturn rootNode;\n\t\t\t})();\n\t\t}\n\t\treturn this.cachedFiletree;\n\t}\n\n\tprivate async bulkWrite(files: [URI, Uint8Array][]): Promise {\n\t\tfiles.forEach(([resource, content]) => this.fileWriteBatch.push({ content, resource }));\n\t\tawait this.writeManyThrottler.queue(() => this.writeMany());\n\n\t\tconst fileTree = await this.getFiletree();\n\t\tfor (const [resource, content] of files) {\n\t\t\tfileTree.add(resource.path, { type: 'file', size: content.byteLength });\n\t\t\tthis.mtimes.set(resource.toString(), Date.now());\n\t\t}\n\n\t\tthis.triggerChanges(files.map(([resource]) => ({ resource, type: FileChangeType.UPDATED })));\n\t}\n\n\tprivate fileWriteBatch: { resource: URI; content: Uint8Array }[] = [];\n\tprivate async writeMany() {\n\t\tif (this.fileWriteBatch.length) {\n\t\t\tconst fileBatch = this.fileWriteBatch.splice(0, this.fileWriteBatch.length);\n\t\t\ttry {\n\t\t\t\tawait this.indexedDB.runInTransaction(this.store, 'readwrite', objectStore => fileBatch.map(entry => {\n\t\t\t\t\treturn objectStore.put(entry.content, entry.resource.path);\n\t\t\t\t}));\n\t\t\t} catch (ex) {\n\t\t\t\tif (ex instanceof DOMException && ex.name === 'QuotaExceededError') {\n\t\t\t\t\tthrow ERR_FILE_EXCEEDS_STORAGE_QUOTA;\n\t\t\t\t}\n\n\t\t\t\tthrow ex;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async deleteKeys(keys: string[]): Promise {\n\t\tif (keys.length) {\n\t\t\tawait this.indexedDB.runInTransaction(this.store, 'readwrite', objectStore => keys.map(key => objectStore.delete(key)));\n\t\t}\n\t}\n\n\tasync reset(): Promise {\n\t\tawait this.indexedDB.runInTransaction(this.store, 'readwrite', objectStore => objectStore.clear());\n\t}\n\n\tprivate reportError(operation: string, error: Error): void {\n\t\tthis._onReportError.fire({ scheme: this.scheme, operation, code: error instanceof FileSystemProviderError || error instanceof DBClosedError ? error.code : 'unknown' });\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 { VSBuffer } from 'vs/base/common/buffer';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { Disposable, IDisposable } from 'vs/base/common/lifecycle';\nimport * as resources from 'vs/base/common/resources';\nimport { ReadableStreamEvents, newWriteableStream } from 'vs/base/common/stream';\nimport { URI } from 'vs/base/common/uri';\nimport { FileChangeType, IFileDeleteOptions, IFileOverwriteOptions, FileSystemProviderCapabilities, FileSystemProviderErrorCode, FileType, IFileWriteOptions, IFileChange, IFileSystemProviderWithFileReadWriteCapability, IStat, IWatchOptions, createFileSystemProviderError, IFileSystemProviderWithOpenReadWriteCloseCapability, IFileOpenOptions, IFileSystemProviderWithFileAtomicDeleteCapability, IFileSystemProviderWithFileAtomicReadCapability, IFileSystemProviderWithFileAtomicWriteCapability, IFileSystemProviderWithFileReadStreamCapability } from 'vs/platform/files/common/files';\n\nclass File implements IStat {\n\n\treadonly type: FileType.File;\n\treadonly ctime: number;\n\tmtime: number;\n\tsize: number;\n\n\tname: string;\n\tdata?: Uint8Array;\n\n\tconstructor(name: string) {\n\t\tthis.type = FileType.File;\n\t\tthis.ctime = Date.now();\n\t\tthis.mtime = Date.now();\n\t\tthis.size = 0;\n\t\tthis.name = name;\n\t}\n}\n\nclass Directory implements IStat {\n\n\treadonly type: FileType.Directory;\n\treadonly ctime: number;\n\tmtime: number;\n\tsize: number;\n\n\tname: string;\n\treadonly entries: Map;\n\n\tconstructor(name: string) {\n\t\tthis.type = FileType.Directory;\n\t\tthis.ctime = Date.now();\n\t\tthis.mtime = Date.now();\n\t\tthis.size = 0;\n\t\tthis.name = name;\n\t\tthis.entries = new Map();\n\t}\n}\n\ntype Entry = File | Directory;\n\nexport class InMemoryFileSystemProvider extends Disposable implements\n\tIFileSystemProviderWithFileReadWriteCapability,\n\tIFileSystemProviderWithOpenReadWriteCloseCapability,\n\tIFileSystemProviderWithFileReadStreamCapability,\n\tIFileSystemProviderWithFileAtomicReadCapability,\n\tIFileSystemProviderWithFileAtomicWriteCapability,\n\tIFileSystemProviderWithFileAtomicDeleteCapability {\n\n\tprivate memoryFdCounter = 0;\n\tprivate readonly fdMemory = new Map();\n\tprivate _onDidChangeCapabilities = this._register(new Emitter());\n\treadonly onDidChangeCapabilities = this._onDidChangeCapabilities.event;\n\n\tprivate _capabilities = FileSystemProviderCapabilities.FileReadWrite | FileSystemProviderCapabilities.PathCaseSensitive;\n\tget capabilities(): FileSystemProviderCapabilities { return this._capabilities; }\n\n\tsetReadOnly(readonly: boolean) {\n\t\tconst isReadonly = !!(this._capabilities & FileSystemProviderCapabilities.Readonly);\n\t\tif (readonly !== isReadonly) {\n\t\t\tthis._capabilities = readonly ? FileSystemProviderCapabilities.Readonly | FileSystemProviderCapabilities.PathCaseSensitive | FileSystemProviderCapabilities.FileReadWrite\n\t\t\t\t: FileSystemProviderCapabilities.FileReadWrite | FileSystemProviderCapabilities.PathCaseSensitive;\n\t\t\tthis._onDidChangeCapabilities.fire();\n\t\t}\n\t}\n\n\troot = new Directory('');\n\n\t// --- manage file metadata\n\n\tasync stat(resource: URI): Promise {\n\t\treturn this._lookup(resource, false);\n\t}\n\n\tasync readdir(resource: URI): Promise<[string, FileType][]> {\n\t\tconst entry = this._lookupAsDirectory(resource, false);\n\t\tconst result: [string, FileType][] = [];\n\t\tentry.entries.forEach((child, name) => result.push([name, child.type]));\n\t\treturn result;\n\t}\n\n\t// --- manage file contents\n\n\tasync readFile(resource: URI): Promise {\n\t\tconst data = this._lookupAsFile(resource, false).data;\n\t\tif (data) {\n\t\t\treturn data;\n\t\t}\n\t\tthrow createFileSystemProviderError('file not found', FileSystemProviderErrorCode.FileNotFound);\n\t}\n\n\treadFileStream(resource: URI): ReadableStreamEvents {\n\t\tconst data = this._lookupAsFile(resource, false).data;\n\n\t\tconst stream = newWriteableStream(data => VSBuffer.concat(data.map(data => VSBuffer.wrap(data))).buffer);\n\t\tstream.end(data);\n\n\t\treturn stream;\n\t}\n\n\tasync writeFile(resource: URI, content: Uint8Array, opts: IFileWriteOptions): Promise {\n\t\tconst basename = resources.basename(resource);\n\t\tconst parent = this._lookupParentDirectory(resource);\n\t\tlet entry = parent.entries.get(basename);\n\t\tif (entry instanceof Directory) {\n\t\t\tthrow createFileSystemProviderError('file is directory', FileSystemProviderErrorCode.FileIsADirectory);\n\t\t}\n\t\tif (!entry && !opts.create) {\n\t\t\tthrow createFileSystemProviderError('file not found', FileSystemProviderErrorCode.FileNotFound);\n\t\t}\n\t\tif (entry && opts.create && !opts.overwrite) {\n\t\t\tthrow createFileSystemProviderError('file exists already', FileSystemProviderErrorCode.FileExists);\n\t\t}\n\t\tif (!entry) {\n\t\t\tentry = new File(basename);\n\t\t\tparent.entries.set(basename, entry);\n\t\t\tthis._fireSoon({ type: FileChangeType.ADDED, resource });\n\t\t}\n\t\tentry.mtime = Date.now();\n\t\tentry.size = content.byteLength;\n\t\tentry.data = content;\n\n\t\tthis._fireSoon({ type: FileChangeType.UPDATED, resource });\n\t}\n\n\t// file open/read/write/close\n\topen(resource: URI, opts: IFileOpenOptions): Promise {\n\t\tconst data = this._lookupAsFile(resource, false).data;\n\t\tif (data) {\n\t\t\tconst fd = this.memoryFdCounter++;\n\t\t\tthis.fdMemory.set(fd, data);\n\t\t\treturn Promise.resolve(fd);\n\t\t}\n\t\tthrow createFileSystemProviderError('file not found', FileSystemProviderErrorCode.FileNotFound);\n\t}\n\n\tclose(fd: number): Promise {\n\t\tthis.fdMemory.delete(fd);\n\t\treturn Promise.resolve();\n\t}\n\n\tread(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise {\n\t\tconst memory = this.fdMemory.get(fd);\n\t\tif (!memory) {\n\t\t\tthrow createFileSystemProviderError(`No file with that descriptor open`, FileSystemProviderErrorCode.Unavailable);\n\t\t}\n\n\t\tconst toWrite = VSBuffer.wrap(memory).slice(pos, pos + length);\n\t\tdata.set(toWrite.buffer, offset);\n\t\treturn Promise.resolve(toWrite.byteLength);\n\t}\n\n\twrite(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise {\n\t\tconst memory = this.fdMemory.get(fd);\n\t\tif (!memory) {\n\t\t\tthrow createFileSystemProviderError(`No file with that descriptor open`, FileSystemProviderErrorCode.Unavailable);\n\t\t}\n\n\t\tconst toWrite = VSBuffer.wrap(data).slice(offset, offset + length);\n\t\tmemory.set(toWrite.buffer, pos);\n\t\treturn Promise.resolve(toWrite.byteLength);\n\t}\n\n\t// --- manage files/folders\n\n\tasync rename(from: URI, to: URI, opts: IFileOverwriteOptions): Promise {\n\t\tif (!opts.overwrite && this._lookup(to, true)) {\n\t\t\tthrow createFileSystemProviderError('file exists already', FileSystemProviderErrorCode.FileExists);\n\t\t}\n\n\t\tconst entry = this._lookup(from, false);\n\t\tconst oldParent = this._lookupParentDirectory(from);\n\n\t\tconst newParent = this._lookupParentDirectory(to);\n\t\tconst newName = resources.basename(to);\n\n\t\toldParent.entries.delete(entry.name);\n\t\tentry.name = newName;\n\t\tnewParent.entries.set(newName, entry);\n\n\t\tthis._fireSoon(\n\t\t\t{ type: FileChangeType.DELETED, resource: from },\n\t\t\t{ type: FileChangeType.ADDED, resource: to }\n\t\t);\n\t}\n\n\tasync delete(resource: URI, opts: IFileDeleteOptions): Promise {\n\t\tconst dirname = resources.dirname(resource);\n\t\tconst basename = resources.basename(resource);\n\t\tconst parent = this._lookupAsDirectory(dirname, false);\n\t\tif (parent.entries.has(basename)) {\n\t\t\tparent.entries.delete(basename);\n\t\t\tparent.mtime = Date.now();\n\t\t\tparent.size -= 1;\n\t\t\tthis._fireSoon({ type: FileChangeType.UPDATED, resource: dirname }, { resource, type: FileChangeType.DELETED });\n\t\t}\n\t}\n\n\tasync mkdir(resource: URI): Promise {\n\t\tif (this._lookup(resource, true)) {\n\t\t\tthrow createFileSystemProviderError('file exists already', FileSystemProviderErrorCode.FileExists);\n\t\t}\n\n\t\tconst basename = resources.basename(resource);\n\t\tconst dirname = resources.dirname(resource);\n\t\tconst parent = this._lookupAsDirectory(dirname, false);\n\n\t\tconst entry = new Directory(basename);\n\t\tparent.entries.set(entry.name, entry);\n\t\tparent.mtime = Date.now();\n\t\tparent.size += 1;\n\t\tthis._fireSoon({ type: FileChangeType.UPDATED, resource: dirname }, { type: FileChangeType.ADDED, resource });\n\t}\n\n\t// --- lookup\n\n\tprivate _lookup(uri: URI, silent: false): Entry;\n\tprivate _lookup(uri: URI, silent: boolean): Entry | undefined;\n\tprivate _lookup(uri: URI, silent: boolean): Entry | undefined {\n\t\tconst parts = uri.path.split('/');\n\t\tlet entry: Entry = this.root;\n\t\tfor (const part of parts) {\n\t\t\tif (!part) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tlet child: Entry | undefined;\n\t\t\tif (entry instanceof Directory) {\n\t\t\t\tchild = entry.entries.get(part);\n\t\t\t}\n\t\t\tif (!child) {\n\t\t\t\tif (!silent) {\n\t\t\t\t\tthrow createFileSystemProviderError('file not found', FileSystemProviderErrorCode.FileNotFound);\n\t\t\t\t} else {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t\tentry = child;\n\t\t}\n\t\treturn entry;\n\t}\n\n\tprivate _lookupAsDirectory(uri: URI, silent: boolean): Directory {\n\t\tconst entry = this._lookup(uri, silent);\n\t\tif (entry instanceof Directory) {\n\t\t\treturn entry;\n\t\t}\n\t\tthrow createFileSystemProviderError('file not a directory', FileSystemProviderErrorCode.FileNotADirectory);\n\t}\n\n\tprivate _lookupAsFile(uri: URI, silent: boolean): File {\n\t\tconst entry = this._lookup(uri, silent);\n\t\tif (entry instanceof File) {\n\t\t\treturn entry;\n\t\t}\n\t\tthrow createFileSystemProviderError('file is a directory', FileSystemProviderErrorCode.FileIsADirectory);\n\t}\n\n\tprivate _lookupParentDirectory(uri: URI): Directory {\n\t\tconst dirname = resources.dirname(uri);\n\t\treturn this._lookupAsDirectory(dirname, false);\n\t}\n\n\t// --- manage file events\n\n\tprivate readonly _onDidChangeFile = this._register(new Emitter());\n\treadonly onDidChangeFile: Event = this._onDidChangeFile.event;\n\n\tprivate _bufferedChanges: IFileChange[] = [];\n\tprivate _fireSoonHandle?: any;\n\n\twatch(resource: URI, opts: IWatchOptions): IDisposable {\n\t\t// ignore, fires for all changes...\n\t\treturn Disposable.None;\n\t}\n\n\tprivate _fireSoon(...changes: IFileChange[]): void {\n\t\tthis._bufferedChanges.push(...changes);\n\n\t\tif (this._fireSoonHandle) {\n\t\t\tclearTimeout(this._fireSoonHandle);\n\t\t}\n\n\t\tthis._fireSoonHandle = setTimeout(() => {\n\t\t\tthis._onDidChangeFile.fire(this._bufferedChanges);\n\t\t\tthis._bufferedChanges.length = 0;\n\t\t}, 5);\n\t}\n\n\toverride dispose(): void {\n\t\tsuper.dispose();\n\n\t\tthis.fdMemory.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 { VSBuffer } from 'vs/base/common/buffer';\nimport { CancellationToken } from 'vs/base/common/cancellation';\nimport { canceled } from 'vs/base/common/errors';\nimport { IDataTransformer, IErrorTransformer, WriteableStream } from 'vs/base/common/stream';\nimport { URI } from 'vs/base/common/uri';\nimport { localize } from 'vs/nls';\nimport { createFileSystemProviderError, ensureFileSystemProviderError, IFileReadStreamOptions, FileSystemProviderErrorCode, IFileSystemProviderWithOpenReadWriteCloseCapability } from 'vs/platform/files/common/files';\n\nexport interface ICreateReadStreamOptions extends IFileReadStreamOptions {\n\n\t/**\n\t * The size of the buffer to use before sending to the stream.\n\t */\n\treadonly bufferSize: number;\n\n\t/**\n\t * Allows to massage any possibly error that happens during reading.\n\t */\n\treadonly errorTransformer?: IErrorTransformer;\n}\n\n/**\n * A helper to read a file from a provider with open/read/close capability into a stream.\n */\nexport async function readFileIntoStream(\n\tprovider: IFileSystemProviderWithOpenReadWriteCloseCapability,\n\tresource: URI,\n\ttarget: WriteableStream,\n\ttransformer: IDataTransformer,\n\toptions: ICreateReadStreamOptions,\n\ttoken: CancellationToken\n): Promise {\n\tlet error: Error | undefined = undefined;\n\n\ttry {\n\t\tawait doReadFileIntoStream(provider, resource, target, transformer, options, token);\n\t} catch (err) {\n\t\terror = err;\n\t} finally {\n\t\tif (error && options.errorTransformer) {\n\t\t\terror = options.errorTransformer(error);\n\t\t}\n\n\t\tif (typeof error !== 'undefined') {\n\t\t\ttarget.error(error);\n\t\t}\n\n\t\ttarget.end();\n\t}\n}\n\nasync function doReadFileIntoStream(provider: IFileSystemProviderWithOpenReadWriteCloseCapability, resource: URI, target: WriteableStream, transformer: IDataTransformer, options: ICreateReadStreamOptions, token: CancellationToken): Promise {\n\n\t// Check for cancellation\n\tthrowIfCancelled(token);\n\n\t// open handle through provider\n\tconst handle = await provider.open(resource, { create: false });\n\n\ttry {\n\n\t\t// Check for cancellation\n\t\tthrowIfCancelled(token);\n\n\t\tlet totalBytesRead = 0;\n\t\tlet bytesRead = 0;\n\t\tlet allowedRemainingBytes = (options && typeof options.length === 'number') ? options.length : undefined;\n\n\t\tlet buffer = VSBuffer.alloc(Math.min(options.bufferSize, typeof allowedRemainingBytes === 'number' ? allowedRemainingBytes : options.bufferSize));\n\n\t\tlet posInFile = options && typeof options.position === 'number' ? options.position : 0;\n\t\tlet posInBuffer = 0;\n\t\tdo {\n\t\t\t// read from source (handle) at current position (pos) into buffer (buffer) at\n\t\t\t// buffer position (posInBuffer) up to the size of the buffer (buffer.byteLength).\n\t\t\tbytesRead = await provider.read(handle, posInFile, buffer.buffer, posInBuffer, buffer.byteLength - posInBuffer);\n\n\t\t\tposInFile += bytesRead;\n\t\t\tposInBuffer += bytesRead;\n\t\t\ttotalBytesRead += bytesRead;\n\n\t\t\tif (typeof allowedRemainingBytes === 'number') {\n\t\t\t\tallowedRemainingBytes -= bytesRead;\n\t\t\t}\n\n\t\t\t// when buffer full, create a new one and emit it through stream\n\t\t\tif (posInBuffer === buffer.byteLength) {\n\t\t\t\tawait target.write(transformer(buffer));\n\n\t\t\t\tbuffer = VSBuffer.alloc(Math.min(options.bufferSize, typeof allowedRemainingBytes === 'number' ? allowedRemainingBytes : options.bufferSize));\n\n\t\t\t\tposInBuffer = 0;\n\t\t\t}\n\t\t} while (bytesRead > 0 && (typeof allowedRemainingBytes !== 'number' || allowedRemainingBytes > 0) && throwIfCancelled(token) && throwIfTooLarge(totalBytesRead, options));\n\n\t\t// wrap up with last buffer (also respect maxBytes if provided)\n\t\tif (posInBuffer > 0) {\n\t\t\tlet lastChunkLength = posInBuffer;\n\t\t\tif (typeof allowedRemainingBytes === 'number') {\n\t\t\t\tlastChunkLength = Math.min(posInBuffer, allowedRemainingBytes);\n\t\t\t}\n\n\t\t\ttarget.write(transformer(buffer.slice(0, lastChunkLength)));\n\t\t}\n\t} catch (error) {\n\t\tthrow ensureFileSystemProviderError(error);\n\t} finally {\n\t\tawait provider.close(handle);\n\t}\n}\n\nfunction throwIfCancelled(token: CancellationToken): boolean {\n\tif (token.isCancellationRequested) {\n\t\tthrow canceled();\n\t}\n\n\treturn true;\n}\n\nfunction throwIfTooLarge(totalBytesRead: number, options: ICreateReadStreamOptions): boolean {\n\n\t// Return early if file is too large to load and we have configured limits\n\tif (typeof options?.limits?.size === 'number' && totalBytesRead > options.limits.size) {\n\t\tthrow createFileSystemProviderError(localize('fileTooLargeError', \"File is too large to open\"), FileSystemProviderErrorCode.FileTooLarge);\n\t}\n\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\nimport { Event } from 'vs/base/common/event';\nimport { GLOBSTAR, IRelativePattern, parse, ParsedPattern } from 'vs/base/common/glob';\nimport { Disposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle';\nimport { isAbsolute } from 'vs/base/common/path';\nimport { isLinux } from 'vs/base/common/platform';\nimport { URI } from 'vs/base/common/uri';\nimport { FileChangeType, IFileChange, isParent } from 'vs/platform/files/common/files';\n\ninterface IWatchRequest {\n\n\t/**\n\t * The path to watch.\n\t */\n\treadonly path: string;\n\n\t/**\n\t * Whether to watch recursively or not.\n\t */\n\treadonly recursive: boolean;\n\n\t/**\n\t * A set of glob patterns or paths to exclude from watching.\n\t */\n\treadonly excludes: string[];\n\n\t/**\n\t * An optional set of glob patterns or paths to include for\n\t * watching. If not provided, all paths are considered for\n\t * events.\n\t */\n\treadonly includes?: Array;\n\n\t/**\n\t * If provided, file change events from the watcher that\n\t * are a result of this watch request will carry the same\n\t * id.\n\t */\n\treadonly correlationId?: number;\n}\n\nexport interface INonRecursiveWatchRequest extends IWatchRequest {\n\n\t/**\n\t * The watcher will be non-recursive.\n\t */\n\treadonly recursive: false;\n}\n\nexport interface IRecursiveWatchRequest extends IWatchRequest {\n\n\t/**\n\t * The watcher will be recursive.\n\t */\n\treadonly recursive: true;\n\n\t/**\n\t * @deprecated this only exists for WSL1 support and should never\n\t * be used in any other case.\n\t */\n\tpollingInterval?: number;\n}\n\nexport function isRecursiveWatchRequest(request: IWatchRequest): request is IRecursiveWatchRequest {\n\treturn request.recursive === true;\n}\n\nexport type IUniversalWatchRequest = IRecursiveWatchRequest | INonRecursiveWatchRequest;\n\ninterface IWatcher {\n\n\t/**\n\t * A normalized file change event from the raw events\n\t * the watcher emits.\n\t */\n\treadonly onDidChangeFile: Event;\n\n\t/**\n\t * An event to indicate a message that should get logged.\n\t */\n\treadonly onDidLogMessage: Event;\n\n\t/**\n\t * An event to indicate an error occurred from the watcher\n\t * that is unrecoverable. Listeners should restart the\n\t * watcher if possible.\n\t */\n\treadonly onDidError: Event;\n\n\t/**\n\t * Configures the watcher to watch according to the\n\t * requests. Any existing watched path that is not\n\t * in the array, will be removed from watching and\n\t * any new path will be added to watching.\n\t */\n\twatch(requests: IWatchRequest[]): Promise;\n\n\t/**\n\t * Enable verbose logging in the watcher.\n\t */\n\tsetVerboseLogging(enabled: boolean): Promise;\n\n\t/**\n\t * Stop all watchers.\n\t */\n\tstop(): Promise;\n}\n\nexport interface IRecursiveWatcher extends IWatcher {\n\twatch(requests: IRecursiveWatchRequest[]): Promise;\n}\n\nexport interface IRecursiveWatcherOptions {\n\n\t/**\n\t * If `true`, will enable polling for all watchers, otherwise\n\t * will enable it for paths included in the string array.\n\t *\n\t * @deprecated this only exists for WSL1 support and should never\n\t * be used in any other case.\n\t */\n\treadonly usePolling: boolean | string[];\n\n\t/**\n\t * If polling is enabled (via `usePolling`), defines the duration\n\t * in which the watcher will poll for changes.\n\t *\n\t * @deprecated this only exists for WSL1 support and should never\n\t * be used in any other case.\n\t */\n\treadonly pollingInterval?: number;\n}\n\nexport interface INonRecursiveWatcher extends IWatcher {\n\twatch(requests: INonRecursiveWatchRequest[]): Promise;\n}\n\nexport interface IUniversalWatcher extends IWatcher {\n\twatch(requests: IUniversalWatchRequest[]): Promise;\n}\n\nexport abstract class AbstractWatcherClient extends Disposable {\n\n\tprivate static readonly MAX_RESTARTS = 5;\n\n\tprivate watcher: IWatcher | undefined;\n\tprivate readonly watcherDisposables = this._register(new MutableDisposable());\n\n\tprivate requests: IWatchRequest[] | undefined = undefined;\n\n\tprivate restartCounter = 0;\n\n\tconstructor(\n\t\tprivate readonly onFileChanges: (changes: IFileChange[]) => void,\n\t\tprivate readonly onLogMessage: (msg: ILogMessage) => void,\n\t\tprivate verboseLogging: boolean,\n\t\tprivate options: {\n\t\t\ttype: string;\n\t\t\trestartOnError: boolean;\n\t\t}\n\t) {\n\t\tsuper();\n\t}\n\n\tprotected abstract createWatcher(disposables: DisposableStore): IWatcher;\n\n\tprotected init(): void {\n\n\t\t// Associate disposables to the watcher\n\t\tconst disposables = new DisposableStore();\n\t\tthis.watcherDisposables.value = disposables;\n\n\t\t// Ask implementors to create the watcher\n\t\tthis.watcher = this.createWatcher(disposables);\n\t\tthis.watcher.setVerboseLogging(this.verboseLogging);\n\n\t\t// Wire in event handlers\n\t\tdisposables.add(this.watcher.onDidChangeFile(changes => this.onFileChanges(changes)));\n\t\tdisposables.add(this.watcher.onDidLogMessage(msg => this.onLogMessage(msg)));\n\t\tdisposables.add(this.watcher.onDidError(error => this.onError(error)));\n\t}\n\n\tprotected onError(error: string): void {\n\n\t\t// Restart on error (up to N times, if enabled)\n\t\tif (this.options.restartOnError) {\n\t\t\tif (this.restartCounter < AbstractWatcherClient.MAX_RESTARTS && this.requests) {\n\t\t\t\tthis.error(`restarting watcher after error: ${error}`);\n\t\t\t\tthis.restart(this.requests);\n\t\t\t} else {\n\t\t\t\tthis.error(`gave up attempting to restart watcher after error: ${error}`);\n\t\t\t}\n\t\t}\n\n\t\t// Do not attempt to restart if not enabled\n\t\telse {\n\t\t\tthis.error(error);\n\t\t}\n\t}\n\n\tprivate restart(requests: IUniversalWatchRequest[]): void {\n\t\tthis.restartCounter++;\n\n\t\tthis.init();\n\t\tthis.watch(requests);\n\t}\n\n\tasync watch(requests: IUniversalWatchRequest[]): Promise {\n\t\tthis.requests = requests;\n\n\t\tawait this.watcher?.watch(requests);\n\t}\n\n\tasync setVerboseLogging(verboseLogging: boolean): Promise {\n\t\tthis.verboseLogging = verboseLogging;\n\n\t\tawait this.watcher?.setVerboseLogging(verboseLogging);\n\t}\n\n\tprivate error(message: string) {\n\t\tthis.onLogMessage({ type: 'error', message: `[File Watcher (${this.options.type})] ${message}` });\n\t}\n\n\tprotected trace(message: string) {\n\t\tthis.onLogMessage({ type: 'trace', message: `[File Watcher (${this.options.type})] ${message}` });\n\t}\n\n\toverride dispose(): void {\n\n\t\t// Render the watcher invalid from here\n\t\tthis.watcher = undefined;\n\n\t\treturn super.dispose();\n\t}\n}\n\nexport abstract class AbstractNonRecursiveWatcherClient extends AbstractWatcherClient {\n\n\tconstructor(\n\t\tonFileChanges: (changes: IFileChange[]) => void,\n\t\tonLogMessage: (msg: ILogMessage) => void,\n\t\tverboseLogging: boolean\n\t) {\n\t\tsuper(onFileChanges, onLogMessage, verboseLogging, { type: 'node.js', restartOnError: false });\n\t}\n\n\tprotected abstract override createWatcher(disposables: DisposableStore): INonRecursiveWatcher;\n}\n\nexport abstract class AbstractUniversalWatcherClient extends AbstractWatcherClient {\n\n\tconstructor(\n\t\tonFileChanges: (changes: IFileChange[]) => void,\n\t\tonLogMessage: (msg: ILogMessage) => void,\n\t\tverboseLogging: boolean\n\t) {\n\t\tsuper(onFileChanges, onLogMessage, verboseLogging, { type: 'universal', restartOnError: true });\n\t}\n\n\tprotected abstract override createWatcher(disposables: DisposableStore): IUniversalWatcher;\n}\n\nexport interface ILogMessage {\n\treadonly type: 'trace' | 'warn' | 'error' | 'info' | 'debug';\n\treadonly message: string;\n}\n\nexport function reviveFileChanges(changes: IFileChange[]): IFileChange[] {\n\treturn changes.map(change => ({\n\t\ttype: change.type,\n\t\tresource: URI.revive(change.resource),\n\t\tcId: change.cId\n\t}));\n}\n\nexport function coalesceEvents(changes: IFileChange[]): IFileChange[] {\n\n\t// Build deltas\n\tconst coalescer = new EventCoalescer();\n\tfor (const event of changes) {\n\t\tcoalescer.processEvent(event);\n\t}\n\n\treturn coalescer.coalesce();\n}\n\nexport function normalizeWatcherPattern(path: string, pattern: string | IRelativePattern): string | IRelativePattern {\n\n\t// Patterns are always matched on the full absolute path\n\t// of the event. As such, if the pattern is not absolute\n\t// and is a string and does not start with a leading\n\t// `**`, we have to convert it to a relative pattern with\n\t// the given `base`\n\n\tif (typeof pattern === 'string' && !pattern.startsWith(GLOBSTAR) && !isAbsolute(pattern)) {\n\t\treturn { base: path, pattern };\n\t}\n\n\treturn pattern;\n}\n\nexport function parseWatcherPatterns(path: string, patterns: Array): ParsedPattern[] {\n\tconst parsedPatterns: ParsedPattern[] = [];\n\n\tfor (const pattern of patterns) {\n\t\tparsedPatterns.push(parse(normalizeWatcherPattern(path, pattern)));\n\t}\n\n\treturn parsedPatterns;\n}\n\nclass EventCoalescer {\n\n\tprivate readonly coalesced = new Set();\n\tprivate readonly mapPathToChange = new Map();\n\n\tprivate toKey(event: IFileChange): string {\n\t\tif (isLinux) {\n\t\t\treturn event.resource.fsPath;\n\t\t}\n\n\t\treturn event.resource.fsPath.toLowerCase(); // normalise to file system case sensitivity\n\t}\n\n\tprocessEvent(event: IFileChange): void {\n\t\tconst existingEvent = this.mapPathToChange.get(this.toKey(event));\n\n\t\tlet keepEvent = false;\n\n\t\t// Event path already exists\n\t\tif (existingEvent) {\n\t\t\tconst currentChangeType = existingEvent.type;\n\t\t\tconst newChangeType = event.type;\n\n\t\t\t// macOS/Windows: track renames to different case\n\t\t\t// by keeping both CREATE and DELETE events\n\t\t\tif (existingEvent.resource.fsPath !== event.resource.fsPath && (event.type === FileChangeType.DELETED || event.type === FileChangeType.ADDED)) {\n\t\t\t\tkeepEvent = true;\n\t\t\t}\n\n\t\t\t// Ignore CREATE followed by DELETE in one go\n\t\t\telse if (currentChangeType === FileChangeType.ADDED && newChangeType === FileChangeType.DELETED) {\n\t\t\t\tthis.mapPathToChange.delete(this.toKey(event));\n\t\t\t\tthis.coalesced.delete(existingEvent);\n\t\t\t}\n\n\t\t\t// Flatten DELETE followed by CREATE into CHANGE\n\t\t\telse if (currentChangeType === FileChangeType.DELETED && newChangeType === FileChangeType.ADDED) {\n\t\t\t\texistingEvent.type = FileChangeType.UPDATED;\n\t\t\t}\n\n\t\t\t// Do nothing. Keep the created event\n\t\t\telse if (currentChangeType === FileChangeType.ADDED && newChangeType === FileChangeType.UPDATED) { }\n\n\t\t\t// Otherwise apply change type\n\t\t\telse {\n\t\t\t\texistingEvent.type = newChangeType;\n\t\t\t}\n\t\t}\n\n\t\t// Otherwise keep\n\t\telse {\n\t\t\tkeepEvent = true;\n\t\t}\n\n\t\tif (keepEvent) {\n\t\t\tthis.coalesced.add(event);\n\t\t\tthis.mapPathToChange.set(this.toKey(event), event);\n\t\t}\n\t}\n\n\tcoalesce(): IFileChange[] {\n\t\tconst addOrChangeEvents: IFileChange[] = [];\n\t\tconst deletedPaths: string[] = [];\n\n\t\t// This algorithm will remove all DELETE events up to the root folder\n\t\t// that got deleted if any. This ensures that we are not producing\n\t\t// DELETE events for each file inside a folder that gets deleted.\n\t\t//\n\t\t// 1.) split ADD/CHANGE and DELETED events\n\t\t// 2.) sort short deleted paths to the top\n\t\t// 3.) for each DELETE, check if there is a deleted parent and ignore the event in that case\n\t\treturn Array.from(this.coalesced).filter(e => {\n\t\t\tif (e.type !== FileChangeType.DELETED) {\n\t\t\t\taddOrChangeEvents.push(e);\n\n\t\t\t\treturn false; // remove ADD / CHANGE\n\t\t\t}\n\n\t\t\treturn true; // keep DELETE\n\t\t}).sort((e1, e2) => {\n\t\t\treturn e1.resource.fsPath.length - e2.resource.fsPath.length; // shortest path first\n\t\t}).filter(e => {\n\t\t\tif (deletedPaths.some(deletedPath => isParent(e.resource.fsPath, deletedPath, !isLinux /* ignorecase */))) {\n\t\t\t\treturn false; // DELETE is ignored if parent is deleted already\n\t\t\t}\n\n\t\t\t// otherwise mark as deleted\n\t\t\tdeletedPaths.push(e.resource.fsPath);\n\n\t\t\treturn true;\n\t\t}).concat(addOrChangeEvents);\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { CancellationToken } from 'vs/base/common/cancellation';\nimport { toErrorMessage } from 'vs/base/common/errorMessage';\nimport { canceled } from 'vs/base/common/errors';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';\nimport { newWriteableStream, ReadableStreamEventPayload, ReadableStreamEvents } from 'vs/base/common/stream';\nimport { URI } from 'vs/base/common/uri';\nimport { generateUuid } from 'vs/base/common/uuid';\nimport { IChannel } from 'vs/base/parts/ipc/common/ipc';\nimport { createFileSystemProviderError, IFileAtomicReadOptions, IFileDeleteOptions, IFileOpenOptions, IFileOverwriteOptions, IFileReadStreamOptions, FileSystemProviderCapabilities, FileSystemProviderErrorCode, FileType, IFileWriteOptions, IFileChange, IFileSystemProviderWithFileAtomicReadCapability, IFileSystemProviderWithFileCloneCapability, IFileSystemProviderWithFileFolderCopyCapability, IFileSystemProviderWithFileReadStreamCapability, IFileSystemProviderWithFileReadWriteCapability, IFileSystemProviderWithOpenReadWriteCloseCapability, IStat, IWatchOptions, IFileSystemProviderError } from 'vs/platform/files/common/files';\nimport { reviveFileChanges } from 'vs/platform/files/common/watcher';\n\nexport const LOCAL_FILE_SYSTEM_CHANNEL_NAME = 'localFilesystem';\n\n/**\n * An implementation of a local disk file system provider\n * that is backed by a `IChannel` and thus implemented via\n * IPC on a different process.\n */\nexport class DiskFileSystemProviderClient extends Disposable implements\n\tIFileSystemProviderWithFileReadWriteCapability,\n\tIFileSystemProviderWithOpenReadWriteCloseCapability,\n\tIFileSystemProviderWithFileReadStreamCapability,\n\tIFileSystemProviderWithFileFolderCopyCapability,\n\tIFileSystemProviderWithFileAtomicReadCapability,\n\tIFileSystemProviderWithFileCloneCapability {\n\n\tconstructor(\n\t\tprivate readonly channel: IChannel,\n\t\tprivate readonly extraCapabilities: { trash?: boolean; pathCaseSensitive?: boolean }\n\t) {\n\t\tsuper();\n\n\t\tthis.registerFileChangeListeners();\n\t}\n\n\t//#region File Capabilities\n\n\treadonly onDidChangeCapabilities: Event = Event.None;\n\n\tprivate _capabilities: FileSystemProviderCapabilities | undefined;\n\tget capabilities(): FileSystemProviderCapabilities {\n\t\tif (!this._capabilities) {\n\t\t\tthis._capabilities =\n\t\t\t\tFileSystemProviderCapabilities.FileReadWrite |\n\t\t\t\tFileSystemProviderCapabilities.FileOpenReadWriteClose |\n\t\t\t\tFileSystemProviderCapabilities.FileReadStream |\n\t\t\t\tFileSystemProviderCapabilities.FileFolderCopy |\n\t\t\t\tFileSystemProviderCapabilities.FileWriteUnlock |\n\t\t\t\tFileSystemProviderCapabilities.FileAtomicRead |\n\t\t\t\tFileSystemProviderCapabilities.FileAtomicWrite |\n\t\t\t\tFileSystemProviderCapabilities.FileAtomicDelete |\n\t\t\t\tFileSystemProviderCapabilities.FileClone;\n\n\t\t\tif (this.extraCapabilities.pathCaseSensitive) {\n\t\t\t\tthis._capabilities |= FileSystemProviderCapabilities.PathCaseSensitive;\n\t\t\t}\n\n\t\t\tif (this.extraCapabilities.trash) {\n\t\t\t\tthis._capabilities |= FileSystemProviderCapabilities.Trash;\n\t\t\t}\n\t\t}\n\n\t\treturn this._capabilities;\n\t}\n\n\t//#endregion\n\n\t//#region File Metadata Resolving\n\n\tstat(resource: URI): Promise {\n\t\treturn this.channel.call('stat', [resource]);\n\t}\n\n\treaddir(resource: URI): Promise<[string, FileType][]> {\n\t\treturn this.channel.call('readdir', [resource]);\n\t}\n\n\t//#endregion\n\n\t//#region File Reading/Writing\n\n\tasync readFile(resource: URI, opts?: IFileAtomicReadOptions): Promise {\n\t\tconst { buffer } = await this.channel.call('readFile', [resource, opts]) as VSBuffer;\n\n\t\treturn buffer;\n\t}\n\n\treadFileStream(resource: URI, opts: IFileReadStreamOptions, token: CancellationToken): ReadableStreamEvents {\n\t\tconst stream = newWriteableStream(data => VSBuffer.concat(data.map(data => VSBuffer.wrap(data))).buffer);\n\t\tconst disposables = new DisposableStore();\n\n\t\t// Reading as file stream goes through an event to the remote side\n\t\tdisposables.add(this.channel.listen>('readFileStream', [resource, opts])(dataOrErrorOrEnd => {\n\n\t\t\t// data\n\t\t\tif (dataOrErrorOrEnd instanceof VSBuffer) {\n\t\t\t\tstream.write(dataOrErrorOrEnd.buffer);\n\t\t\t}\n\n\t\t\t// end or error\n\t\t\telse {\n\t\t\t\tif (dataOrErrorOrEnd === 'end') {\n\t\t\t\t\tstream.end();\n\t\t\t\t} else {\n\t\t\t\t\tlet error: Error;\n\n\t\t\t\t\t// Take Error as is if type matches\n\t\t\t\t\tif (dataOrErrorOrEnd instanceof Error) {\n\t\t\t\t\t\terror = dataOrErrorOrEnd;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Otherwise, try to deserialize into an error.\n\t\t\t\t\t// Since we communicate via IPC, we cannot be sure\n\t\t\t\t\t// that Error objects are properly serialized.\n\t\t\t\t\telse {\n\t\t\t\t\t\tconst errorCandidate = dataOrErrorOrEnd as IFileSystemProviderError;\n\n\t\t\t\t\t\terror = createFileSystemProviderError(errorCandidate.message ?? toErrorMessage(errorCandidate), errorCandidate.code ?? FileSystemProviderErrorCode.Unknown);\n\t\t\t\t\t}\n\n\t\t\t\t\tstream.error(error);\n\t\t\t\t\tstream.end();\n\t\t\t\t}\n\n\t\t\t\t// Signal to the remote side that we no longer listen\n\t\t\t\tdisposables.dispose();\n\t\t\t}\n\t\t}));\n\n\t\t// Support cancellation\n\t\tdisposables.add(token.onCancellationRequested(() => {\n\n\t\t\t// Ensure to end the stream properly with an error\n\t\t\t// to indicate the cancellation.\n\t\t\tstream.error(canceled());\n\t\t\tstream.end();\n\n\t\t\t// Ensure to dispose the listener upon cancellation. This will\n\t\t\t// bubble through the remote side as event and allows to stop\n\t\t\t// reading the file.\n\t\t\tdisposables.dispose();\n\t\t}));\n\n\t\treturn stream;\n\t}\n\n\twriteFile(resource: URI, content: Uint8Array, opts: IFileWriteOptions): Promise {\n\t\treturn this.channel.call('writeFile', [resource, VSBuffer.wrap(content), opts]);\n\t}\n\n\topen(resource: URI, opts: IFileOpenOptions): Promise {\n\t\treturn this.channel.call('open', [resource, opts]);\n\t}\n\n\tclose(fd: number): Promise {\n\t\treturn this.channel.call('close', [fd]);\n\t}\n\n\tasync read(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise {\n\t\tconst [bytes, bytesRead]: [VSBuffer, number] = await this.channel.call('read', [fd, pos, length]);\n\n\t\t// copy back the data that was written into the buffer on the remote\n\t\t// side. we need to do this because buffers are not referenced by\n\t\t// pointer, but only by value and as such cannot be directly written\n\t\t// to from the other process.\n\t\tdata.set(bytes.buffer.slice(0, bytesRead), offset);\n\n\t\treturn bytesRead;\n\t}\n\n\twrite(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise {\n\t\treturn this.channel.call('write', [fd, pos, VSBuffer.wrap(data), offset, length]);\n\t}\n\n\t//#endregion\n\n\t//#region Move/Copy/Delete/Create Folder\n\n\tmkdir(resource: URI): Promise {\n\t\treturn this.channel.call('mkdir', [resource]);\n\t}\n\n\tdelete(resource: URI, opts: IFileDeleteOptions): Promise {\n\t\treturn this.channel.call('delete', [resource, opts]);\n\t}\n\n\trename(resource: URI, target: URI, opts: IFileOverwriteOptions): Promise {\n\t\treturn this.channel.call('rename', [resource, target, opts]);\n\t}\n\n\tcopy(resource: URI, target: URI, opts: IFileOverwriteOptions): Promise {\n\t\treturn this.channel.call('copy', [resource, target, opts]);\n\t}\n\n\t//#endregion\n\n\t//#region Clone File\n\n\tcloneFile(resource: URI, target: URI): Promise {\n\t\treturn this.channel.call('cloneFile', [resource, target]);\n\t}\n\n\t//#endregion\n\n\t//#region File Watching\n\n\tprivate readonly _onDidChange = this._register(new Emitter());\n\treadonly onDidChangeFile = this._onDidChange.event;\n\n\tprivate readonly _onDidWatchError = this._register(new Emitter());\n\treadonly onDidWatchError = this._onDidWatchError.event;\n\n\t// The contract for file watching via remote is to identify us\n\t// via a unique but readonly session ID. Since the remote is\n\t// managing potentially many watchers from different clients,\n\t// this helps the server to properly partition events to the right\n\t// clients.\n\tprivate readonly sessionId = generateUuid();\n\n\tprivate registerFileChangeListeners(): void {\n\n\t\t// The contract for file changes is that there is one listener\n\t\t// for both events and errors from the watcher. So we need to\n\t\t// unwrap the event from the remote and emit through the proper\n\t\t// emitter.\n\t\tthis._register(this.channel.listen('fileChange', [this.sessionId])(eventsOrError => {\n\t\t\tif (Array.isArray(eventsOrError)) {\n\t\t\t\tconst events = eventsOrError;\n\t\t\t\tthis._onDidChange.fire(reviveFileChanges(events));\n\t\t\t} else {\n\t\t\t\tconst error = eventsOrError;\n\t\t\t\tthis._onDidWatchError.fire(error);\n\t\t\t}\n\t\t}));\n\t}\n\n\twatch(resource: URI, opts: IWatchOptions): IDisposable {\n\n\t\t// Generate a request UUID to correlate the watcher\n\t\t// back to us when we ask to dispose the watcher later.\n\t\tconst req = generateUuid();\n\n\t\tthis.channel.call('watch', [this.sessionId, req, resource, opts]);\n\n\t\treturn toDisposable(() => this.channel.call('unwatch', [this.sessionId, req]));\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 *--------------------------------------------------------------------------------------------*/\n\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\nimport { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';\nimport { IMarkdownString } from 'vs/base/common/htmlContent';\nimport { HoverPosition } from 'vs/base/browser/ui/hover/hoverWidget';\nimport { IHoverDelegate, IHoverDelegateOptions, IHoverWidget } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate';\nimport { IConfigurationService } from 'vs/platform/configuration/common/configuration';\nimport { addStandardDisposableListener } from 'vs/base/browser/dom';\nimport { KeyCode } from 'vs/base/common/keyCodes';\n\nexport const IHoverService = createDecorator('hoverService');\n\n/**\n * Enables the convenient display of rich markdown-based hovers in the workbench.\n */\nexport interface IHoverService {\n\treadonly _serviceBrand: undefined;\n\n\t/**\n\t * Shows a hover, provided a hover with the same options object is not already visible.\n\t * @param options A set of options defining the characteristics of the hover.\n\t * @param focus Whether to focus the hover (useful for keyboard accessibility).\n\t *\n\t * **Example:** A simple usage with a single element target.\n\t *\n\t * ```typescript\n\t * showHover({\n\t * text: new MarkdownString('Hello world'),\n\t * target: someElement\n\t * });\n\t * ```\n\t */\n\tshowHover(options: IHoverOptions, focus?: boolean): IHoverWidget | undefined;\n\n\t/**\n\t * Hides the hover if it was visible. This call will be ignored if the the hover is currently\n\t * \"locked\" via the alt/option key.\n\t */\n\thideHover(): void;\n\n\t/**\n\t * This should only be used until we have the ability to show multiple context views\n\t * simultaneously. #188822\n\t */\n\tshowAndFocusLastHover(): void;\n}\n\nexport interface IHoverOptions {\n\t/**\n\t * The content to display in the primary section of the hover. The type of text determines the\n\t * default `hideOnHover` behavior.\n\t */\n\tcontent: IMarkdownString | string | HTMLElement;\n\n\t/**\n\t * The target for the hover. This determines the position of the hover and it will only be\n\t * hidden when the mouse leaves both the hover and the target. A HTMLElement can be used for\n\t * simple cases and a IHoverTarget for more complex cases where multiple elements and/or a\n\t * dispose method is required.\n\t */\n\ttarget: IHoverTarget | HTMLElement;\n\n\t/*\n\t * The container to pass to {@link IContextViewProvider.showContextView} which renders the hover\n\t * in. This is particularly useful for more natural tab focusing behavior, where the hover is\n\t * created as the next tab index after the element being hovered and/or to workaround the\n\t * element's container hiding on `focusout`.\n\t */\n\tcontainer?: HTMLElement;\n\n\t/**\n\t * An ID to associate with the hover to be used as an equality check. Normally when calling\n\t * {@link IHoverService.showHover} the options object itself is used to determine if the hover\n\t * is the same one that is already showing, when this is set, the ID will be used instead.\n\t */\n\tid?: number | string;\n\n\t/**\n\t * A set of actions for the hover's \"status bar\".\n\t */\n\tactions?: IHoverAction[];\n\n\t/**\n\t * An optional array of classes to add to the hover element.\n\t */\n\tadditionalClasses?: string[];\n\n\t/**\n\t * An optional link handler for markdown links, if this is not provided the IOpenerService will\n\t * be used to open the links using its default options.\n\t */\n\tlinkHandler?(url: string): void;\n\n\t/**\n\t * Whether to trap focus in the following ways:\n\t * - When the hover closes, focus goes to the element that had focus before the hover opened\n\t * - If there are elements in the hover to focus, focus stays inside of the hover when tabbing\n\t * Note that this is overridden to true when in screen reader optimized mode.\n\t */\n\ttrapFocus?: boolean;\n\n\t/**\n\t * Options that defines where the hover is positioned.\n\t */\n\tposition?: IHoverPositionOptions;\n\n\t/**\n\t * Options that defines how long the hover is shown and when it hides.\n\t */\n\tpersistence?: IHoverPersistenceOptions;\n\n\t/**\n\t * Options that define how the hover looks.\n\t */\n\tappearance?: IHoverAppearanceOptions;\n}\n\nexport interface IHoverPositionOptions {\n\t/**\n\t * Position of the hover. The default is to show above the target. This option will be ignored\n\t * if there is not enough room to layout the hover in the specified position, unless the\n\t * forcePosition option is set.\n\t */\n\thoverPosition?: HoverPosition;\n\n\t/**\n\t * Force the hover position, reducing the size of the hover instead of adjusting the hover\n\t * position.\n\t */\n\tforcePosition?: boolean;\n}\n\nexport interface IHoverPersistenceOptions {\n\t/**\n\t * Whether to hide the hover when the mouse leaves the `target` and enters the actual hover.\n\t * This is false by default when text is an `IMarkdownString` and true when `text` is a\n\t * `string`. Note that this will be ignored if any `actions` are provided as hovering is\n\t * required to make them accessible.\n\t *\n\t * In general hiding on hover is desired for:\n\t * - Regular text where selection is not important\n\t * - Markdown that contains no links where selection is not important\n\t */\n\thideOnHover?: boolean;\n\n\t/**\n\t * Whether to hide the hover when a key is pressed.\n\t */\n\thideOnKeyDown?: boolean;\n\n\t/**\n\t * Whether to make the hover sticky, this means it will not be hidden when the mouse leaves the\n\t * hover.\n\t */\n\tsticky?: boolean;\n}\n\nexport interface IHoverAppearanceOptions {\n\t/**\n\t * Whether to show the hover pointer, a little arrow that connects the target and the hover.\n\t */\n\tshowPointer?: boolean;\n\n\t/**\n\t * Whether to show a compact hover, reducing the font size and padding of the hover.\n\t */\n\tcompact?: boolean;\n\n\t/**\n\t * When {@link hideOnHover} is explicitly true or undefined and its auto value is detected to\n\t * hide, show a hint at the bottom of the hover explaining how to mouse over the widget. This\n\t * should be used in the cases where despite the hover having no interactive content, it's\n\t * likely the user may want to interact with it somehow.\n\t */\n\tshowHoverHint?: boolean;\n\n\t/**\n\t * Whether to skip the fade in animation, this should be used when hovering from one hover to\n\t * another in the same group so it looks like the hover is moving from one element to the other.\n\t */\n\tskipFadeInAnimation?: boolean;\n}\n\nexport interface IHoverAction {\n\t/**\n\t * The label to use in the hover's status bar.\n\t */\n\tlabel: string;\n\n\t/**\n\t * The command ID of the action, this is used to resolve the keybinding to display after the\n\t * action label.\n\t */\n\tcommandId: string;\n\n\t/**\n\t * An optional class of an icon that will be displayed before the label.\n\t */\n\ticonClass?: string;\n\n\t/**\n\t * The callback to run the action.\n\t * @param target The action element that was activated.\n\t */\n\trun(target: HTMLElement): void;\n}\n\n/**\n * A target for a hover.\n */\nexport interface IHoverTarget extends IDisposable {\n\t/**\n\t * A set of target elements used to position the hover. If multiple elements are used the hover\n\t * will try to not overlap any target element. An example use case for this is show a hover for\n\t * wrapped text.\n\t */\n\treadonly targetElements: readonly HTMLElement[];\n\n\t/**\n\t * An optional absolute x coordinate to position the hover with, for example to position the\n\t * hover using `MouseEvent.pageX`.\n\t */\n\tx?: number;\n\n\t/**\n\t * An optional absolute y coordinate to position the hover with, for example to position the\n\t * hover using `MouseEvent.pageY`.\n\t */\n\ty?: number;\n}\n\nexport class WorkbenchHoverDelegate extends Disposable implements IHoverDelegate {\n\n\tprivate lastHoverHideTime = Number.MAX_VALUE;\n\tprivate timeLimit = 200;\n\n\tprivate _delay: number;\n\tget delay(): number {\n\t\tif (this.instantHover && Date.now() - this.lastHoverHideTime < this.timeLimit) {\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 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\treturn this.hoverService.showHover({\n\t\t\t...options,\n\t\t\tpersistence: {\n\t\t\t\thideOnHover: true\n\t\t\t},\n\t\t\t...overrideOptions\n\t\t}, focus);\n\t}\n\n\tsetOptions(options: Partial | ((options: IHoverDelegateOptions, focus?: boolean) => Partial)): void {\n\t\tthis.overrideOptions = options;\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\thas(id: ServiceIdentifier): boolean {\n\t\treturn this._entries.has(id);\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 { IDisposable, 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\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\tcreateChild(services: ServiceCollection): IInstantiationService {\n\t\treturn new InstantiationService(services, this._strict, this, this._enableTracing);\n\t}\n\n\tinvokeFunction(fn: (accessor: ServicesAccessor, ...args: TS) => R, ...args: TS): R {\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\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 _setServiceInstance(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._setServiceInstance(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._setServiceInstance(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);\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): T {\n\t\tif (!supportsDelayedInstantiation) {\n\t\t\t// eager instantiation\n\t\t\treturn this._createInstance(ctor, args, _trace);\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\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 { rtrim } from 'vs/base/common/strings';\n\nexport function normalizeGitHubUrl(url: string): string {\n\t// If the url has a .git suffix, remove it\n\tif (url.endsWith('.git')) {\n\t\turl = url.substr(0, url.length - 4);\n\t}\n\n\t// Remove trailing slash\n\turl = rtrim(url, '/');\n\n\tif (url.endsWith('/new')) {\n\t\turl = rtrim(url, '/new');\n\t}\n\n\tif (url.endsWith('/issues')) {\n\t\turl = rtrim(url, '/issues');\n\t}\n\n\treturn url;\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 isWYSIWYG(): boolean {\n\t\treturn this._chords.every((keybinding) => this._isWYSIWYG(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 _isWYSIWYG(keybinding: T): boolean;\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 { IJSONSchema } from 'vs/base/common/jsonSchema';\nimport { KeyCode } from 'vs/base/common/keyCodes';\nimport { ResolvedKeybinding, Keybinding } 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 IUserFriendlyKeybinding {\n\tkey: string;\n\tcommand: string;\n\targs?: any;\n\twhen?: string;\n}\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 altGraphKey: boolean;\n\treadonly keyCode: KeyCode;\n\treadonly code: string;\n}\n\nexport interface KeybindingsSchemaContribution {\n\treadonly onDidChange?: Event;\n\n\tgetSchemaAdditions(): IJSONSchema[];\n}\n\nexport const IKeybindingService = createDecorator('keybindingService');\n\nexport interface IKeybindingService {\n\treadonly _serviceBrand: undefined;\n\n\treadonly inChordMode: boolean;\n\n\tonDidUpdateKeybindings: Event;\n\n\t/**\n\t * Returns none, one or many (depending on keyboard layout)!\n\t */\n\tresolveKeybinding(keybinding: Keybinding): ResolvedKeybinding[];\n\n\tresolveKeyboardEvent(keyboardEvent: IKeyboardEvent): ResolvedKeybinding;\n\n\tresolveUserBinding(userBinding: string): 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 * Enable hold mode for this command. This is only possible if the command is current being dispatched, meaning\n\t * we are after its keydown and before is keyup event.\n\t *\n\t * @returns A promise that resolves when hold stops, returns undefined if hold mode could not be enabled.\n\t */\n\tenableKeybindingHoldMode(commandId: string): Promise | undefined;\n\n\tdispatchByUserSettingsLabel(userSettingsLabel: string, target: IContextKeyServiceTarget): void;\n\n\t/**\n\t * Look up keybindings for a command.\n\t * Use `lookupKeybinding` if you are interested in the preferred keybinding.\n\t */\n\tlookupKeybindings(commandId: string): ResolvedKeybinding[];\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\tgetDefaultKeybindingsContent(): string;\n\n\tgetDefaultKeybindings(): readonly ResolvedKeybindingItem[];\n\n\tgetKeybindings(): readonly ResolvedKeybindingItem[];\n\n\tcustomKeybindingsCount(): number;\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\tregisterSchemaContribution(contribution: KeybindingsSchemaContribution): void;\n\n\ttoggleLogging(): boolean;\n\n\t_dumpDebugInfo(): string;\n\t_dumpDebugInfoJSON(): 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 * 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 { 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 { WorkspaceEdit } from 'vs/editor/common/languages';\nimport { TrackedRangeStickiness } from 'vs/editor/common/model';\nimport { createCombinedWorkspaceEdit } from 'vs/editor/contrib/dropOrPasteInto/browser/edit';\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';\n\n\ninterface EditSet {\n\treadonly activeEditIndex: number;\n\treadonly allEdits: ReadonlyArray<{\n\t\treadonly label: string;\n\t\treadonly insertText: string | { readonly snippet: string };\n\t\treadonly additionalEdit?: WorkspaceEdit;\n\t}>;\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.label,\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) {\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, 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[edits.activeEditIndex];\n\t\tif (!edit) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst combinedWorkspaceEdit = createCombinedWorkspaceEdit(model.uri, ranges, edit);\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\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} finally {\n\t\t\tmodel.deltaDecorations(editTrackingDecoration, []);\n\t\t}\n\n\t\tif (canShowWidget && editResult.isApplied && edits.allEdits.length > 1) {\n\t\t\tthis.show(editRange ?? primaryRange, edits, async (newEditIndex) => {\n\t\t\t\tconst model = this._editor.getModel();\n\t\t\t\tif (!model) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tawait model.undo();\n\t\t\t\tthis.applyEditAndShowIfNeeded(ranges, { activeEditIndex: newEditIndex, allEdits: edits.allEdits }, canShowWidget, token);\n\t\t\t});\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 { 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 getDefaultBoundCommands(): Map {\n\t\treturn this._defaultBoundCommands;\n\t}\n\n\tpublic getDefaultKeybindings(): readonly ResolvedKeybindingItem[] {\n\t\treturn this._defaultKeybindings;\n\t}\n\n\tpublic getKeybindings(): readonly ResolvedKeybindingItem[] {\n\t\treturn this._keybindings;\n\t}\n\n\tpublic lookupKeybindings(commandId: string): ResolvedKeybindingItem[] {\n\t\tconst items = this._lookupMap.get(commandId);\n\t\tif (typeof items === 'undefined' || items.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\t// Reverse to get the most specific item first\n\t\tconst result: ResolvedKeybindingItem[] = [];\n\t\tlet resultLen = 0;\n\t\tfor (let i = items.length - 1; i >= 0; i--) {\n\t\t\tresult[resultLen++] = items[i];\n\t\t}\n\t\treturn result;\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 * as arrays from 'vs/base/common/arrays';\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 { Keybinding, 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, KeybindingsSchemaContribution } 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 resolveKeybinding(keybinding: Keybinding): ResolvedKeybinding[];\n\tpublic abstract resolveKeyboardEvent(keyboardEvent: IKeyboardEvent): ResolvedKeybinding;\n\tpublic abstract resolveUserBinding(userBinding: string): ResolvedKeybinding[];\n\tpublic abstract registerSchemaContribution(contribution: KeybindingsSchemaContribution): void;\n\tpublic abstract _dumpDebugInfo(): string;\n\tpublic abstract _dumpDebugInfoJSON(): string;\n\n\tpublic getDefaultKeybindingsContent(): string {\n\t\treturn '';\n\t}\n\n\tpublic toggleLogging(): boolean {\n\t\tthis._logging = !this._logging;\n\t\treturn this._logging;\n\t}\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 getDefaultKeybindings(): readonly ResolvedKeybindingItem[] {\n\t\treturn this._getResolver().getDefaultKeybindings();\n\t}\n\n\tpublic getKeybindings(): readonly ResolvedKeybindingItem[] {\n\t\treturn this._getResolver().getKeybindings();\n\t}\n\n\tpublic customKeybindingsCount(): number {\n\t\treturn 0;\n\t}\n\n\tpublic lookupKeybindings(commandId: string): ResolvedKeybinding[] {\n\t\treturn arrays.coalesce(\n\t\t\tthis._getResolver().lookupKeybindings(commandId).map(item => item.resolvedKeybinding)\n\t\t);\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\tpublic dispatchByUserSettingsLabel(userSettingsLabel: string, target: IContextKeyServiceTarget): void {\n\t\tthis._log(`/ Dispatching keybinding triggered via menu entry accelerator - ${userSettingsLabel}`);\n\t\tconst keybindings = this.resolveUserBinding(userSettingsLabel);\n\t\tif (keybindings.length === 0) {\n\t\t\tthis._log(`\\\\ Could not resolve - ${userSettingsLabel}`);\n\t\t} else {\n\t\t\tthis._doDispatch(keybindings[0], target, /*isSingleModiferChord*/false);\n\t\t}\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\tabstract enableKeybindingHoldMode(commandId: string): Promise | undefined;\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 _isWYSIWYG(): boolean {\n\t\treturn true;\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","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { ScanCode, ScanCodeUtils } from 'vs/base/common/keyCodes';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\nimport { IKeyboardEvent } from 'vs/platform/keybinding/common/keybinding';\nimport { IKeyboardMapper } from 'vs/platform/keyboardLayout/common/keyboardMapper';\n\nexport const IKeyboardLayoutService = createDecorator('keyboardLayoutService');\n\nexport interface IWindowsKeyMapping {\n\tvkey: string;\n\tvalue: string;\n\twithShift: string;\n\twithAltGr: string;\n\twithShiftAltGr: string;\n}\nexport interface IWindowsKeyboardMapping {\n\t[code: string]: IWindowsKeyMapping;\n}\nexport interface ILinuxKeyMapping {\n\tvalue: string;\n\twithShift: string;\n\twithAltGr: string;\n\twithShiftAltGr: string;\n}\nexport interface ILinuxKeyboardMapping {\n\t[code: string]: ILinuxKeyMapping;\n}\nexport interface IMacKeyMapping {\n\tvalue: string;\n\tvalueIsDeadKey: boolean;\n\twithShift: string;\n\twithShiftIsDeadKey: boolean;\n\twithAltGr: string;\n\twithAltGrIsDeadKey: boolean;\n\twithShiftAltGr: string;\n\twithShiftAltGrIsDeadKey: boolean;\n}\nexport interface IMacKeyboardMapping {\n\t[code: string]: IMacKeyMapping;\n}\n\nexport type IMacLinuxKeyMapping = IMacKeyMapping | ILinuxKeyMapping;\nexport type IMacLinuxKeyboardMapping = IMacKeyboardMapping | ILinuxKeyboardMapping;\nexport type IKeyboardMapping = IWindowsKeyboardMapping | ILinuxKeyboardMapping | IMacKeyboardMapping;\n\nexport interface IWindowsKeyboardLayoutInfo {\n\tname: string;\n\tid: string;\n\ttext: string;\n}\n\nexport interface ILinuxKeyboardLayoutInfo {\n\tmodel: string;\n\tgroup: number;\n\tlayout: string;\n\tvariant: string;\n\toptions: string;\n\trules: string;\n}\n\nexport interface IMacKeyboardLayoutInfo {\n\tid: string;\n\tlang: string;\n\tlocalizedName?: string;\n}\n\nexport type IKeyboardLayoutInfo = (IWindowsKeyboardLayoutInfo | ILinuxKeyboardLayoutInfo | IMacKeyboardLayoutInfo) & { isUserKeyboardLayout?: boolean; isUSStandard?: true };\n\nexport interface IKeyboardLayoutService {\n\treadonly _serviceBrand: undefined;\n\n\treadonly onDidChangeKeyboardLayout: Event;\n\n\tgetRawKeyboardMapping(): IKeyboardMapping | null;\n\tgetCurrentKeyboardLayout(): IKeyboardLayoutInfo | null;\n\tgetAllKeyboardLayouts(): IKeyboardLayoutInfo[];\n\tgetKeyboardMapper(): IKeyboardMapper;\n\tvalidateCurrentKeyboardMapping(keyboardEvent: IKeyboardEvent): void;\n}\n\nexport function areKeyboardLayoutsEqual(a: IKeyboardLayoutInfo | null, b: IKeyboardLayoutInfo | null): boolean {\n\tif (!a || !b) {\n\t\treturn false;\n\t}\n\n\tif ((a).name && (b).name && (a).name === (b).name) {\n\t\treturn true;\n\t}\n\n\tif ((a).id && (b).id && (a).id === (b).id) {\n\t\treturn true;\n\t}\n\n\tif ((a).model &&\n\t\t(b).model &&\n\t\t(a).model === (b).model &&\n\t\t(a).layout === (b).layout\n\t) {\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\nexport function parseKeyboardLayoutDescription(layout: IKeyboardLayoutInfo | null): { label: string; description: string } {\n\tif (!layout) {\n\t\treturn { label: '', description: '' };\n\t}\n\n\tif ((layout).name) {\n\t\t// windows\n\t\tconst windowsLayout = layout;\n\t\treturn {\n\t\t\tlabel: windowsLayout.text,\n\t\t\tdescription: ''\n\t\t};\n\t}\n\n\tif ((layout).id) {\n\t\tconst macLayout = layout;\n\t\tif (macLayout.localizedName) {\n\t\t\treturn {\n\t\t\t\tlabel: macLayout.localizedName,\n\t\t\t\tdescription: ''\n\t\t\t};\n\t\t}\n\n\t\tif (/^com\\.apple\\.keylayout\\./.test(macLayout.id)) {\n\t\t\treturn {\n\t\t\t\tlabel: macLayout.id.replace(/^com\\.apple\\.keylayout\\./, '').replace(/-/, ' '),\n\t\t\t\tdescription: ''\n\t\t\t};\n\t\t}\n\t\tif (/^.*inputmethod\\./.test(macLayout.id)) {\n\t\t\treturn {\n\t\t\t\tlabel: macLayout.id.replace(/^.*inputmethod\\./, '').replace(/[-\\.]/, ' '),\n\t\t\t\tdescription: `Input Method (${macLayout.lang})`\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tlabel: macLayout.lang,\n\t\t\tdescription: ''\n\t\t};\n\t}\n\n\tconst linuxLayout = layout;\n\n\treturn {\n\t\tlabel: linuxLayout.layout,\n\t\tdescription: ''\n\t};\n}\n\nexport function getKeyboardLayoutId(layout: IKeyboardLayoutInfo): string {\n\tif ((layout).name) {\n\t\treturn (layout).name;\n\t}\n\n\tif ((layout).id) {\n\t\treturn (layout).id;\n\t}\n\n\treturn (layout).layout;\n}\n\nfunction windowsKeyMappingEquals(a: IWindowsKeyMapping, b: IWindowsKeyMapping): boolean {\n\tif (!a && !b) {\n\t\treturn true;\n\t}\n\tif (!a || !b) {\n\t\treturn false;\n\t}\n\treturn (\n\t\ta.vkey === b.vkey\n\t\t&& a.value === b.value\n\t\t&& a.withShift === b.withShift\n\t\t&& a.withAltGr === b.withAltGr\n\t\t&& a.withShiftAltGr === b.withShiftAltGr\n\t);\n}\n\nexport function windowsKeyboardMappingEquals(a: IWindowsKeyboardMapping | null, b: IWindowsKeyboardMapping | null): boolean {\n\tif (!a && !b) {\n\t\treturn true;\n\t}\n\tif (!a || !b) {\n\t\treturn false;\n\t}\n\tfor (let scanCode = 0; scanCode < ScanCode.MAX_VALUE; scanCode++) {\n\t\tconst strScanCode = ScanCodeUtils.toString(scanCode);\n\t\tconst aEntry = a[strScanCode];\n\t\tconst bEntry = b[strScanCode];\n\t\tif (!windowsKeyMappingEquals(aEntry, bEntry)) {\n\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n}\n\nfunction macLinuxKeyMappingEquals(a: IMacLinuxKeyMapping, b: IMacLinuxKeyMapping): boolean {\n\tif (!a && !b) {\n\t\treturn true;\n\t}\n\tif (!a || !b) {\n\t\treturn false;\n\t}\n\treturn (\n\t\ta.value === b.value\n\t\t&& a.withShift === b.withShift\n\t\t&& a.withAltGr === b.withAltGr\n\t\t&& a.withShiftAltGr === b.withShiftAltGr\n\t);\n}\n\nexport function macLinuxKeyboardMappingEquals(a: IMacLinuxKeyboardMapping | null, b: IMacLinuxKeyboardMapping | null): boolean {\n\tif (!a && !b) {\n\t\treturn true;\n\t}\n\tif (!a || !b) {\n\t\treturn false;\n\t}\n\tfor (let scanCode = 0; scanCode < ScanCode.MAX_VALUE; scanCode++) {\n\t\tconst strScanCode = ScanCodeUtils.toString(scanCode);\n\t\tconst aEntry = a[strScanCode];\n\t\tconst bEntry = b[strScanCode];\n\t\tif (!macLinuxKeyMappingEquals(aEntry, bEntry)) {\n\t\t\treturn false;\n\t\t}\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\nimport { ResolvedKeybinding, Keybinding } from 'vs/base/common/keybindings';\nimport { IKeyboardEvent } from 'vs/platform/keybinding/common/keybinding';\n\nexport interface IKeyboardMapper {\n\tdumpDebugInfo(): string;\n\tresolveKeyboardEvent(keyboardEvent: IKeyboardEvent): ResolvedKeybinding;\n\tresolveKeybinding(keybinding: Keybinding): ResolvedKeybinding[];\n}\n\nexport class CachedKeyboardMapper implements IKeyboardMapper {\n\n\tprivate _actual: IKeyboardMapper;\n\tprivate _cache: Map;\n\n\tconstructor(actual: IKeyboardMapper) {\n\t\tthis._actual = actual;\n\t\tthis._cache = new Map();\n\t}\n\n\tpublic dumpDebugInfo(): string {\n\t\treturn this._actual.dumpDebugInfo();\n\t}\n\n\tpublic resolveKeyboardEvent(keyboardEvent: IKeyboardEvent): ResolvedKeybinding {\n\t\treturn this._actual.resolveKeyboardEvent(keyboardEvent);\n\t}\n\n\tpublic resolveKeybinding(keybinding: Keybinding): ResolvedKeybinding[] {\n\t\tconst hashCode = keybinding.getHashCode();\n\t\tconst resolved = this._cache.get(hashCode);\n\t\tif (!resolved) {\n\t\t\tconst r = this._actual.resolveKeybinding(keybinding);\n\t\t\tthis._cache.set(hashCode, r);\n\t\t\treturn r;\n\t\t}\n\t\treturn resolved;\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { createDecorator } from 'vs/platform/instantiation/common/instantiation';\nimport { IWorkspace, ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspace/common/workspace';\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\tgetWorkspaceLabel(workspace: (IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | URI | IWorkspace), options?: { verbose: Verbosity }): string;\n\tgetHostLabel(scheme: string, authority?: string): string;\n\tgetHostTooltip(scheme: string, authority?: string): string | undefined;\n\tgetSeparator(scheme: string, authority?: string): '/' | '\\\\';\n\n\tregisterFormatter(formatter: ResourceLabelFormatter): IDisposable;\n\tonDidChangeFormatters: Event;\n\n\t/**\n\t * Registers a formatter that's cached for the machine beyond the lifecycle\n\t * of the current window. Disposing the formatter _will not_ remove it from\n\t * the cache.\n\t */\n\tregisterCachedFormatter(formatter: ResourceLabelFormatter): IDisposable;\n}\n\nexport const enum Verbosity {\n\tSHORT,\n\tMEDIUM,\n\tLONG\n}\n\nexport interface IFormatterChangeEvent {\n\tscheme: string;\n}\n\nexport interface ResourceLabelFormatter {\n\tscheme: string;\n\tauthority?: string;\n\tpriority?: boolean;\n\tformatting: ResourceLabelFormatting;\n}\n\nexport interface ResourceLabelFormatting {\n\tlabel: string; // myLabel:/${path}\n\tseparator: '/' | '\\\\' | '';\n\ttildify?: boolean;\n\tnormalizeDriveLetter?: boolean;\n\tworkspaceSuffix?: string;\n\tworkspaceTooltip?: string;\n\tauthorityPrefix?: string;\n\tstripPathStartingSeparator?: 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 *--------------------------------------------------------------------------------------------*/\n\nimport { CancellationTokenSource } from 'vs/base/common/cancellation';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { language } from 'vs/base/common/platform';\nimport { URI } from 'vs/base/common/uri';\nimport { IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';\nimport { localize } from 'vs/nls';\nimport { IExtensionGalleryService, IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\n\nexport function getLocale(extension: IGalleryExtension): string | undefined {\n\treturn extension.tags.find(t => t.startsWith('lp-'))?.split('lp-')[1];\n}\n\nexport const ILanguagePackService = createDecorator('languagePackService');\n\nexport interface ILanguagePackItem extends IQuickPickItem {\n\treadonly extensionId?: string;\n\treadonly galleryExtension?: IGalleryExtension;\n}\n\nexport interface ILanguagePackService {\n\treadonly _serviceBrand: undefined;\n\tgetAvailableLanguages(): Promise>;\n\tgetInstalledLanguages(): Promise>;\n\tgetBuiltInExtensionTranslationsUri(id: string, language: string): Promise;\n}\n\nexport abstract class LanguagePackBaseService extends Disposable implements ILanguagePackService {\n\tdeclare readonly _serviceBrand: undefined;\n\n\tconstructor(@IExtensionGalleryService protected readonly extensionGalleryService: IExtensionGalleryService) {\n\t\tsuper();\n\t}\n\n\tabstract getBuiltInExtensionTranslationsUri(id: string, language: string): Promise;\n\n\tabstract getInstalledLanguages(): Promise>;\n\n\tasync getAvailableLanguages(): Promise {\n\t\tconst timeout = new CancellationTokenSource();\n\t\tsetTimeout(() => timeout.cancel(), 1000);\n\n\t\tlet result;\n\t\ttry {\n\t\t\tresult = await this.extensionGalleryService.query({\n\t\t\t\ttext: 'category:\"language packs\"',\n\t\t\t\tpageSize: 20\n\t\t\t}, timeout.token);\n\t\t} catch (_) {\n\t\t\t// This method is best effort. So, we ignore any errors.\n\t\t\treturn [];\n\t\t}\n\n\t\tconst languagePackExtensions = result.firstPage.filter(e => e.properties.localizedLanguages?.length && e.tags.some(t => t.startsWith('lp-')));\n\t\tconst allFromMarketplace: ILanguagePackItem[] = languagePackExtensions.map(lp => {\n\t\t\tconst languageName = lp.properties.localizedLanguages?.[0];\n\t\t\tconst locale = getLocale(lp)!;\n\t\t\tconst baseQuickPick = this.createQuickPickItem(locale, languageName, lp);\n\t\t\treturn {\n\t\t\t\t...baseQuickPick,\n\t\t\t\textensionId: lp.identifier.id,\n\t\t\t\tgalleryExtension: lp\n\t\t\t};\n\t\t});\n\n\t\tallFromMarketplace.push(this.createQuickPickItem('en', 'English'));\n\n\t\treturn allFromMarketplace;\n\t}\n\n\tprotected createQuickPickItem(locale: string, languageName?: string, languagePack?: IGalleryExtension): IQuickPickItem {\n\t\tconst label = languageName ?? locale;\n\t\tlet description: string | undefined;\n\t\tif (label !== locale) {\n\t\t\tdescription = `(${locale})`;\n\t\t}\n\n\t\tif (locale.toLowerCase() === language.toLowerCase()) {\n\t\t\tdescription ??= '';\n\t\t\tdescription += localize('currentDisplayLanguage', \" (Current)\");\n\t\t}\n\n\t\tif (languagePack?.installCount) {\n\t\t\tdescription ??= '';\n\n\t\t\tconst count = languagePack.installCount;\n\t\t\tlet countLabel: string;\n\t\t\tif (count > 1000000) {\n\t\t\t\tcountLabel = `${Math.floor(count / 100000) / 10}M`;\n\t\t\t} else if (count > 1000) {\n\t\t\t\tcountLabel = `${Math.floor(count / 1000)}K`;\n\t\t\t} else {\n\t\t\t\tcountLabel = String(count);\n\t\t\t}\n\t\t\tdescription += ` $(cloud-download) ${countLabel}`;\n\t\t}\n\n\t\treturn {\n\t\t\tid: locale,\n\t\t\tlabel,\n\t\t\tdescription\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\n/**\n * These are some predefined strings that we test during smoke testing that they are localized\n * correctly. Don't change these strings!!\n */\n\nconst open: string = nls.localize('open', 'open');\nconst close: string = nls.localize('close', 'close');\nconst find: string = nls.localize('find', 'find');\n\nexport default {\n\topen: open,\n\tclose: close,\n\tfind: find\n};\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 * 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 * A promise resolved when the stylesheets for the active container have been\n\t * loaded. Aux windows load their styles asynchronously, so there may be\n\t * an initial delay before resolution happens.\n\t */\n\treadonly whenActiveContainerStylesLoaded: Promise;\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 { addDisposableListener } from 'vs/base/browser/dom';\nimport { alert, status } from 'vs/base/browser/ui/aria/aria';\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\talwaysUnderlineAccessKeys(): Promise {\n\t\treturn Promise.resolve(false);\n\t}\n\n\tgetAccessibilitySupport(): AccessibilitySupport {\n\t\treturn this._accessibilitySupport;\n\t}\n\n\tsetAccessibilitySupport(accessibilitySupport: AccessibilitySupport): void {\n\t\tif (this._accessibilitySupport === accessibilitySupport) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._accessibilitySupport = accessibilitySupport;\n\t\tthis._onDidChangeScreenReaderOptimized.fire();\n\t}\n\n\talert(message: string): void {\n\t\talert(message);\n\t}\n\n\tstatus(message: string): void {\n\t\tstatus(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 { ContextView, ContextViewDOMPosition } from 'vs/base/browser/ui/contextview/contextview';\nimport { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle';\nimport { ILayoutService } from 'vs/platform/layout/browser/layoutService';\nimport { IContextViewDelegate, IContextViewService } from './contextView';\nimport { getWindow } from 'vs/base/browser/dom';\n\nexport class ContextViewService extends Disposable implements IContextViewService {\n\n\tdeclare readonly _serviceBrand: undefined;\n\n\tprivate currentViewDisposable: IDisposable = Disposable.None;\n\tprivate 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): IDisposable {\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 disposable = toDisposable(() => {\n\t\t\tif (this.currentViewDisposable === disposable) {\n\t\t\t\tthis.hideContextView();\n\t\t\t}\n\t\t});\n\n\t\tthis.currentViewDisposable = disposable;\n\t\treturn disposable;\n\t}\n\n\tgetContextViewElement(): HTMLElement {\n\t\treturn this.contextView.getViewElement();\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}\n\n\toverride dispose(): void {\n\t\tsuper.dispose();\n\n\t\tthis.currentViewDisposable.dispose();\n\t\tthis.currentViewDisposable = Disposable.None;\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { clearNode, createCSSRule, createStyleSheet } from 'vs/base/browser/dom';\nimport { RunOnceScheduler } from 'vs/base/common/async';\n\nexport enum ZIndex {\n\tBase = 0,\n\tSash = 35,\n\tSuggestWidget = 40,\n\tHover = 50,\n\tDragImage = 1000,\n\tMenubarMenuItemsHolder = 2000, // quick-input-widget\n\tContextView = 2500,\n\tModalDialog = 2600,\n\tPaneDropOverlay = 10000\n}\n\nconst ZIndexValues = Object.keys(ZIndex).filter(key => !isNaN(Number(key))).map(key => Number(key)).sort((a, b) => b - a);\nfunction findBase(z: number) {\n\tfor (const zi of ZIndexValues) {\n\t\tif (z >= zi) {\n\t\t\treturn zi;\n\t\t}\n\t}\n\n\treturn -1;\n}\n\nclass ZIndexRegistry {\n\tprivate styleSheet: HTMLStyleElement;\n\tprivate zIndexMap: Map;\n\tprivate scheduler: RunOnceScheduler;\n\tconstructor() {\n\t\tthis.styleSheet = createStyleSheet();\n\t\tthis.zIndexMap = new Map();\n\t\tthis.scheduler = new RunOnceScheduler(() => this.updateStyleElement(), 200);\n\t}\n\n\tregisterZIndex(relativeLayer: ZIndex, z: number, name: string): string {\n\t\tif (this.zIndexMap.get(name)) {\n\t\t\tthrow new Error(`z-index with name ${name} has already been registered.`);\n\t\t}\n\n\t\tconst proposedZValue = relativeLayer + z;\n\t\tif (findBase(proposedZValue) !== relativeLayer) {\n\t\t\tthrow new Error(`Relative layer: ${relativeLayer} + z-index: ${z} exceeds next layer ${proposedZValue}.`);\n\t\t}\n\n\t\tthis.zIndexMap.set(name, proposedZValue);\n\t\tthis.scheduler.schedule();\n\t\treturn this.getVarName(name);\n\t}\n\n\tprivate getVarName(name: string): string {\n\t\treturn `--z-index-${name}`;\n\t}\n\n\tprivate updateStyleElement(): void {\n\t\tclearNode(this.styleSheet);\n\t\tlet ruleBuilder = '';\n\t\tthis.zIndexMap.forEach((zIndex, name) => {\n\t\t\truleBuilder += `${this.getVarName(name)}: ${zIndex};\\n`;\n\t\t});\n\t\tcreateCSSRule(':root', ruleBuilder, this.styleSheet);\n\t}\n}\n\nconst zIndexRegistry = new ZIndexRegistry();\n\nexport function registerZIndex(relativeLayer: ZIndex, z: number, name: string): string {\n\treturn zIndexRegistry.registerZIndex(relativeLayer, z, name);\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { isThenable, Promises } from 'vs/base/common/async';\n\n// Shared veto handling across main and renderer\nexport function handleVetos(vetos: (boolean | Promise)[], onError: (error: Error) => void): Promise {\n\tif (vetos.length === 0) {\n\t\treturn Promise.resolve(false);\n\t}\n\n\tconst promises: Promise[] = [];\n\tlet lazyValue = false;\n\n\tfor (const valueOrPromise of vetos) {\n\n\t\t// veto, done\n\t\tif (valueOrPromise === true) {\n\t\t\treturn Promise.resolve(true);\n\t\t}\n\n\t\tif (isThenable(valueOrPromise)) {\n\t\t\tpromises.push(valueOrPromise.then(value => {\n\t\t\t\tif (value) {\n\t\t\t\t\tlazyValue = true; // veto, done\n\t\t\t\t}\n\t\t\t}, err => {\n\t\t\t\tonError(err); // error, treated like a veto, done\n\t\t\t\tlazyValue = true;\n\t\t\t}));\n\t\t}\n\t}\n\n\treturn Promises.settled(promises).then(() => lazyValue);\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { toErrorMessage } from 'vs/base/common/errorMessage';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { hash } from 'vs/base/common/hash';\nimport { Disposable, IDisposable } from 'vs/base/common/lifecycle';\nimport { ResourceMap } from 'vs/base/common/map';\nimport { isWindows } from 'vs/base/common/platform';\nimport { joinPath } from 'vs/base/common/resources';\nimport { Mutable, isNumber, isString } from 'vs/base/common/types';\nimport { URI } from 'vs/base/common/uri';\nimport { RawContextKey } from 'vs/platform/contextkey/common/contextkey';\nimport { IEnvironmentService } from 'vs/platform/environment/common/environment';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\n\nexport const ILogService = createDecorator('logService');\nexport const ILoggerService = createDecorator('loggerService');\n\nfunction now(): string {\n\treturn new Date().toISOString();\n}\n\nexport function isLogLevel(thing: unknown): thing is LogLevel {\n\treturn isNumber(thing);\n}\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\t/**\n\t * An operation to flush the contents. Can be synchronous.\n\t */\n\tflush(): void;\n}\n\nexport function log(logger: ILogger, level: LogLevel, message: string): void {\n\tswitch (level) {\n\t\tcase LogLevel.Trace: logger.trace(message); break;\n\t\tcase LogLevel.Debug: logger.debug(message); break;\n\t\tcase LogLevel.Info: logger.info(message); break;\n\t\tcase LogLevel.Warning: logger.warn(message); break;\n\t\tcase LogLevel.Error: logger.error(message); break;\n\t\tcase LogLevel.Off: /* do nothing */ break;\n\t\tdefault: throw new Error(`Invalid log level ${level}`);\n\t}\n}\n\nfunction format(args: any, verbose: boolean = false): string {\n\tlet result = '';\n\n\tfor (let i = 0; i < args.length; i++) {\n\t\tlet a = args[i];\n\n\t\tif (a instanceof Error) {\n\t\t\ta = toErrorMessage(a, verbose);\n\t\t}\n\n\t\tif (typeof a === 'object') {\n\t\t\ttry {\n\t\t\t\ta = JSON.stringify(a);\n\t\t\t} catch (e) { }\n\t\t}\n\n\t\tresult += (i > 0 ? ' ' : '') + a;\n\t}\n\n\treturn result;\n}\n\nexport interface ILogService extends ILogger {\n\treadonly _serviceBrand: undefined;\n}\n\nexport interface ILoggerOptions {\n\n\t/**\n\t * Id of the logger.\n\t */\n\tid?: string;\n\n\t/**\n\t * Name of the logger.\n\t */\n\tname?: string;\n\n\t/**\n\t * Do not create rotating files if max size exceeds.\n\t */\n\tdonotRotate?: boolean;\n\n\t/**\n\t * Do not use formatters.\n\t */\n\tdonotUseFormatters?: boolean;\n\n\t/**\n\t * When to log. Set to `always` to log always.\n\t */\n\tlogLevel?: 'always' | LogLevel;\n\n\t/**\n\t * Whether the log should be hidden from the user.\n\t */\n\thidden?: boolean;\n\n\t/**\n\t * Condition which must be true to show this logger\n\t */\n\twhen?: string;\n\n\t/**\n\t * Id of the extension that created this logger.\n\t */\n\textensionId?: string;\n}\n\nexport interface ILoggerResource {\n\treadonly resource: URI;\n\treadonly id: string;\n\treadonly name?: string;\n\treadonly logLevel?: LogLevel;\n\treadonly hidden?: boolean;\n\treadonly when?: string;\n\treadonly extensionId?: string;\n}\n\nexport type DidChangeLoggersEvent = {\n\treadonly added: Iterable;\n\treadonly removed: Iterable;\n};\n\nexport interface ILoggerService {\n\n\treadonly _serviceBrand: undefined;\n\n\t/**\n\t * Creates a logger for the given resource, or gets one if it already exists.\n\t *\n\t * This will also register the logger with the logger service.\n\t */\n\tcreateLogger(resource: URI, options?: ILoggerOptions): ILogger;\n\n\t/**\n\t * Creates a logger with the given id in the logs folder, or gets one if it already exists.\n\t *\n\t * This will also register the logger with the logger service.\n\t */\n\tcreateLogger(id: string, options?: Omit): ILogger;\n\n\t/**\n\t * Gets an existing logger, if any.\n\t */\n\tgetLogger(resourceOrId: URI | string): ILogger | undefined;\n\n\t/**\n\t * An event which fires when the log level of a logger has changed\n\t */\n\treadonly onDidChangeLogLevel: Event;\n\n\t/**\n\t * Set default log level.\n\t */\n\tsetLogLevel(level: LogLevel): void;\n\n\t/**\n\t * Set log level for a logger.\n\t */\n\tsetLogLevel(resource: URI, level: LogLevel): void;\n\n\t/**\n\t * Get log level for a logger or the default log level.\n\t */\n\tgetLogLevel(resource?: URI): LogLevel;\n\n\t/**\n\t * An event which fires when the visibility of a logger has changed\n\t */\n\treadonly onDidChangeVisibility: Event<[URI, boolean]>;\n\n\t/**\n\t * Set the visibility of a logger.\n\t */\n\tsetVisibility(resourceOrId: URI | string, visible: boolean): void;\n\n\t/**\n\t * An event which fires when the logger resources are changed\n\t */\n\treadonly onDidChangeLoggers: Event;\n\n\t/**\n\t * Register a logger with the logger service.\n\t *\n\t * Note that this will not create a logger, but only register it.\n\t *\n\t * Use `createLogger` to create a logger and register it.\n\t *\n\t * Use it when you want to register a logger that is not created by the logger service.\n\t */\n\tregisterLogger(resource: ILoggerResource): void;\n\n\t/**\n\t * Deregister the logger for the given resource.\n\t */\n\tderegisterLogger(resource: URI): void;\n\n\t/**\n\t * Get all registered loggers\n\t */\n\tgetRegisteredLoggers(): Iterable;\n\n\t/**\n\t * Get the registered logger for the given resource.\n\t */\n\tgetRegisteredLogger(resource: URI): ILoggerResource | 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\tabstract flush(): void;\n}\n\nexport abstract class AbstractMessageLogger extends AbstractLogger implements ILogger {\n\n\tprotected abstract log(level: LogLevel, message: string): void;\n\n\tconstructor(private readonly logAlways?: boolean) {\n\t\tsuper();\n\t}\n\n\tprotected override checkLogLevel(level: LogLevel): boolean {\n\t\treturn this.logAlways || super.checkLogLevel(level);\n\t}\n\n\ttrace(message: string, ...args: any[]): void {\n\t\tif (this.checkLogLevel(LogLevel.Trace)) {\n\t\t\tthis.log(LogLevel.Trace, format([message, ...args], true));\n\t\t}\n\t}\n\n\tdebug(message: string, ...args: any[]): void {\n\t\tif (this.checkLogLevel(LogLevel.Debug)) {\n\t\t\tthis.log(LogLevel.Debug, format([message, ...args]));\n\t\t}\n\t}\n\n\tinfo(message: string, ...args: any[]): void {\n\t\tif (this.checkLogLevel(LogLevel.Info)) {\n\t\t\tthis.log(LogLevel.Info, format([message, ...args]));\n\t\t}\n\t}\n\n\twarn(message: string, ...args: any[]): void {\n\t\tif (this.checkLogLevel(LogLevel.Warning)) {\n\t\t\tthis.log(LogLevel.Warning, format([message, ...args]));\n\t\t}\n\t}\n\n\terror(message: string | Error, ...args: any[]): void {\n\t\tif (this.checkLogLevel(LogLevel.Error)) {\n\n\t\t\tif (message instanceof Error) {\n\t\t\t\tconst array = Array.prototype.slice.call(arguments) as any[];\n\t\t\t\tarray[0] = message.stack;\n\t\t\t\tthis.log(LogLevel.Error, format(array));\n\t\t\t} else {\n\t\t\t\tthis.log(LogLevel.Error, format([message, ...args]));\n\t\t\t}\n\t\t}\n\t}\n\n\tflush(): void { }\n}\n\n\nexport class ConsoleMainLogger extends AbstractLogger implements ILogger {\n\n\tprivate useColors: boolean;\n\n\tconstructor(logLevel: LogLevel = DEFAULT_LOG_LEVEL) {\n\t\tsuper();\n\t\tthis.setLevel(logLevel);\n\t\tthis.useColors = !isWindows;\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(`\\x1b[90m[main ${now()}]\\x1b[0m`, message, ...args);\n\t\t\t} else {\n\t\t\t\tconsole.log(`[main ${now()}]`, 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(`\\x1b[90m[main ${now()}]\\x1b[0m`, message, ...args);\n\t\t\t} else {\n\t\t\t\tconsole.log(`[main ${now()}]`, 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(`\\x1b[90m[main ${now()}]\\x1b[0m`, message, ...args);\n\t\t\t} else {\n\t\t\t\tconsole.log(`[main ${now()}]`, 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.warn(`\\x1b[93m[main ${now()}]\\x1b[0m`, message, ...args);\n\t\t\t} else {\n\t\t\t\tconsole.warn(`[main ${now()}]`, 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.error(`\\x1b[91m[main ${now()}]\\x1b[0m`, message, ...args);\n\t\t\t} else {\n\t\t\t\tconsole.error(`[main ${now()}]`, message, ...args);\n\t\t\t}\n\t\t}\n\t}\n\n\tflush(): void {\n\t\t// noop\n\t}\n\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\n\tflush(): void {\n\t\t// noop\n\t}\n}\n\nexport class AdapterLogger extends AbstractLogger implements ILogger {\n\n\tconstructor(private readonly adapter: { log: (logLevel: LogLevel, args: any[]) => void }, logLevel: LogLevel = DEFAULT_LOG_LEVEL) {\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\tthis.adapter.log(LogLevel.Trace, [this.extractMessage(message), ...args]);\n\t\t}\n\t}\n\n\tdebug(message: string, ...args: any[]): void {\n\t\tif (this.checkLogLevel(LogLevel.Debug)) {\n\t\t\tthis.adapter.log(LogLevel.Debug, [this.extractMessage(message), ...args]);\n\t\t}\n\t}\n\n\tinfo(message: string, ...args: any[]): void {\n\t\tif (this.checkLogLevel(LogLevel.Info)) {\n\t\t\tthis.adapter.log(LogLevel.Info, [this.extractMessage(message), ...args]);\n\t\t}\n\t}\n\n\twarn(message: string | Error, ...args: any[]): void {\n\t\tif (this.checkLogLevel(LogLevel.Warning)) {\n\t\t\tthis.adapter.log(LogLevel.Warning, [this.extractMessage(message), ...args]);\n\t\t}\n\t}\n\n\terror(message: string | Error, ...args: any[]): void {\n\t\tif (this.checkLogLevel(LogLevel.Error)) {\n\t\t\tthis.adapter.log(LogLevel.Error, [this.extractMessage(message), ...args]);\n\t\t}\n\t}\n\n\tprivate extractMessage(msg: string | Error): string {\n\t\tif (typeof msg === 'string') {\n\t\t\treturn msg;\n\t\t}\n\n\t\treturn toErrorMessage(msg, this.checkLogLevel(LogLevel.Trace));\n\t}\n\n\tflush(): void {\n\t\t// noop\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\tflush(): void {\n\t\tfor (const logger of this.loggers) {\n\t\t\tlogger.flush();\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\ntype LoggerEntry = { logger: ILogger | undefined; info: Mutable };\n\nexport abstract class AbstractLoggerService extends Disposable implements ILoggerService {\n\n\tdeclare readonly _serviceBrand: undefined;\n\n\tprivate readonly _loggers = new ResourceMap();\n\n\tprivate _onDidChangeLoggers = this._register(new Emitter<{ added: ILoggerResource[]; removed: ILoggerResource[] }>);\n\treadonly onDidChangeLoggers = this._onDidChangeLoggers.event;\n\n\tprivate _onDidChangeLogLevel = this._register(new Emitter);\n\treadonly onDidChangeLogLevel = this._onDidChangeLogLevel.event;\n\n\tprivate _onDidChangeVisibility = this._register(new Emitter<[URI, boolean]>);\n\treadonly onDidChangeVisibility = this._onDidChangeVisibility.event;\n\n\tconstructor(\n\t\tprotected logLevel: LogLevel,\n\t\tprivate readonly logsHome: URI,\n\t\tloggerResources?: Iterable,\n\t) {\n\t\tsuper();\n\t\tif (loggerResources) {\n\t\t\tfor (const loggerResource of loggerResources) {\n\t\t\t\tthis._loggers.set(loggerResource.resource, { logger: undefined, info: loggerResource });\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate getLoggerEntry(resourceOrId: URI | string): LoggerEntry | undefined {\n\t\tif (isString(resourceOrId)) {\n\t\t\treturn [...this._loggers.values()].find(logger => logger.info.id === resourceOrId);\n\t\t}\n\t\treturn this._loggers.get(resourceOrId);\n\t}\n\n\tgetLogger(resourceOrId: URI | string): ILogger | undefined {\n\t\treturn this.getLoggerEntry(resourceOrId)?.logger;\n\t}\n\n\tcreateLogger(idOrResource: URI | string, options?: ILoggerOptions): ILogger {\n\t\tconst resource = this.toResource(idOrResource);\n\t\tconst id = isString(idOrResource) ? idOrResource : (options?.id ?? hash(resource.toString()).toString(16));\n\t\tlet logger = this._loggers.get(resource)?.logger;\n\t\tconst logLevel = options?.logLevel === 'always' ? LogLevel.Trace : options?.logLevel;\n\t\tif (!logger) {\n\t\t\tlogger = this.doCreateLogger(resource, logLevel ?? this.getLogLevel(resource) ?? this.logLevel, { ...options, id });\n\t\t}\n\t\tconst loggerEntry: LoggerEntry = {\n\t\t\tlogger,\n\t\t\tinfo: { resource, id, logLevel, name: options?.name, hidden: options?.hidden, extensionId: options?.extensionId, when: options?.when }\n\t\t};\n\t\tthis.registerLogger(loggerEntry.info);\n\t\t// TODO: @sandy081 Remove this once registerLogger can take ILogger\n\t\tthis._loggers.set(resource, loggerEntry);\n\t\treturn logger;\n\t}\n\n\tprotected toResource(idOrResource: string | URI): URI {\n\t\treturn isString(idOrResource) ? joinPath(this.logsHome, `${idOrResource}.log`) : idOrResource;\n\t}\n\n\tsetLogLevel(logLevel: LogLevel): void;\n\tsetLogLevel(resource: URI, logLevel: LogLevel): void;\n\tsetLogLevel(arg1: any, arg2?: any): void {\n\t\tif (URI.isUri(arg1)) {\n\t\t\tconst resource = arg1;\n\t\t\tconst logLevel = arg2;\n\t\t\tconst logger = this._loggers.get(resource);\n\t\t\tif (logger && logLevel !== logger.info.logLevel) {\n\t\t\t\tlogger.info.logLevel = logLevel === this.logLevel ? undefined : logLevel;\n\t\t\t\tlogger.logger?.setLevel(logLevel);\n\t\t\t\tthis._loggers.set(logger.info.resource, logger);\n\t\t\t\tthis._onDidChangeLogLevel.fire([resource, logLevel]);\n\t\t\t}\n\t\t} else {\n\t\t\tthis.logLevel = arg1;\n\t\t\tfor (const [resource, logger] of this._loggers.entries()) {\n\t\t\t\tif (this._loggers.get(resource)?.info.logLevel === undefined) {\n\t\t\t\t\tlogger.logger?.setLevel(this.logLevel);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis._onDidChangeLogLevel.fire(this.logLevel);\n\t\t}\n\t}\n\n\tsetVisibility(resourceOrId: URI | string, visibility: boolean): void {\n\t\tconst logger = this.getLoggerEntry(resourceOrId);\n\t\tif (logger && visibility !== !logger.info.hidden) {\n\t\t\tlogger.info.hidden = !visibility;\n\t\t\tthis._loggers.set(logger.info.resource, logger);\n\t\t\tthis._onDidChangeVisibility.fire([logger.info.resource, visibility]);\n\t\t}\n\t}\n\n\tgetLogLevel(resource?: URI): LogLevel {\n\t\tlet logLevel;\n\t\tif (resource) {\n\t\t\tlogLevel = this._loggers.get(resource)?.info.logLevel;\n\t\t}\n\t\treturn logLevel ?? this.logLevel;\n\t}\n\n\tregisterLogger(resource: ILoggerResource): void {\n\t\tconst existing = this._loggers.get(resource.resource);\n\t\tif (existing) {\n\t\t\tif (existing.info.hidden !== resource.hidden) {\n\t\t\t\tthis.setVisibility(resource.resource, !resource.hidden);\n\t\t\t}\n\t\t} else {\n\t\t\tthis._loggers.set(resource.resource, { info: resource, logger: undefined });\n\t\t\tthis._onDidChangeLoggers.fire({ added: [resource], removed: [] });\n\t\t}\n\t}\n\n\tderegisterLogger(resource: URI): void {\n\t\tconst existing = this._loggers.get(resource);\n\t\tif (existing) {\n\t\t\tif (existing.logger) {\n\t\t\t\texisting.logger.dispose();\n\t\t\t}\n\t\t\tthis._loggers.delete(resource);\n\t\t\tthis._onDidChangeLoggers.fire({ added: [], removed: [existing.info] });\n\t\t}\n\t}\n\n\t*getRegisteredLoggers(): Iterable {\n\t\tfor (const entry of this._loggers.values()) {\n\t\t\tyield entry.info;\n\t\t}\n\t}\n\n\tgetRegisteredLogger(resource: URI): ILoggerResource | undefined {\n\t\treturn this._loggers.get(resource)?.info;\n\t}\n\n\toverride dispose(): void {\n\t\tthis._loggers.forEach(logger => logger.logger?.dispose());\n\t\tthis._loggers.clear();\n\t\tsuper.dispose();\n\t}\n\n\tprotected abstract doCreateLogger(resource: URI, logLevel: LogLevel, options?: ILoggerOptions): ILogger;\n}\n\nexport class NullLogger implements ILogger {\n\treadonly onDidChangeLogLevel: Event = new Emitter().event;\n\tsetLevel(level: LogLevel): void { }\n\tgetLevel(): LogLevel { return LogLevel.Info; }\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\tcritical(message: string | Error, ...args: any[]): void { }\n\tdispose(): void { }\n\tflush(): void { }\n}\n\nexport class NullLogService extends NullLogger implements ILogService {\n\tdeclare readonly _serviceBrand: undefined;\n}\n\nexport function getLogLevel(environmentService: IEnvironmentService): LogLevel {\n\tif (environmentService.verbose) {\n\t\treturn LogLevel.Trace;\n\t}\n\tif (typeof environmentService.logLevel === 'string') {\n\t\tconst logLevel = parseLogLevel(environmentService.logLevel.toLowerCase());\n\t\tif (logLevel !== undefined) {\n\t\t\treturn logLevel;\n\t\t}\n\t}\n\treturn DEFAULT_LOG_LEVEL;\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\nexport function parseLogLevel(logLevel: string): LogLevel | undefined {\n\tswitch (logLevel) {\n\t\tcase 'trace':\n\t\t\treturn LogLevel.Trace;\n\t\tcase 'debug':\n\t\t\treturn LogLevel.Debug;\n\t\tcase 'info':\n\t\t\treturn LogLevel.Info;\n\t\tcase 'warn':\n\t\t\treturn LogLevel.Warning;\n\t\tcase 'error':\n\t\t\treturn LogLevel.Error;\n\t\tcase 'critical':\n\t\t\treturn LogLevel.Error;\n\t\tcase 'off':\n\t\t\treturn LogLevel.Off;\n\t}\n\treturn undefined;\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\tdata: string;\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 onKeyPress: Event;\n\treadonly onKeyUp: Event;\n\treadonly onCompositionStart: Event;\n\treadonly onCompositionUpdate: Event;\n\treadonly onCompositionEnd: Event;\n\treadonly onBeforeInput: 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 _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\t_initializeFromTest(): void {\n\t\tthis._hasFocus = true;\n\t\tthis._textAreaState = TextAreaState.readFromTextArea(this._textArea, null);\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 onKeyPress = this._register(new DomEmitter(this._actual, 'keypress')).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 { binarySearch, coalesceInPlace, 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 { commonPrefixLength } from 'vs/base/common/strings';\nimport { URI } from 'vs/base/common/uri';\nimport { IPosition, Position } from 'vs/editor/common/core/position';\nimport { IRange, Range } from 'vs/editor/common/core/range';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { DocumentSymbol, DocumentSymbolProvider } from 'vs/editor/common/languages';\nimport { MarkerSeverity } from 'vs/platform/markers/common/markers';\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 getElementById(id: string, element: TreeElement): TreeElement | undefined {\n\t\tif (!id) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst len = commonPrefixLength(id, element.id);\n\t\tif (len === id.length) {\n\t\t\treturn element;\n\t\t}\n\t\tif (len < element.id.length) {\n\t\t\treturn undefined;\n\t\t}\n\t\tfor (const [, child] of element.children) {\n\t\t\tconst candidate = TreeElement.getElementById(id, child);\n\t\t\tif (candidate) {\n\t\t\t\treturn candidate;\n\t\t\t}\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tstatic size(element: TreeElement): number {\n\t\tlet res = 1;\n\t\tfor (const [, child] of element.children) {\n\t\t\tres += TreeElement.size(child);\n\t\t}\n\t\treturn res;\n\t}\n\n\tstatic empty(element: TreeElement): boolean {\n\t\treturn element.children.size === 0;\n\t}\n}\n\nexport interface IOutlineMarker {\n\tstartLineNumber: number;\n\tstartColumn: number;\n\tendLineNumber: number;\n\tendColumn: number;\n\tseverity: MarkerSeverity;\n}\n\nexport class OutlineElement extends TreeElement {\n\n\tchildren = new Map();\n\tmarker: { count: number; topSev: MarkerSeverity } | undefined;\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\tgetItemEnclosingPosition(position: IPosition): OutlineElement | undefined {\n\t\treturn position ? this._getItemEnclosingPosition(position, this.children) : undefined;\n\t}\n\n\tprivate _getItemEnclosingPosition(position: IPosition, children: Map): OutlineElement | undefined {\n\t\tfor (const [, item] of children) {\n\t\t\tif (!item.symbol.range || !Range.containsPosition(item.symbol.range, position)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\treturn this._getItemEnclosingPosition(position, item.children) || item;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tupdateMarker(marker: IOutlineMarker[]): void {\n\t\tfor (const [, child] of this.children) {\n\t\t\tthis._updateMarker(marker, child);\n\t\t}\n\t}\n\n\tprivate _updateMarker(markers: IOutlineMarker[], item: OutlineElement): void {\n\t\titem.marker = undefined;\n\n\t\t// find the proper start index to check for item/marker overlap.\n\t\tconst idx = binarySearch(markers, item.symbol.range, Range.compareRangesUsingStarts);\n\t\tlet start: number;\n\t\tif (idx < 0) {\n\t\t\tstart = ~idx;\n\t\t\tif (start > 0 && Range.areIntersecting(markers[start - 1], item.symbol.range)) {\n\t\t\t\tstart -= 1;\n\t\t\t}\n\t\t} else {\n\t\t\tstart = idx;\n\t\t}\n\n\t\tconst myMarkers: IOutlineMarker[] = [];\n\t\tlet myTopSev: MarkerSeverity | undefined;\n\n\t\tfor (; start < markers.length && Range.areIntersecting(item.symbol.range, markers[start]); start++) {\n\t\t\t// remove markers intersecting with this outline element\n\t\t\t// and store them in a 'private' array.\n\t\t\tconst marker = markers[start];\n\t\t\tmyMarkers.push(marker);\n\t\t\t(markers as Array)[start] = undefined;\n\t\t\tif (!myTopSev || marker.severity > myTopSev) {\n\t\t\t\tmyTopSev = marker.severity;\n\t\t\t}\n\t\t}\n\n\t\t// Recurse into children and let them match markers that have matched\n\t\t// this outline element. This might remove markers from this element and\n\t\t// therefore we remember that we have had markers. That allows us to render\n\t\t// the dot, saying 'this element has children with markers'\n\t\tfor (const [, child] of item.children) {\n\t\t\tthis._updateMarker(myMarkers, child);\n\t\t}\n\n\t\tif (myTopSev) {\n\t\t\titem.marker = {\n\t\t\t\tcount: myMarkers.length,\n\t\t\t\ttopSev: myTopSev\n\t\t\t};\n\t\t}\n\n\t\tcoalesceInPlace(markers);\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\tstatic get(element: TreeElement | undefined): OutlineModel | undefined {\n\t\twhile (element) {\n\t\t\tif (element instanceof OutlineModel) {\n\t\t\t\treturn element;\n\t\t\t}\n\t\t\telement = element.parent;\n\t\t}\n\t\treturn undefined;\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\tmerge(other: OutlineModel): boolean {\n\t\tif (this.uri.toString() !== other.uri.toString()) {\n\t\t\treturn false;\n\t\t}\n\t\tif (this._groups.size !== other._groups.size) {\n\t\t\treturn false;\n\t\t}\n\t\tthis._groups = other._groups;\n\t\tthis.children = other.children;\n\t\treturn true;\n\t}\n\n\tgetItemEnclosingPosition(position: IPosition, context?: OutlineElement): OutlineElement | undefined {\n\n\t\tlet preferredGroup: OutlineGroup | undefined;\n\t\tif (context) {\n\t\t\tlet candidate = context.parent;\n\t\t\twhile (candidate && !preferredGroup) {\n\t\t\t\tif (candidate instanceof OutlineGroup) {\n\t\t\t\t\tpreferredGroup = candidate;\n\t\t\t\t}\n\t\t\t\tcandidate = candidate.parent;\n\t\t\t}\n\t\t}\n\n\t\tlet result: OutlineElement | undefined = undefined;\n\t\tfor (const [, group] of this._groups) {\n\t\t\tresult = group.getItemEnclosingPosition(position);\n\t\t\tif (result && (!preferredGroup || preferredGroup === group)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tgetItemById(id: string): TreeElement | undefined {\n\t\treturn TreeElement.getElementById(id, this);\n\t}\n\n\tupdateMarker(marker: IOutlineMarker[]): void {\n\t\t// sort markers by start range so that we can use\n\t\t// outline element starts for quicker look up\n\t\tmarker.sort(Range.compareRangesUsingStarts);\n\n\t\tfor (const [, group] of this._groups) {\n\t\t\tgroup.updateMarker(marker.slice(0));\n\t\t}\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\tgetDebounceValue(textModel: ITextModel): number;\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\tgetDebounceValue(textModel: ITextModel): number {\n\t\treturn this._debounceInformation.get(textModel);\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, 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\tnavigator.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 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 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\tasync hasResources(): Promise {\n\t\treturn this.resources.length > 0;\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 { coalesce } from 'vs/base/common/arrays';\nimport { Promises, ResourceQueue } from 'vs/base/common/async';\nimport { bufferedStreamToBuffer, bufferToReadable, newWriteableBufferStream, readableToBuffer, streamToBuffer, VSBuffer, VSBufferReadable, VSBufferReadableBufferedStream, VSBufferReadableStream } from 'vs/base/common/buffer';\nimport { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';\nimport { Emitter } from 'vs/base/common/event';\nimport { hash } from 'vs/base/common/hash';\nimport { Iterable } from 'vs/base/common/iterator';\nimport { Disposable, DisposableStore, dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle';\nimport { TernarySearchTree } from 'vs/base/common/ternarySearchTree';\nimport { Schemas } from 'vs/base/common/network';\nimport { mark } from 'vs/base/common/performance';\nimport { extUri, extUriIgnorePathCase, IExtUri, isAbsolutePath } from 'vs/base/common/resources';\nimport { consumeStream, isReadableBufferedStream, isReadableStream, listenStream, newWriteableStream, peekReadable, peekStream, transform } from 'vs/base/common/stream';\nimport { URI } from 'vs/base/common/uri';\nimport { localize } from 'vs/nls';\nimport { ensureFileSystemProviderError, etag, ETAG_DISABLED, FileChangesEvent, IFileDeleteOptions, FileOperation, FileOperationError, FileOperationEvent, FileOperationResult, FilePermission, FileSystemProviderCapabilities, FileSystemProviderErrorCode, FileType, hasFileAtomicReadCapability, hasFileFolderCopyCapability, hasFileReadStreamCapability, hasOpenReadWriteCloseCapability, hasReadWriteCapability, ICreateFileOptions, IFileContent, IFileService, IFileStat, IFileStatWithMetadata, IFileStreamContent, IFileSystemProvider, IFileSystemProviderActivationEvent, IFileSystemProviderCapabilitiesChangeEvent, IFileSystemProviderRegistrationEvent, IFileSystemProviderWithFileAtomicReadCapability, IFileSystemProviderWithFileReadStreamCapability, IFileSystemProviderWithFileReadWriteCapability, IFileSystemProviderWithOpenReadWriteCloseCapability, IReadFileOptions, IReadFileStreamOptions, IResolveFileOptions, IFileStatResult, IFileStatResultWithMetadata, IResolveMetadataFileOptions, IStat, IFileStatWithPartialMetadata, IWatchOptions, IWriteFileOptions, NotModifiedSinceFileOperationError, toFileOperationResult, toFileSystemProviderErrorCode, hasFileCloneCapability, TooLargeFileOperationError, hasFileAtomicDeleteCapability, hasFileAtomicWriteCapability, IWatchOptionsWithCorrelation, IFileSystemWatcher, IWatchOptionsWithoutCorrelation } from 'vs/platform/files/common/files';\nimport { readFileIntoStream } from 'vs/platform/files/common/io';\nimport { ILogService } from 'vs/platform/log/common/log';\nimport { ErrorNoTelemetry } from 'vs/base/common/errors';\n\nexport class FileService extends Disposable implements IFileService {\n\n\tdeclare readonly _serviceBrand: undefined;\n\n\t// Choose a buffer size that is a balance between memory needs and\n\t// manageable IPC overhead. The larger the buffer size, the less\n\t// roundtrips we have to do for reading/writing data.\n\tprivate readonly BUFFER_SIZE = 256 * 1024;\n\n\tconstructor(@ILogService private readonly logService: ILogService) {\n\t\tsuper();\n\t}\n\n\t//#region File System Provider\n\n\tprivate readonly _onDidChangeFileSystemProviderRegistrations = this._register(new Emitter());\n\treadonly onDidChangeFileSystemProviderRegistrations = this._onDidChangeFileSystemProviderRegistrations.event;\n\n\tprivate readonly _onWillActivateFileSystemProvider = this._register(new Emitter());\n\treadonly onWillActivateFileSystemProvider = this._onWillActivateFileSystemProvider.event;\n\n\tprivate readonly _onDidChangeFileSystemProviderCapabilities = this._register(new Emitter());\n\treadonly onDidChangeFileSystemProviderCapabilities = this._onDidChangeFileSystemProviderCapabilities.event;\n\n\tprivate readonly provider = new Map();\n\n\tregisterProvider(scheme: string, provider: IFileSystemProvider): IDisposable {\n\t\tif (this.provider.has(scheme)) {\n\t\t\tthrow new Error(`A filesystem provider for the scheme '${scheme}' is already registered.`);\n\t\t}\n\n\t\tmark(`code/registerFilesystem/${scheme}`);\n\n\t\tconst providerDisposables = new DisposableStore();\n\n\t\t// Add provider with event\n\t\tthis.provider.set(scheme, provider);\n\t\tthis._onDidChangeFileSystemProviderRegistrations.fire({ added: true, scheme, provider });\n\n\t\t// Forward events from provider\n\t\tproviderDisposables.add(provider.onDidChangeFile(changes => {\n\t\t\tconst event = new FileChangesEvent(changes, !this.isPathCaseSensitive(provider));\n\n\t\t\t// Always emit any event internally\n\t\t\tthis.internalOnDidFilesChange.fire(event);\n\n\t\t\t// Only emit uncorrelated events in the global `onDidFilesChange` event\n\t\t\tif (!event.hasCorrelation()) {\n\t\t\t\tthis._onDidUncorrelatedFilesChange.fire(event);\n\t\t\t}\n\t\t}));\n\t\tif (typeof provider.onDidWatchError === 'function') {\n\t\t\tproviderDisposables.add(provider.onDidWatchError(error => this._onDidWatchError.fire(new Error(error))));\n\t\t}\n\t\tproviderDisposables.add(provider.onDidChangeCapabilities(() => this._onDidChangeFileSystemProviderCapabilities.fire({ provider, scheme })));\n\n\t\treturn toDisposable(() => {\n\t\t\tthis._onDidChangeFileSystemProviderRegistrations.fire({ added: false, scheme, provider });\n\t\t\tthis.provider.delete(scheme);\n\n\t\t\tdispose(providerDisposables);\n\t\t});\n\t}\n\n\tgetProvider(scheme: string): IFileSystemProvider | undefined {\n\t\treturn this.provider.get(scheme);\n\t}\n\n\tasync activateProvider(scheme: string): Promise {\n\n\t\t// Emit an event that we are about to activate a provider with the given scheme.\n\t\t// Listeners can participate in the activation by registering a provider for it.\n\t\tconst joiners: Promise[] = [];\n\t\tthis._onWillActivateFileSystemProvider.fire({\n\t\t\tscheme,\n\t\t\tjoin(promise) {\n\t\t\t\tjoiners.push(promise);\n\t\t\t},\n\t\t});\n\n\t\tif (this.provider.has(scheme)) {\n\t\t\treturn; // provider is already here so we can return directly\n\t\t}\n\n\t\t// If the provider is not yet there, make sure to join on the listeners assuming\n\t\t// that it takes a bit longer to register the file system provider.\n\t\tawait Promises.settled(joiners);\n\t}\n\n\tasync canHandleResource(resource: URI): Promise {\n\n\t\t// Await activation of potentially extension contributed providers\n\t\tawait this.activateProvider(resource.scheme);\n\n\t\treturn this.hasProvider(resource);\n\t}\n\n\thasProvider(resource: URI): boolean {\n\t\treturn this.provider.has(resource.scheme);\n\t}\n\n\thasCapability(resource: URI, capability: FileSystemProviderCapabilities): boolean {\n\t\tconst provider = this.provider.get(resource.scheme);\n\n\t\treturn !!(provider && (provider.capabilities & capability));\n\t}\n\n\tlistCapabilities(): Iterable<{ scheme: string; capabilities: FileSystemProviderCapabilities }> {\n\t\treturn Iterable.map(this.provider, ([scheme, provider]) => ({ scheme, capabilities: provider.capabilities }));\n\t}\n\n\tprotected async withProvider(resource: URI): Promise {\n\n\t\t// Assert path is absolute\n\t\tif (!isAbsolutePath(resource)) {\n\t\t\tthrow new FileOperationError(localize('invalidPath', \"Unable to resolve filesystem provider with relative file path '{0}'\", this.resourceForError(resource)), FileOperationResult.FILE_INVALID_PATH);\n\t\t}\n\n\t\t// Activate provider\n\t\tawait this.activateProvider(resource.scheme);\n\n\t\t// Assert provider\n\t\tconst provider = this.provider.get(resource.scheme);\n\t\tif (!provider) {\n\t\t\tconst error = new ErrorNoTelemetry();\n\t\t\terror.message = localize('noProviderFound', \"ENOPRO: No file system provider found for resource '{0}'\", resource.toString());\n\n\t\t\tthrow error;\n\t\t}\n\n\t\treturn provider;\n\t}\n\n\tprivate async withReadProvider(resource: URI): Promise {\n\t\tconst provider = await this.withProvider(resource);\n\n\t\tif (hasOpenReadWriteCloseCapability(provider) || hasReadWriteCapability(provider) || hasFileReadStreamCapability(provider)) {\n\t\t\treturn provider;\n\t\t}\n\n\t\tthrow new Error(`Filesystem provider for scheme '${resource.scheme}' neither has FileReadWrite, FileReadStream nor FileOpenReadWriteClose capability which is needed for the read operation.`);\n\t}\n\n\tprivate async withWriteProvider(resource: URI): Promise {\n\t\tconst provider = await this.withProvider(resource);\n\n\t\tif (hasOpenReadWriteCloseCapability(provider) || hasReadWriteCapability(provider)) {\n\t\t\treturn provider;\n\t\t}\n\n\t\tthrow new Error(`Filesystem provider for scheme '${resource.scheme}' neither has FileReadWrite nor FileOpenReadWriteClose capability which is needed for the write operation.`);\n\t}\n\n\t//#endregion\n\n\t//#region Operation events\n\n\tprivate readonly _onDidRunOperation = this._register(new Emitter());\n\treadonly onDidRunOperation = this._onDidRunOperation.event;\n\n\t//#endregion\n\n\t//#region File Metadata Resolving\n\n\tasync resolve(resource: URI, options: IResolveMetadataFileOptions): Promise;\n\tasync resolve(resource: URI, options?: IResolveFileOptions): Promise;\n\tasync resolve(resource: URI, options?: IResolveFileOptions): Promise {\n\t\ttry {\n\t\t\treturn await this.doResolveFile(resource, options);\n\t\t} catch (error) {\n\n\t\t\t// Specially handle file not found case as file operation result\n\t\t\tif (toFileSystemProviderErrorCode(error) === FileSystemProviderErrorCode.FileNotFound) {\n\t\t\t\tthrow new FileOperationError(localize('fileNotFoundError', \"Unable to resolve nonexistent file '{0}'\", this.resourceForError(resource)), FileOperationResult.FILE_NOT_FOUND);\n\t\t\t}\n\n\t\t\t// Bubble up any other error as is\n\t\t\tthrow ensureFileSystemProviderError(error);\n\t\t}\n\t}\n\n\tprivate async doResolveFile(resource: URI, options: IResolveMetadataFileOptions): Promise;\n\tprivate async doResolveFile(resource: URI, options?: IResolveFileOptions): Promise;\n\tprivate async doResolveFile(resource: URI, options?: IResolveFileOptions): Promise {\n\t\tconst provider = await this.withProvider(resource);\n\t\tconst isPathCaseSensitive = this.isPathCaseSensitive(provider);\n\n\t\tconst resolveTo = options?.resolveTo;\n\t\tconst resolveSingleChildDescendants = options?.resolveSingleChildDescendants;\n\t\tconst resolveMetadata = options?.resolveMetadata;\n\n\t\tconst stat = await provider.stat(resource);\n\n\t\tlet trie: TernarySearchTree | undefined;\n\n\t\treturn this.toFileStat(provider, resource, stat, undefined, !!resolveMetadata, (stat, siblings) => {\n\n\t\t\t// lazy trie to check for recursive resolving\n\t\t\tif (!trie) {\n\t\t\t\ttrie = TernarySearchTree.forUris(() => !isPathCaseSensitive);\n\t\t\t\ttrie.set(resource, true);\n\t\t\t\tif (resolveTo) {\n\t\t\t\t\ttrie.fill(true, resolveTo);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// check for recursive resolving\n\t\t\tif (trie.get(stat.resource) || trie.findSuperstr(stat.resource.with({ query: null, fragment: null } /* required for https://github.com/microsoft/vscode/issues/128151 */))) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\t// check for resolving single child folders\n\t\t\tif (stat.isDirectory && resolveSingleChildDescendants) {\n\t\t\t\treturn siblings === 1;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t});\n\t}\n\n\tprivate async toFileStat(provider: IFileSystemProvider, resource: URI, stat: IStat | { type: FileType } & Partial, siblings: number | undefined, resolveMetadata: boolean, recurse: (stat: IFileStat, siblings?: number) => boolean): Promise;\n\tprivate async toFileStat(provider: IFileSystemProvider, resource: URI, stat: IStat, siblings: number | undefined, resolveMetadata: true, recurse: (stat: IFileStat, siblings?: number) => boolean): Promise;\n\tprivate async toFileStat(provider: IFileSystemProvider, resource: URI, stat: IStat | { type: FileType } & Partial, siblings: number | undefined, resolveMetadata: boolean, recurse: (stat: IFileStat, siblings?: number) => boolean): Promise {\n\t\tconst { providerExtUri } = this.getExtUri(provider);\n\n\t\t// convert to file stat\n\t\tconst fileStat: IFileStat = {\n\t\t\tresource,\n\t\t\tname: providerExtUri.basename(resource),\n\t\t\tisFile: (stat.type & FileType.File) !== 0,\n\t\t\tisDirectory: (stat.type & FileType.Directory) !== 0,\n\t\t\tisSymbolicLink: (stat.type & FileType.SymbolicLink) !== 0,\n\t\t\tmtime: stat.mtime,\n\t\t\tctime: stat.ctime,\n\t\t\tsize: stat.size,\n\t\t\treadonly: Boolean((stat.permissions ?? 0) & FilePermission.Readonly) || Boolean(provider.capabilities & FileSystemProviderCapabilities.Readonly),\n\t\t\tlocked: Boolean((stat.permissions ?? 0) & FilePermission.Locked),\n\t\t\tetag: etag({ mtime: stat.mtime, size: stat.size }),\n\t\t\tchildren: undefined\n\t\t};\n\n\t\t// check to recurse for directories\n\t\tif (fileStat.isDirectory && recurse(fileStat, siblings)) {\n\t\t\ttry {\n\t\t\t\tconst entries = await provider.readdir(resource);\n\t\t\t\tconst resolvedEntries = await Promises.settled(entries.map(async ([name, type]) => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst childResource = providerExtUri.joinPath(resource, name);\n\t\t\t\t\t\tconst childStat = resolveMetadata ? await provider.stat(childResource) : { type };\n\n\t\t\t\t\t\treturn await this.toFileStat(provider, childResource, childStat, entries.length, resolveMetadata, recurse);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tthis.logService.trace(error);\n\n\t\t\t\t\t\treturn null; // can happen e.g. due to permission errors\n\t\t\t\t\t}\n\t\t\t\t}));\n\n\t\t\t\t// make sure to get rid of null values that signal a failure to resolve a particular entry\n\t\t\t\tfileStat.children = coalesce(resolvedEntries);\n\t\t\t} catch (error) {\n\t\t\t\tthis.logService.trace(error);\n\n\t\t\t\tfileStat.children = []; // gracefully handle errors, we may not have permissions to read\n\t\t\t}\n\n\t\t\treturn fileStat;\n\t\t}\n\n\t\treturn fileStat;\n\t}\n\n\tasync resolveAll(toResolve: { resource: URI; options?: IResolveFileOptions }[]): Promise;\n\tasync resolveAll(toResolve: { resource: URI; options: IResolveMetadataFileOptions }[]): Promise;\n\tasync resolveAll(toResolve: { resource: URI; options?: IResolveFileOptions }[]): Promise {\n\t\treturn Promises.settled(toResolve.map(async entry => {\n\t\t\ttry {\n\t\t\t\treturn { stat: await this.doResolveFile(entry.resource, entry.options), success: true };\n\t\t\t} catch (error) {\n\t\t\t\tthis.logService.trace(error);\n\n\t\t\t\treturn { stat: undefined, success: false };\n\t\t\t}\n\t\t}));\n\t}\n\n\tasync stat(resource: URI): Promise {\n\t\tconst provider = await this.withProvider(resource);\n\n\t\tconst stat = await provider.stat(resource);\n\n\t\treturn this.toFileStat(provider, resource, stat, undefined, true, () => false /* Do not resolve any children */);\n\t}\n\n\tasync exists(resource: URI): Promise {\n\t\tconst provider = await this.withProvider(resource);\n\n\t\ttry {\n\t\t\tconst stat = await provider.stat(resource);\n\n\t\t\treturn !!stat;\n\t\t} catch (error) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t//#endregion\n\n\t//#region File Reading/Writing\n\n\tasync canCreateFile(resource: URI, options?: ICreateFileOptions): Promise {\n\t\ttry {\n\t\t\tawait this.doValidateCreateFile(resource, options);\n\t\t} catch (error) {\n\t\t\treturn error;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tprivate async doValidateCreateFile(resource: URI, options?: ICreateFileOptions): Promise {\n\n\t\t// validate overwrite\n\t\tif (!options?.overwrite && await this.exists(resource)) {\n\t\t\tthrow new FileOperationError(localize('fileExists', \"Unable to create file '{0}' that already exists when overwrite flag is not set\", this.resourceForError(resource)), FileOperationResult.FILE_MODIFIED_SINCE, options);\n\t\t}\n\t}\n\n\tasync createFile(resource: URI, bufferOrReadableOrStream: VSBuffer | VSBufferReadable | VSBufferReadableStream = VSBuffer.fromString(''), options?: ICreateFileOptions): Promise {\n\n\t\t// validate\n\t\tawait this.doValidateCreateFile(resource, options);\n\n\t\t// do write into file (this will create it too)\n\t\tconst fileStat = await this.writeFile(resource, bufferOrReadableOrStream);\n\n\t\t// events\n\t\tthis._onDidRunOperation.fire(new FileOperationEvent(resource, FileOperation.CREATE, fileStat));\n\n\t\treturn fileStat;\n\t}\n\n\tasync writeFile(resource: URI, bufferOrReadableOrStream: VSBuffer | VSBufferReadable | VSBufferReadableStream, options?: IWriteFileOptions): Promise {\n\t\tconst provider = this.throwIfFileSystemIsReadonly(await this.withWriteProvider(resource), resource);\n\t\tconst { providerExtUri } = this.getExtUri(provider);\n\n\t\tlet writeFileOptions = options;\n\t\tif (hasFileAtomicWriteCapability(provider) && !writeFileOptions?.atomic) {\n\t\t\tconst enforcedAtomicWrite = provider.enforceAtomicWriteFile?.(resource);\n\t\t\tif (enforcedAtomicWrite) {\n\t\t\t\twriteFileOptions = { ...options, atomic: enforcedAtomicWrite };\n\t\t\t}\n\t\t}\n\n\t\ttry {\n\n\t\t\t// validate write\n\t\t\tconst stat = await this.validateWriteFile(provider, resource, writeFileOptions);\n\n\t\t\t// mkdir recursively as needed\n\t\t\tif (!stat) {\n\t\t\t\tawait this.mkdirp(provider, providerExtUri.dirname(resource));\n\t\t\t}\n\n\t\t\t// optimization: if the provider has unbuffered write capability and the data\n\t\t\t// to write is not a buffer, we consume up to 3 chunks and try to write the data\n\t\t\t// unbuffered to reduce the overhead. If the stream or readable has more data\n\t\t\t// to provide we continue to write buffered.\n\t\t\tlet bufferOrReadableOrStreamOrBufferedStream: VSBuffer | VSBufferReadable | VSBufferReadableStream | VSBufferReadableBufferedStream;\n\t\t\tif (hasReadWriteCapability(provider) && !(bufferOrReadableOrStream instanceof VSBuffer)) {\n\t\t\t\tif (isReadableStream(bufferOrReadableOrStream)) {\n\t\t\t\t\tconst bufferedStream = await peekStream(bufferOrReadableOrStream, 3);\n\t\t\t\t\tif (bufferedStream.ended) {\n\t\t\t\t\t\tbufferOrReadableOrStreamOrBufferedStream = VSBuffer.concat(bufferedStream.buffer);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tbufferOrReadableOrStreamOrBufferedStream = bufferedStream;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tbufferOrReadableOrStreamOrBufferedStream = peekReadable(bufferOrReadableOrStream, data => VSBuffer.concat(data), 3);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tbufferOrReadableOrStreamOrBufferedStream = bufferOrReadableOrStream;\n\t\t\t}\n\n\t\t\t// write file: unbuffered\n\t\t\tif (\n\t\t\t\t!hasOpenReadWriteCloseCapability(provider) ||\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// buffered writing is unsupported\n\t\t\t\t(hasReadWriteCapability(provider) && bufferOrReadableOrStreamOrBufferedStream instanceof VSBuffer) ||\t\t// data is a full buffer already\n\t\t\t\t(hasReadWriteCapability(provider) && hasFileAtomicWriteCapability(provider) && writeFileOptions?.atomic)\t// atomic write forces unbuffered write if the provider supports it\n\t\t\t) {\n\t\t\t\tawait this.doWriteUnbuffered(provider, resource, writeFileOptions, bufferOrReadableOrStreamOrBufferedStream);\n\t\t\t}\n\n\t\t\t// write file: buffered\n\t\t\telse {\n\t\t\t\tawait this.doWriteBuffered(provider, resource, writeFileOptions, bufferOrReadableOrStreamOrBufferedStream instanceof VSBuffer ? bufferToReadable(bufferOrReadableOrStreamOrBufferedStream) : bufferOrReadableOrStreamOrBufferedStream);\n\t\t\t}\n\n\t\t\t// events\n\t\t\tthis._onDidRunOperation.fire(new FileOperationEvent(resource, FileOperation.WRITE));\n\t\t} catch (error) {\n\t\t\tthrow new FileOperationError(localize('err.write', \"Unable to write file '{0}' ({1})\", this.resourceForError(resource), ensureFileSystemProviderError(error).toString()), toFileOperationResult(error), writeFileOptions);\n\t\t}\n\n\t\treturn this.resolve(resource, { resolveMetadata: true });\n\t}\n\n\tprivate async validateWriteFile(provider: IFileSystemProvider, resource: URI, options?: IWriteFileOptions): Promise {\n\n\t\t// Validate unlock support\n\t\tconst unlock = !!options?.unlock;\n\t\tif (unlock && !(provider.capabilities & FileSystemProviderCapabilities.FileWriteUnlock)) {\n\t\t\tthrow new Error(localize('writeFailedUnlockUnsupported', \"Unable to unlock file '{0}' because provider does not support it.\", this.resourceForError(resource)));\n\t\t}\n\n\t\t// Validate atomic support\n\t\tconst atomic = !!options?.atomic;\n\t\tif (atomic) {\n\t\t\tif (!(provider.capabilities & FileSystemProviderCapabilities.FileAtomicWrite)) {\n\t\t\t\tthrow new Error(localize('writeFailedAtomicUnsupported1', \"Unable to atomically write file '{0}' because provider does not support it.\", this.resourceForError(resource)));\n\t\t\t}\n\n\t\t\tif (!(provider.capabilities & FileSystemProviderCapabilities.FileReadWrite)) {\n\t\t\t\tthrow new Error(localize('writeFailedAtomicUnsupported2', \"Unable to atomically write file '{0}' because provider does not support unbuffered writes.\", this.resourceForError(resource)));\n\t\t\t}\n\n\t\t\tif (unlock) {\n\t\t\t\tthrow new Error(localize('writeFailedAtomicUnlock', \"Unable to unlock file '{0}' because atomic write is enabled.\", this.resourceForError(resource)));\n\t\t\t}\n\t\t}\n\n\t\t// Validate via file stat meta data\n\t\tlet stat: IStat | undefined = undefined;\n\t\ttry {\n\t\t\tstat = await provider.stat(resource);\n\t\t} catch (error) {\n\t\t\treturn undefined; // file might not exist\n\t\t}\n\n\t\t// File cannot be directory\n\t\tif ((stat.type & FileType.Directory) !== 0) {\n\t\t\tthrow new FileOperationError(localize('fileIsDirectoryWriteError', \"Unable to write file '{0}' that is actually a directory\", this.resourceForError(resource)), FileOperationResult.FILE_IS_DIRECTORY, options);\n\t\t}\n\n\t\t// File cannot be readonly\n\t\tthis.throwIfFileIsReadonly(resource, stat);\n\n\t\t// Dirty write prevention: if the file on disk has been changed and does not match our expected\n\t\t// mtime and etag, we bail out to prevent dirty writing.\n\t\t//\n\t\t// First, we check for a mtime that is in the future before we do more checks. The assumption is\n\t\t// that only the mtime is an indicator for a file that has changed on disk.\n\t\t//\n\t\t// Second, if the mtime has advanced, we compare the size of the file on disk with our previous\n\t\t// one using the etag() function. Relying only on the mtime check has prooven to produce false\n\t\t// positives due to file system weirdness (especially around remote file systems). As such, the\n\t\t// check for size is a weaker check because it can return a false negative if the file has changed\n\t\t// but to the same length. This is a compromise we take to avoid having to produce checksums of\n\t\t// the file content for comparison which would be much slower to compute.\n\t\tif (\n\t\t\ttypeof options?.mtime === 'number' && typeof options.etag === 'string' && options.etag !== ETAG_DISABLED &&\n\t\t\ttypeof stat.mtime === 'number' && typeof stat.size === 'number' &&\n\t\t\toptions.mtime < stat.mtime && options.etag !== etag({ mtime: options.mtime /* not using stat.mtime for a reason, see above */, size: stat.size })\n\t\t) {\n\t\t\tthrow new FileOperationError(localize('fileModifiedError', \"File Modified Since\"), FileOperationResult.FILE_MODIFIED_SINCE, options);\n\t\t}\n\n\t\treturn stat;\n\t}\n\n\tasync readFile(resource: URI, options?: IReadFileOptions, token?: CancellationToken): Promise {\n\t\tconst provider = await this.withReadProvider(resource);\n\n\t\tif (options?.atomic) {\n\t\t\treturn this.doReadFileAtomic(provider, resource, options, token);\n\t\t}\n\n\t\treturn this.doReadFile(provider, resource, options, token);\n\t}\n\n\tprivate async doReadFileAtomic(provider: IFileSystemProviderWithFileReadWriteCapability | IFileSystemProviderWithOpenReadWriteCloseCapability | IFileSystemProviderWithFileReadStreamCapability, resource: URI, options?: IReadFileOptions, token?: CancellationToken): Promise {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tthis.writeQueue.queueFor(resource, async () => {\n\t\t\t\ttry {\n\t\t\t\t\tconst content = await this.doReadFile(provider, resource, options, token);\n\t\t\t\t\tresolve(content);\n\t\t\t\t} catch (error) {\n\t\t\t\t\treject(error);\n\t\t\t\t}\n\t\t\t}, this.getExtUri(provider).providerExtUri);\n\t\t});\n\t}\n\n\tprivate async doReadFile(provider: IFileSystemProviderWithFileReadWriteCapability | IFileSystemProviderWithOpenReadWriteCloseCapability | IFileSystemProviderWithFileReadStreamCapability, resource: URI, options?: IReadFileOptions, token?: CancellationToken): Promise {\n\t\tconst stream = await this.doReadFileStream(provider, resource, {\n\t\t\t...options,\n\t\t\t// optimization: since we know that the caller does not\n\t\t\t// care about buffering, we indicate this to the reader.\n\t\t\t// this reduces all the overhead the buffered reading\n\t\t\t// has (open, read, close) if the provider supports\n\t\t\t// unbuffered reading.\n\t\t\tpreferUnbuffered: true\n\t\t}, token);\n\n\t\treturn {\n\t\t\t...stream,\n\t\t\tvalue: await streamToBuffer(stream.value)\n\t\t};\n\t}\n\n\tasync readFileStream(resource: URI, options?: IReadFileStreamOptions, token?: CancellationToken): Promise {\n\t\tconst provider = await this.withReadProvider(resource);\n\n\t\treturn this.doReadFileStream(provider, resource, options, token);\n\t}\n\n\tprivate async doReadFileStream(provider: IFileSystemProviderWithFileReadWriteCapability | IFileSystemProviderWithOpenReadWriteCloseCapability | IFileSystemProviderWithFileReadStreamCapability, resource: URI, options?: IReadFileOptions & IReadFileStreamOptions & { preferUnbuffered?: boolean }, token?: CancellationToken): Promise {\n\n\t\t// install a cancellation token that gets cancelled\n\t\t// when any error occurs. this allows us to resolve\n\t\t// the content of the file while resolving metadata\n\t\t// but still cancel the operation in certain cases.\n\t\t//\n\t\t// in addition, we pass the optional token in that\n\t\t// we got from the outside to even allow for external\n\t\t// cancellation of the read operation.\n\t\tconst cancellableSource = new CancellationTokenSource(token);\n\n\t\tlet readFileOptions = options;\n\t\tif (hasFileAtomicReadCapability(provider) && provider.enforceAtomicReadFile?.(resource)) {\n\t\t\treadFileOptions = { ...options, atomic: true };\n\t\t}\n\n\t\t// validate read operation\n\t\tconst statPromise = this.validateReadFile(resource, readFileOptions).then(stat => stat, error => {\n\t\t\tcancellableSource.dispose(true);\n\n\t\t\tthrow error;\n\t\t});\n\n\t\tlet fileStream: VSBufferReadableStream | undefined = undefined;\n\t\ttry {\n\n\t\t\t// if the etag is provided, we await the result of the validation\n\t\t\t// due to the likelihood of hitting a NOT_MODIFIED_SINCE result.\n\t\t\t// otherwise, we let it run in parallel to the file reading for\n\t\t\t// optimal startup performance.\n\t\t\tif (typeof readFileOptions?.etag === 'string' && readFileOptions.etag !== ETAG_DISABLED) {\n\t\t\t\tawait statPromise;\n\t\t\t}\n\n\t\t\t// read unbuffered\n\t\t\tif (\n\t\t\t\t(readFileOptions?.atomic && hasFileAtomicReadCapability(provider)) ||\t\t\t\t\t\t\t\t// atomic reads are always unbuffered\n\t\t\t\t!(hasOpenReadWriteCloseCapability(provider) || hasFileReadStreamCapability(provider)) ||\t// provider has no buffered capability\n\t\t\t\t(hasReadWriteCapability(provider) && readFileOptions?.preferUnbuffered)\t\t\t\t\t\t\t\t// unbuffered read is preferred\n\t\t\t) {\n\t\t\t\tfileStream = this.readFileUnbuffered(provider, resource, readFileOptions);\n\t\t\t}\n\n\t\t\t// read streamed (always prefer over primitive buffered read)\n\t\t\telse if (hasFileReadStreamCapability(provider)) {\n\t\t\t\tfileStream = this.readFileStreamed(provider, resource, cancellableSource.token, readFileOptions);\n\t\t\t}\n\n\t\t\t// read buffered\n\t\t\telse {\n\t\t\t\tfileStream = this.readFileBuffered(provider, resource, cancellableSource.token, readFileOptions);\n\t\t\t}\n\n\t\t\tfileStream.on('end', () => cancellableSource.dispose());\n\t\t\tfileStream.on('error', () => cancellableSource.dispose());\n\n\t\t\tconst fileStat = await statPromise;\n\n\t\t\treturn {\n\t\t\t\t...fileStat,\n\t\t\t\tvalue: fileStream\n\t\t\t};\n\t\t} catch (error) {\n\n\t\t\t// Await the stream to finish so that we exit this method\n\t\t\t// in a consistent state with file handles closed\n\t\t\t// (https://github.com/microsoft/vscode/issues/114024)\n\t\t\tif (fileStream) {\n\t\t\t\tawait consumeStream(fileStream);\n\t\t\t}\n\n\t\t\t// Re-throw errors as file operation errors but preserve\n\t\t\t// specific errors (such as not modified since)\n\t\t\tthrow this.restoreReadError(error, resource, readFileOptions);\n\t\t}\n\t}\n\n\tprivate restoreReadError(error: Error, resource: URI, options?: IReadFileStreamOptions): FileOperationError {\n\t\tconst message = localize('err.read', \"Unable to read file '{0}' ({1})\", this.resourceForError(resource), ensureFileSystemProviderError(error).toString());\n\n\t\tif (error instanceof NotModifiedSinceFileOperationError) {\n\t\t\treturn new NotModifiedSinceFileOperationError(message, error.stat, options);\n\t\t}\n\n\t\tif (error instanceof TooLargeFileOperationError) {\n\t\t\treturn new TooLargeFileOperationError(message, error.fileOperationResult, error.size, error.options as IReadFileOptions);\n\t\t}\n\n\t\treturn new FileOperationError(message, toFileOperationResult(error), options);\n\t}\n\n\tprivate readFileStreamed(provider: IFileSystemProviderWithFileReadStreamCapability, resource: URI, token: CancellationToken, options: IReadFileStreamOptions = Object.create(null)): VSBufferReadableStream {\n\t\tconst fileStream = provider.readFileStream(resource, options, token);\n\n\t\treturn transform(fileStream, {\n\t\t\tdata: data => data instanceof VSBuffer ? data : VSBuffer.wrap(data),\n\t\t\terror: error => this.restoreReadError(error, resource, options)\n\t\t}, data => VSBuffer.concat(data));\n\t}\n\n\tprivate readFileBuffered(provider: IFileSystemProviderWithOpenReadWriteCloseCapability, resource: URI, token: CancellationToken, options: IReadFileStreamOptions = Object.create(null)): VSBufferReadableStream {\n\t\tconst stream = newWriteableBufferStream();\n\n\t\treadFileIntoStream(provider, resource, stream, data => data, {\n\t\t\t...options,\n\t\t\tbufferSize: this.BUFFER_SIZE,\n\t\t\terrorTransformer: error => this.restoreReadError(error, resource, options)\n\t\t}, token);\n\n\t\treturn stream;\n\t}\n\n\tprivate readFileUnbuffered(provider: IFileSystemProviderWithFileReadWriteCapability | IFileSystemProviderWithFileAtomicReadCapability, resource: URI, options?: IReadFileOptions & IReadFileStreamOptions): VSBufferReadableStream {\n\t\tconst stream = newWriteableStream(data => VSBuffer.concat(data));\n\n\t\t// Read the file into the stream async but do not wait for\n\t\t// this to complete because streams work via events\n\t\t(async () => {\n\t\t\ttry {\n\t\t\t\tlet buffer: Uint8Array;\n\t\t\t\tif (options?.atomic && hasFileAtomicReadCapability(provider)) {\n\t\t\t\t\tbuffer = await provider.readFile(resource, { atomic: true });\n\t\t\t\t} else {\n\t\t\t\t\tbuffer = await provider.readFile(resource);\n\t\t\t\t}\n\n\t\t\t\t// respect position option\n\t\t\t\tif (typeof options?.position === 'number') {\n\t\t\t\t\tbuffer = buffer.slice(options.position);\n\t\t\t\t}\n\n\t\t\t\t// respect length option\n\t\t\t\tif (typeof options?.length === 'number') {\n\t\t\t\t\tbuffer = buffer.slice(0, options.length);\n\t\t\t\t}\n\n\t\t\t\t// Throw if file is too large to load\n\t\t\t\tthis.validateReadFileLimits(resource, buffer.byteLength, options);\n\n\t\t\t\t// End stream with data\n\t\t\t\tstream.end(VSBuffer.wrap(buffer));\n\t\t\t} catch (err) {\n\t\t\t\tstream.error(err);\n\t\t\t\tstream.end();\n\t\t\t}\n\t\t})();\n\n\t\treturn stream;\n\t}\n\n\tprivate async validateReadFile(resource: URI, options?: IReadFileStreamOptions): Promise {\n\t\tconst stat = await this.resolve(resource, { resolveMetadata: true });\n\n\t\t// Throw if resource is a directory\n\t\tif (stat.isDirectory) {\n\t\t\tthrow new FileOperationError(localize('fileIsDirectoryReadError', \"Unable to read file '{0}' that is actually a directory\", this.resourceForError(resource)), FileOperationResult.FILE_IS_DIRECTORY, options);\n\t\t}\n\n\t\t// Throw if file not modified since (unless disabled)\n\t\tif (typeof options?.etag === 'string' && options.etag !== ETAG_DISABLED && options.etag === stat.etag) {\n\t\t\tthrow new NotModifiedSinceFileOperationError(localize('fileNotModifiedError', \"File not modified since\"), stat, options);\n\t\t}\n\n\t\t// Throw if file is too large to load\n\t\tthis.validateReadFileLimits(resource, stat.size, options);\n\n\t\treturn stat;\n\t}\n\n\tprivate validateReadFileLimits(resource: URI, size: number, options?: IReadFileStreamOptions): void {\n\t\tif (typeof options?.limits?.size === 'number' && size > options.limits.size) {\n\t\t\tthrow new TooLargeFileOperationError(localize('fileTooLargeError', \"Unable to read file '{0}' that is too large to open\", this.resourceForError(resource)), FileOperationResult.FILE_TOO_LARGE, size, options);\n\t\t}\n\t}\n\n\t//#endregion\n\n\t//#region Move/Copy/Delete/Create Folder\n\n\tasync canMove(source: URI, target: URI, overwrite?: boolean): Promise {\n\t\treturn this.doCanMoveCopy(source, target, 'move', overwrite);\n\t}\n\n\tasync canCopy(source: URI, target: URI, overwrite?: boolean): Promise {\n\t\treturn this.doCanMoveCopy(source, target, 'copy', overwrite);\n\t}\n\n\tprivate async doCanMoveCopy(source: URI, target: URI, mode: 'move' | 'copy', overwrite?: boolean): Promise {\n\t\tif (source.toString() !== target.toString()) {\n\t\t\ttry {\n\t\t\t\tconst sourceProvider = mode === 'move' ? this.throwIfFileSystemIsReadonly(await this.withWriteProvider(source), source) : await this.withReadProvider(source);\n\t\t\t\tconst targetProvider = this.throwIfFileSystemIsReadonly(await this.withWriteProvider(target), target);\n\n\t\t\t\tawait this.doValidateMoveCopy(sourceProvider, source, targetProvider, target, mode, overwrite);\n\t\t\t} catch (error) {\n\t\t\t\treturn error;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tasync move(source: URI, target: URI, overwrite?: boolean): Promise {\n\t\tconst sourceProvider = this.throwIfFileSystemIsReadonly(await this.withWriteProvider(source), source);\n\t\tconst targetProvider = this.throwIfFileSystemIsReadonly(await this.withWriteProvider(target), target);\n\n\t\t// move\n\t\tconst mode = await this.doMoveCopy(sourceProvider, source, targetProvider, target, 'move', !!overwrite);\n\n\t\t// resolve and send events\n\t\tconst fileStat = await this.resolve(target, { resolveMetadata: true });\n\t\tthis._onDidRunOperation.fire(new FileOperationEvent(source, mode === 'move' ? FileOperation.MOVE : FileOperation.COPY, fileStat));\n\n\t\treturn fileStat;\n\t}\n\n\tasync copy(source: URI, target: URI, overwrite?: boolean): Promise {\n\t\tconst sourceProvider = await this.withReadProvider(source);\n\t\tconst targetProvider = this.throwIfFileSystemIsReadonly(await this.withWriteProvider(target), target);\n\n\t\t// copy\n\t\tconst mode = await this.doMoveCopy(sourceProvider, source, targetProvider, target, 'copy', !!overwrite);\n\n\t\t// resolve and send events\n\t\tconst fileStat = await this.resolve(target, { resolveMetadata: true });\n\t\tthis._onDidRunOperation.fire(new FileOperationEvent(source, mode === 'copy' ? FileOperation.COPY : FileOperation.MOVE, fileStat));\n\n\t\treturn fileStat;\n\t}\n\n\tprivate async doMoveCopy(sourceProvider: IFileSystemProvider, source: URI, targetProvider: IFileSystemProvider, target: URI, mode: 'move' | 'copy', overwrite: boolean): Promise<'move' | 'copy'> {\n\t\tif (source.toString() === target.toString()) {\n\t\t\treturn mode; // simulate node.js behaviour here and do a no-op if paths match\n\t\t}\n\n\t\t// validation\n\t\tconst { exists, isSameResourceWithDifferentPathCase } = await this.doValidateMoveCopy(sourceProvider, source, targetProvider, target, mode, overwrite);\n\n\t\t// delete as needed (unless target is same resurce with different path case)\n\t\tif (exists && !isSameResourceWithDifferentPathCase && overwrite) {\n\t\t\tawait this.del(target, { recursive: true });\n\t\t}\n\n\t\t// create parent folders\n\t\tawait this.mkdirp(targetProvider, this.getExtUri(targetProvider).providerExtUri.dirname(target));\n\n\t\t// copy source => target\n\t\tif (mode === 'copy') {\n\n\t\t\t// same provider with fast copy: leverage copy() functionality\n\t\t\tif (sourceProvider === targetProvider && hasFileFolderCopyCapability(sourceProvider)) {\n\t\t\t\tawait sourceProvider.copy(source, target, { overwrite });\n\t\t\t}\n\n\t\t\t// when copying via buffer/unbuffered, we have to manually\n\t\t\t// traverse the source if it is a folder and not a file\n\t\t\telse {\n\t\t\t\tconst sourceFile = await this.resolve(source);\n\t\t\t\tif (sourceFile.isDirectory) {\n\t\t\t\t\tawait this.doCopyFolder(sourceProvider, sourceFile, targetProvider, target);\n\t\t\t\t} else {\n\t\t\t\t\tawait this.doCopyFile(sourceProvider, source, targetProvider, target);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn mode;\n\t\t}\n\n\t\t// move source => target\n\t\telse {\n\n\t\t\t// same provider: leverage rename() functionality\n\t\t\tif (sourceProvider === targetProvider) {\n\t\t\t\tawait sourceProvider.rename(source, target, { overwrite });\n\n\t\t\t\treturn mode;\n\t\t\t}\n\n\t\t\t// across providers: copy to target & delete at source\n\t\t\telse {\n\t\t\t\tawait this.doMoveCopy(sourceProvider, source, targetProvider, target, 'copy', overwrite);\n\t\t\t\tawait this.del(source, { recursive: true });\n\n\t\t\t\treturn 'copy';\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async doCopyFile(sourceProvider: IFileSystemProvider, source: URI, targetProvider: IFileSystemProvider, target: URI): Promise {\n\n\t\t// copy: source (buffered) => target (buffered)\n\t\tif (hasOpenReadWriteCloseCapability(sourceProvider) && hasOpenReadWriteCloseCapability(targetProvider)) {\n\t\t\treturn this.doPipeBuffered(sourceProvider, source, targetProvider, target);\n\t\t}\n\n\t\t// copy: source (buffered) => target (unbuffered)\n\t\tif (hasOpenReadWriteCloseCapability(sourceProvider) && hasReadWriteCapability(targetProvider)) {\n\t\t\treturn this.doPipeBufferedToUnbuffered(sourceProvider, source, targetProvider, target);\n\t\t}\n\n\t\t// copy: source (unbuffered) => target (buffered)\n\t\tif (hasReadWriteCapability(sourceProvider) && hasOpenReadWriteCloseCapability(targetProvider)) {\n\t\t\treturn this.doPipeUnbufferedToBuffered(sourceProvider, source, targetProvider, target);\n\t\t}\n\n\t\t// copy: source (unbuffered) => target (unbuffered)\n\t\tif (hasReadWriteCapability(sourceProvider) && hasReadWriteCapability(targetProvider)) {\n\t\t\treturn this.doPipeUnbuffered(sourceProvider, source, targetProvider, target);\n\t\t}\n\t}\n\n\tprivate async doCopyFolder(sourceProvider: IFileSystemProvider, sourceFolder: IFileStat, targetProvider: IFileSystemProvider, targetFolder: URI): Promise {\n\n\t\t// create folder in target\n\t\tawait targetProvider.mkdir(targetFolder);\n\n\t\t// create children in target\n\t\tif (Array.isArray(sourceFolder.children)) {\n\t\t\tawait Promises.settled(sourceFolder.children.map(async sourceChild => {\n\t\t\t\tconst targetChild = this.getExtUri(targetProvider).providerExtUri.joinPath(targetFolder, sourceChild.name);\n\t\t\t\tif (sourceChild.isDirectory) {\n\t\t\t\t\treturn this.doCopyFolder(sourceProvider, await this.resolve(sourceChild.resource), targetProvider, targetChild);\n\t\t\t\t} else {\n\t\t\t\t\treturn this.doCopyFile(sourceProvider, sourceChild.resource, targetProvider, targetChild);\n\t\t\t\t}\n\t\t\t}));\n\t\t}\n\t}\n\n\tprivate async doValidateMoveCopy(sourceProvider: IFileSystemProvider, source: URI, targetProvider: IFileSystemProvider, target: URI, mode: 'move' | 'copy', overwrite?: boolean): Promise<{ exists: boolean; isSameResourceWithDifferentPathCase: boolean }> {\n\t\tlet isSameResourceWithDifferentPathCase = false;\n\n\t\t// Check if source is equal or parent to target (requires providers to be the same)\n\t\tif (sourceProvider === targetProvider) {\n\t\t\tconst { providerExtUri, isPathCaseSensitive } = this.getExtUri(sourceProvider);\n\t\t\tif (!isPathCaseSensitive) {\n\t\t\t\tisSameResourceWithDifferentPathCase = providerExtUri.isEqual(source, target);\n\t\t\t}\n\n\t\t\tif (isSameResourceWithDifferentPathCase && mode === 'copy') {\n\t\t\t\tthrow new Error(localize('unableToMoveCopyError1', \"Unable to copy when source '{0}' is same as target '{1}' with different path case on a case insensitive file system\", this.resourceForError(source), this.resourceForError(target)));\n\t\t\t}\n\n\t\t\tif (!isSameResourceWithDifferentPathCase && providerExtUri.isEqualOrParent(target, source)) {\n\t\t\t\tthrow new Error(localize('unableToMoveCopyError2', \"Unable to move/copy when source '{0}' is parent of target '{1}'.\", this.resourceForError(source), this.resourceForError(target)));\n\t\t\t}\n\t\t}\n\n\t\t// Extra checks if target exists and this is not a rename\n\t\tconst exists = await this.exists(target);\n\t\tif (exists && !isSameResourceWithDifferentPathCase) {\n\n\t\t\t// Bail out if target exists and we are not about to overwrite\n\t\t\tif (!overwrite) {\n\t\t\t\tthrow new FileOperationError(localize('unableToMoveCopyError3', \"Unable to move/copy '{0}' because target '{1}' already exists at destination.\", this.resourceForError(source), this.resourceForError(target)), FileOperationResult.FILE_MOVE_CONFLICT);\n\t\t\t}\n\n\t\t\t// Special case: if the target is a parent of the source, we cannot delete\n\t\t\t// it as it would delete the source as well. In this case we have to throw\n\t\t\tif (sourceProvider === targetProvider) {\n\t\t\t\tconst { providerExtUri } = this.getExtUri(sourceProvider);\n\t\t\t\tif (providerExtUri.isEqualOrParent(source, target)) {\n\t\t\t\t\tthrow new Error(localize('unableToMoveCopyError4', \"Unable to move/copy '{0}' into '{1}' since a file would replace the folder it is contained in.\", this.resourceForError(source), this.resourceForError(target)));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn { exists, isSameResourceWithDifferentPathCase };\n\t}\n\n\tprivate getExtUri(provider: IFileSystemProvider): { providerExtUri: IExtUri; isPathCaseSensitive: boolean } {\n\t\tconst isPathCaseSensitive = this.isPathCaseSensitive(provider);\n\n\t\treturn {\n\t\t\tproviderExtUri: isPathCaseSensitive ? extUri : extUriIgnorePathCase,\n\t\t\tisPathCaseSensitive\n\t\t};\n\t}\n\n\tprivate isPathCaseSensitive(provider: IFileSystemProvider): boolean {\n\t\treturn !!(provider.capabilities & FileSystemProviderCapabilities.PathCaseSensitive);\n\t}\n\n\tasync createFolder(resource: URI): Promise {\n\t\tconst provider = this.throwIfFileSystemIsReadonly(await this.withProvider(resource), resource);\n\n\t\t// mkdir recursively\n\t\tawait this.mkdirp(provider, resource);\n\n\t\t// events\n\t\tconst fileStat = await this.resolve(resource, { resolveMetadata: true });\n\t\tthis._onDidRunOperation.fire(new FileOperationEvent(resource, FileOperation.CREATE, fileStat));\n\n\t\treturn fileStat;\n\t}\n\n\tprivate async mkdirp(provider: IFileSystemProvider, directory: URI): Promise {\n\t\tconst directoriesToCreate: string[] = [];\n\n\t\t// mkdir until we reach root\n\t\tconst { providerExtUri } = this.getExtUri(provider);\n\t\twhile (!providerExtUri.isEqual(directory, providerExtUri.dirname(directory))) {\n\t\t\ttry {\n\t\t\t\tconst stat = await provider.stat(directory);\n\t\t\t\tif ((stat.type & FileType.Directory) === 0) {\n\t\t\t\t\tthrow new Error(localize('mkdirExistsError', \"Unable to create folder '{0}' that already exists but is not a directory\", this.resourceForError(directory)));\n\t\t\t\t}\n\n\t\t\t\tbreak; // we have hit a directory that exists -> good\n\t\t\t} catch (error) {\n\n\t\t\t\t// Bubble up any other error that is not file not found\n\t\t\t\tif (toFileSystemProviderErrorCode(error) !== FileSystemProviderErrorCode.FileNotFound) {\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\n\t\t\t\t// Upon error, remember directories that need to be created\n\t\t\t\tdirectoriesToCreate.push(providerExtUri.basename(directory));\n\n\t\t\t\t// Continue up\n\t\t\t\tdirectory = providerExtUri.dirname(directory);\n\t\t\t}\n\t\t}\n\n\t\t// Create directories as needed\n\t\tfor (let i = directoriesToCreate.length - 1; i >= 0; i--) {\n\t\t\tdirectory = providerExtUri.joinPath(directory, directoriesToCreate[i]);\n\n\t\t\ttry {\n\t\t\t\tawait provider.mkdir(directory);\n\t\t\t} catch (error) {\n\t\t\t\tif (toFileSystemProviderErrorCode(error) !== FileSystemProviderErrorCode.FileExists) {\n\t\t\t\t\t// For mkdirp() we tolerate that the mkdir() call fails\n\t\t\t\t\t// in case the folder already exists. This follows node.js\n\t\t\t\t\t// own implementation of fs.mkdir({ recursive: true }) and\n\t\t\t\t\t// reduces the chances of race conditions leading to errors\n\t\t\t\t\t// if multiple calls try to create the same folders\n\t\t\t\t\t// As such, we only throw an error here if it is other than\n\t\t\t\t\t// the fact that the file already exists.\n\t\t\t\t\t// (see also https://github.com/microsoft/vscode/issues/89834)\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tasync canDelete(resource: URI, options?: Partial): Promise {\n\t\ttry {\n\t\t\tawait this.doValidateDelete(resource, options);\n\t\t} catch (error) {\n\t\t\treturn error;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tprivate async doValidateDelete(resource: URI, options?: Partial): Promise {\n\t\tconst provider = this.throwIfFileSystemIsReadonly(await this.withProvider(resource), resource);\n\n\t\t// Validate trash support\n\t\tconst useTrash = !!options?.useTrash;\n\t\tif (useTrash && !(provider.capabilities & FileSystemProviderCapabilities.Trash)) {\n\t\t\tthrow new Error(localize('deleteFailedTrashUnsupported', \"Unable to delete file '{0}' via trash because provider does not support it.\", this.resourceForError(resource)));\n\t\t}\n\n\t\t// Validate atomic support\n\t\tconst atomic = options?.atomic;\n\t\tif (atomic && !(provider.capabilities & FileSystemProviderCapabilities.FileAtomicDelete)) {\n\t\t\tthrow new Error(localize('deleteFailedAtomicUnsupported', \"Unable to delete file '{0}' atomically because provider does not support it.\", this.resourceForError(resource)));\n\t\t}\n\n\t\tif (useTrash && atomic) {\n\t\t\tthrow new Error(localize('deleteFailedTrashAndAtomicUnsupported', \"Unable to atomically delete file '{0}' because using trash is enabled.\", this.resourceForError(resource)));\n\t\t}\n\n\t\t// Validate delete\n\t\tlet stat: IStat | undefined = undefined;\n\t\ttry {\n\t\t\tstat = await provider.stat(resource);\n\t\t} catch (error) {\n\t\t\t// Handled later\n\t\t}\n\n\t\tif (stat) {\n\t\t\tthis.throwIfFileIsReadonly(resource, stat);\n\t\t} else {\n\t\t\tthrow new FileOperationError(localize('deleteFailedNotFound', \"Unable to delete nonexistent file '{0}'\", this.resourceForError(resource)), FileOperationResult.FILE_NOT_FOUND);\n\t\t}\n\n\t\t// Validate recursive\n\t\tconst recursive = !!options?.recursive;\n\t\tif (!recursive) {\n\t\t\tconst stat = await this.resolve(resource);\n\t\t\tif (stat.isDirectory && Array.isArray(stat.children) && stat.children.length > 0) {\n\t\t\t\tthrow new Error(localize('deleteFailedNonEmptyFolder', \"Unable to delete non-empty folder '{0}'.\", this.resourceForError(resource)));\n\t\t\t}\n\t\t}\n\n\t\treturn provider;\n\t}\n\n\tasync del(resource: URI, options?: Partial): Promise {\n\t\tconst provider = await this.doValidateDelete(resource, options);\n\n\t\tlet deleteFileOptions = options;\n\t\tif (hasFileAtomicDeleteCapability(provider) && !deleteFileOptions?.atomic) {\n\t\t\tconst enforcedAtomicDelete = provider.enforceAtomicDelete?.(resource);\n\t\t\tif (enforcedAtomicDelete) {\n\t\t\t\tdeleteFileOptions = { ...options, atomic: enforcedAtomicDelete };\n\t\t\t}\n\t\t}\n\n\t\tconst useTrash = !!deleteFileOptions?.useTrash;\n\t\tconst recursive = !!deleteFileOptions?.recursive;\n\t\tconst atomic = deleteFileOptions?.atomic ?? false;\n\n\t\t// Delete through provider\n\t\tawait provider.delete(resource, { recursive, useTrash, atomic });\n\n\t\t// Events\n\t\tthis._onDidRunOperation.fire(new FileOperationEvent(resource, FileOperation.DELETE));\n\t}\n\n\t//#endregion\n\n\t//#region Clone File\n\n\tasync cloneFile(source: URI, target: URI): Promise {\n\t\tconst sourceProvider = await this.withProvider(source);\n\t\tconst targetProvider = this.throwIfFileSystemIsReadonly(await this.withWriteProvider(target), target);\n\n\t\tif (sourceProvider === targetProvider && this.getExtUri(sourceProvider).providerExtUri.isEqual(source, target)) {\n\t\t\treturn; // return early if paths are equal\n\t\t}\n\n\t\t// same provider, use `cloneFile` when native support is provided\n\t\tif (sourceProvider === targetProvider && hasFileCloneCapability(sourceProvider)) {\n\t\t\treturn sourceProvider.cloneFile(source, target);\n\t\t}\n\n\t\t// otherwise, either providers are different or there is no native\n\t\t// `cloneFile` support, then we fallback to emulate a clone as best\n\t\t// as we can with the other primitives\n\n\t\t// create parent folders\n\t\tawait this.mkdirp(targetProvider, this.getExtUri(targetProvider).providerExtUri.dirname(target));\n\n\t\t// leverage `copy` method if provided and providers are identical\n\t\t// queue on the source to ensure atomic read\n\t\tif (sourceProvider === targetProvider && hasFileFolderCopyCapability(sourceProvider)) {\n\t\t\treturn this.writeQueue.queueFor(source, () => sourceProvider.copy(source, target, { overwrite: true }), this.getExtUri(sourceProvider).providerExtUri);\n\t\t}\n\n\t\t// otherwise copy via buffer/unbuffered and use a write queue\n\t\t// on the source to ensure atomic operation as much as possible\n\t\treturn this.writeQueue.queueFor(source, () => this.doCopyFile(sourceProvider, source, targetProvider, target), this.getExtUri(sourceProvider).providerExtUri);\n\t}\n\n\t//#endregion\n\n\t//#region File Watching\n\n\tprivate readonly internalOnDidFilesChange = this._register(new Emitter());\n\n\tprivate readonly _onDidUncorrelatedFilesChange = this._register(new Emitter());\n\treadonly onDidFilesChange = this._onDidUncorrelatedFilesChange.event; // global `onDidFilesChange` skips correlated events\n\n\tprivate readonly _onDidWatchError = this._register(new Emitter());\n\treadonly onDidWatchError = this._onDidWatchError.event;\n\n\tprivate readonly activeWatchers = new Map();\n\n\tprivate static WATCHER_CORRELATION_IDS = 0;\n\n\tcreateWatcher(resource: URI, options: IWatchOptionsWithoutCorrelation): IFileSystemWatcher {\n\t\treturn this.watch(resource, {\n\t\t\t...options,\n\t\t\t// Explicitly set a correlation id so that file events that originate\n\t\t\t// from requests from extensions are exclusively routed back to the\n\t\t\t// extension host and not into the workbench.\n\t\t\tcorrelationId: FileService.WATCHER_CORRELATION_IDS++\n\t\t});\n\t}\n\n\twatch(resource: URI, options: IWatchOptionsWithCorrelation): IFileSystemWatcher;\n\twatch(resource: URI, options?: IWatchOptionsWithoutCorrelation): IDisposable;\n\twatch(resource: URI, options: IWatchOptions = { recursive: false, excludes: [] }): IFileSystemWatcher | IDisposable {\n\t\tconst disposables = new DisposableStore();\n\n\t\t// Forward watch request to provider and wire in disposables\n\t\tlet watchDisposed = false;\n\t\tlet disposeWatch = () => { watchDisposed = true; };\n\t\tdisposables.add(toDisposable(() => disposeWatch()));\n\n\t\t// Watch and wire in disposable which is async but\n\t\t// check if we got disposed meanwhile and forward\n\t\t(async () => {\n\t\t\ttry {\n\t\t\t\tconst disposable = await this.doWatch(resource, options);\n\t\t\t\tif (watchDisposed) {\n\t\t\t\t\tdispose(disposable);\n\t\t\t\t} else {\n\t\t\t\t\tdisposeWatch = () => dispose(disposable);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthis.logService.error(error);\n\t\t\t}\n\t\t})();\n\n\t\t// When a correlation identifier is set, return a specific\n\t\t// watcher that only emits events matching that correalation.\n\t\tconst correlationId = options.correlationId;\n\t\tif (typeof correlationId === 'number') {\n\t\t\tconst fileChangeEmitter = disposables.add(new Emitter());\n\t\t\tdisposables.add(this.internalOnDidFilesChange.event(e => {\n\t\t\t\tif (e.correlates(correlationId)) {\n\t\t\t\t\tfileChangeEmitter.fire(e);\n\t\t\t\t}\n\t\t\t}));\n\n\t\t\tconst watcher: IFileSystemWatcher = {\n\t\t\t\tonDidChange: fileChangeEmitter.event,\n\t\t\t\tdispose: () => disposables.dispose()\n\t\t\t};\n\n\t\t\treturn watcher;\n\t\t}\n\n\t\treturn disposables;\n\t}\n\n\tprivate async doWatch(resource: URI, options: IWatchOptions): Promise {\n\t\tconst provider = await this.withProvider(resource);\n\n\t\t// Deduplicate identical watch requests\n\t\tconst watchHash = hash([this.getExtUri(provider).providerExtUri.getComparisonKey(resource), options]);\n\t\tlet watcher = this.activeWatchers.get(watchHash);\n\t\tif (!watcher) {\n\t\t\twatcher = {\n\t\t\t\tcount: 0,\n\t\t\t\tdisposable: provider.watch(resource, options)\n\t\t\t};\n\n\t\t\tthis.activeWatchers.set(watchHash, watcher);\n\t\t}\n\n\t\t// Increment usage counter\n\t\twatcher.count += 1;\n\n\t\treturn toDisposable(() => {\n\t\t\tif (watcher) {\n\n\t\t\t\t// Unref\n\t\t\t\twatcher.count--;\n\n\t\t\t\t// Dispose only when last user is reached\n\t\t\t\tif (watcher.count === 0) {\n\t\t\t\t\tdispose(watcher.disposable);\n\t\t\t\t\tthis.activeWatchers.delete(watchHash);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\toverride dispose(): void {\n\t\tsuper.dispose();\n\n\t\tfor (const [, watcher] of this.activeWatchers) {\n\t\t\tdispose(watcher.disposable);\n\t\t}\n\n\t\tthis.activeWatchers.clear();\n\t}\n\n\t//#endregion\n\n\t//#region Helpers\n\n\tprivate readonly writeQueue = this._register(new ResourceQueue());\n\n\tprivate async doWriteBuffered(provider: IFileSystemProviderWithOpenReadWriteCloseCapability, resource: URI, options: IWriteFileOptions | undefined, readableOrStreamOrBufferedStream: VSBufferReadable | VSBufferReadableStream | VSBufferReadableBufferedStream): Promise {\n\t\treturn this.writeQueue.queueFor(resource, async () => {\n\n\t\t\t// open handle\n\t\t\tconst handle = await provider.open(resource, { create: true, unlock: options?.unlock ?? false });\n\n\t\t\t// write into handle until all bytes from buffer have been written\n\t\t\ttry {\n\t\t\t\tif (isReadableStream(readableOrStreamOrBufferedStream) || isReadableBufferedStream(readableOrStreamOrBufferedStream)) {\n\t\t\t\t\tawait this.doWriteStreamBufferedQueued(provider, handle, readableOrStreamOrBufferedStream);\n\t\t\t\t} else {\n\t\t\t\t\tawait this.doWriteReadableBufferedQueued(provider, handle, readableOrStreamOrBufferedStream);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthrow ensureFileSystemProviderError(error);\n\t\t\t} finally {\n\n\t\t\t\t// close handle always\n\t\t\t\tawait provider.close(handle);\n\t\t\t}\n\t\t}, this.getExtUri(provider).providerExtUri);\n\t}\n\n\tprivate async doWriteStreamBufferedQueued(provider: IFileSystemProviderWithOpenReadWriteCloseCapability, handle: number, streamOrBufferedStream: VSBufferReadableStream | VSBufferReadableBufferedStream): Promise {\n\t\tlet posInFile = 0;\n\t\tlet stream: VSBufferReadableStream;\n\n\t\t// Buffered stream: consume the buffer first by writing\n\t\t// it to the target before reading from the stream.\n\t\tif (isReadableBufferedStream(streamOrBufferedStream)) {\n\t\t\tif (streamOrBufferedStream.buffer.length > 0) {\n\t\t\t\tconst chunk = VSBuffer.concat(streamOrBufferedStream.buffer);\n\t\t\t\tawait this.doWriteBuffer(provider, handle, chunk, chunk.byteLength, posInFile, 0);\n\n\t\t\t\tposInFile += chunk.byteLength;\n\t\t\t}\n\n\t\t\t// If the stream has been consumed, return early\n\t\t\tif (streamOrBufferedStream.ended) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tstream = streamOrBufferedStream.stream;\n\t\t}\n\n\t\t// Unbuffered stream - just take as is\n\t\telse {\n\t\t\tstream = streamOrBufferedStream;\n\t\t}\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tlistenStream(stream, {\n\t\t\t\tonData: async chunk => {\n\n\t\t\t\t\t// pause stream to perform async write operation\n\t\t\t\t\tstream.pause();\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait this.doWriteBuffer(provider, handle, chunk, chunk.byteLength, posInFile, 0);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\treturn reject(error);\n\t\t\t\t\t}\n\n\t\t\t\t\tposInFile += chunk.byteLength;\n\n\t\t\t\t\t// resume stream now that we have successfully written\n\t\t\t\t\t// run this on the next tick to prevent increasing the\n\t\t\t\t\t// execution stack because resume() may call the event\n\t\t\t\t\t// handler again before finishing.\n\t\t\t\t\tsetTimeout(() => stream.resume());\n\t\t\t\t},\n\t\t\t\tonError: error => reject(error),\n\t\t\t\tonEnd: () => resolve()\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate async doWriteReadableBufferedQueued(provider: IFileSystemProviderWithOpenReadWriteCloseCapability, handle: number, readable: VSBufferReadable): Promise {\n\t\tlet posInFile = 0;\n\n\t\tlet chunk: VSBuffer | null;\n\t\twhile ((chunk = readable.read()) !== null) {\n\t\t\tawait this.doWriteBuffer(provider, handle, chunk, chunk.byteLength, posInFile, 0);\n\n\t\t\tposInFile += chunk.byteLength;\n\t\t}\n\t}\n\n\tprivate async doWriteBuffer(provider: IFileSystemProviderWithOpenReadWriteCloseCapability, handle: number, buffer: VSBuffer, length: number, posInFile: number, posInBuffer: number): Promise {\n\t\tlet totalBytesWritten = 0;\n\t\twhile (totalBytesWritten < length) {\n\n\t\t\t// Write through the provider\n\t\t\tconst bytesWritten = await provider.write(handle, posInFile + totalBytesWritten, buffer.buffer, posInBuffer + totalBytesWritten, length - totalBytesWritten);\n\t\t\ttotalBytesWritten += bytesWritten;\n\t\t}\n\t}\n\n\tprivate async doWriteUnbuffered(provider: IFileSystemProviderWithFileReadWriteCapability, resource: URI, options: IWriteFileOptions | undefined, bufferOrReadableOrStreamOrBufferedStream: VSBuffer | VSBufferReadable | VSBufferReadableStream | VSBufferReadableBufferedStream): Promise {\n\t\treturn this.writeQueue.queueFor(resource, () => this.doWriteUnbufferedQueued(provider, resource, options, bufferOrReadableOrStreamOrBufferedStream), this.getExtUri(provider).providerExtUri);\n\t}\n\n\tprivate async doWriteUnbufferedQueued(provider: IFileSystemProviderWithFileReadWriteCapability, resource: URI, options: IWriteFileOptions | undefined, bufferOrReadableOrStreamOrBufferedStream: VSBuffer | VSBufferReadable | VSBufferReadableStream | VSBufferReadableBufferedStream): Promise {\n\t\tlet buffer: VSBuffer;\n\t\tif (bufferOrReadableOrStreamOrBufferedStream instanceof VSBuffer) {\n\t\t\tbuffer = bufferOrReadableOrStreamOrBufferedStream;\n\t\t} else if (isReadableStream(bufferOrReadableOrStreamOrBufferedStream)) {\n\t\t\tbuffer = await streamToBuffer(bufferOrReadableOrStreamOrBufferedStream);\n\t\t} else if (isReadableBufferedStream(bufferOrReadableOrStreamOrBufferedStream)) {\n\t\t\tbuffer = await bufferedStreamToBuffer(bufferOrReadableOrStreamOrBufferedStream);\n\t\t} else {\n\t\t\tbuffer = readableToBuffer(bufferOrReadableOrStreamOrBufferedStream);\n\t\t}\n\n\t\t// Write through the provider\n\t\tawait provider.writeFile(resource, buffer.buffer, { create: true, overwrite: true, unlock: options?.unlock ?? false, atomic: options?.atomic ?? false });\n\t}\n\n\tprivate async doPipeBuffered(sourceProvider: IFileSystemProviderWithOpenReadWriteCloseCapability, source: URI, targetProvider: IFileSystemProviderWithOpenReadWriteCloseCapability, target: URI): Promise {\n\t\treturn this.writeQueue.queueFor(target, () => this.doPipeBufferedQueued(sourceProvider, source, targetProvider, target), this.getExtUri(targetProvider).providerExtUri);\n\t}\n\n\tprivate async doPipeBufferedQueued(sourceProvider: IFileSystemProviderWithOpenReadWriteCloseCapability, source: URI, targetProvider: IFileSystemProviderWithOpenReadWriteCloseCapability, target: URI): Promise {\n\t\tlet sourceHandle: number | undefined = undefined;\n\t\tlet targetHandle: number | undefined = undefined;\n\n\t\ttry {\n\n\t\t\t// Open handles\n\t\t\tsourceHandle = await sourceProvider.open(source, { create: false });\n\t\t\ttargetHandle = await targetProvider.open(target, { create: true, unlock: false });\n\n\t\t\tconst buffer = VSBuffer.alloc(this.BUFFER_SIZE);\n\n\t\t\tlet posInFile = 0;\n\t\t\tlet posInBuffer = 0;\n\t\t\tlet bytesRead = 0;\n\t\t\tdo {\n\t\t\t\t// read from source (sourceHandle) at current position (posInFile) into buffer (buffer) at\n\t\t\t\t// buffer position (posInBuffer) up to the size of the buffer (buffer.byteLength).\n\t\t\t\tbytesRead = await sourceProvider.read(sourceHandle, posInFile, buffer.buffer, posInBuffer, buffer.byteLength - posInBuffer);\n\n\t\t\t\t// write into target (targetHandle) at current position (posInFile) from buffer (buffer) at\n\t\t\t\t// buffer position (posInBuffer) all bytes we read (bytesRead).\n\t\t\t\tawait this.doWriteBuffer(targetProvider, targetHandle, buffer, bytesRead, posInFile, posInBuffer);\n\n\t\t\t\tposInFile += bytesRead;\n\t\t\t\tposInBuffer += bytesRead;\n\n\t\t\t\t// when buffer full, fill it again from the beginning\n\t\t\t\tif (posInBuffer === buffer.byteLength) {\n\t\t\t\t\tposInBuffer = 0;\n\t\t\t\t}\n\t\t\t} while (bytesRead > 0);\n\t\t} catch (error) {\n\t\t\tthrow ensureFileSystemProviderError(error);\n\t\t} finally {\n\t\t\tawait Promises.settled([\n\t\t\t\ttypeof sourceHandle === 'number' ? sourceProvider.close(sourceHandle) : Promise.resolve(),\n\t\t\t\ttypeof targetHandle === 'number' ? targetProvider.close(targetHandle) : Promise.resolve(),\n\t\t\t]);\n\t\t}\n\t}\n\n\tprivate async doPipeUnbuffered(sourceProvider: IFileSystemProviderWithFileReadWriteCapability, source: URI, targetProvider: IFileSystemProviderWithFileReadWriteCapability, target: URI): Promise {\n\t\treturn this.writeQueue.queueFor(target, () => this.doPipeUnbufferedQueued(sourceProvider, source, targetProvider, target), this.getExtUri(targetProvider).providerExtUri);\n\t}\n\n\tprivate async doPipeUnbufferedQueued(sourceProvider: IFileSystemProviderWithFileReadWriteCapability, source: URI, targetProvider: IFileSystemProviderWithFileReadWriteCapability, target: URI): Promise {\n\t\treturn targetProvider.writeFile(target, await sourceProvider.readFile(source), { create: true, overwrite: true, unlock: false, atomic: false });\n\t}\n\n\tprivate async doPipeUnbufferedToBuffered(sourceProvider: IFileSystemProviderWithFileReadWriteCapability, source: URI, targetProvider: IFileSystemProviderWithOpenReadWriteCloseCapability, target: URI): Promise {\n\t\treturn this.writeQueue.queueFor(target, () => this.doPipeUnbufferedToBufferedQueued(sourceProvider, source, targetProvider, target), this.getExtUri(targetProvider).providerExtUri);\n\t}\n\n\tprivate async doPipeUnbufferedToBufferedQueued(sourceProvider: IFileSystemProviderWithFileReadWriteCapability, source: URI, targetProvider: IFileSystemProviderWithOpenReadWriteCloseCapability, target: URI): Promise {\n\n\t\t// Open handle\n\t\tconst targetHandle = await targetProvider.open(target, { create: true, unlock: false });\n\n\t\t// Read entire buffer from source and write buffered\n\t\ttry {\n\t\t\tconst buffer = await sourceProvider.readFile(source);\n\t\t\tawait this.doWriteBuffer(targetProvider, targetHandle, VSBuffer.wrap(buffer), buffer.byteLength, 0, 0);\n\t\t} catch (error) {\n\t\t\tthrow ensureFileSystemProviderError(error);\n\t\t} finally {\n\t\t\tawait targetProvider.close(targetHandle);\n\t\t}\n\t}\n\n\tprivate async doPipeBufferedToUnbuffered(sourceProvider: IFileSystemProviderWithOpenReadWriteCloseCapability, source: URI, targetProvider: IFileSystemProviderWithFileReadWriteCapability, target: URI): Promise {\n\n\t\t// Read buffer via stream buffered\n\t\tconst buffer = await streamToBuffer(this.readFileBuffered(sourceProvider, source, CancellationToken.None));\n\n\t\t// Write buffer into target at once\n\t\tawait this.doWriteUnbuffered(targetProvider, target, undefined, buffer);\n\t}\n\n\tprotected throwIfFileSystemIsReadonly(provider: T, resource: URI): T {\n\t\tif (provider.capabilities & FileSystemProviderCapabilities.Readonly) {\n\t\t\tthrow new FileOperationError(localize('err.readonly', \"Unable to modify read-only file '{0}'\", this.resourceForError(resource)), FileOperationResult.FILE_PERMISSION_DENIED);\n\t\t}\n\n\t\treturn provider;\n\t}\n\n\tprivate throwIfFileIsReadonly(resource: URI, stat: IStat): void {\n\t\tif ((stat.permissions ?? 0) & FilePermission.Readonly) {\n\t\t\tthrow new FileOperationError(localize('err.readonly', \"Unable to modify read-only file '{0}'\", this.resourceForError(resource)), FileOperationResult.FILE_PERMISSION_DENIED);\n\t\t}\n\t}\n\n\tprivate resourceForError(resource: URI): string {\n\t\tif (resource.scheme === Schemas.file) {\n\t\t\treturn resource.fsPath;\n\t\t}\n\n\t\treturn resource.toString(true);\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 *--------------------------------------------------------------------------------------------*/\n\nimport { mainWindow } from 'vs/base/browser/window';\nimport { relativePath } from 'vs/base/common/resources';\nimport { URI } from 'vs/base/common/uri';\nimport { IEnvironmentService } from 'vs/platform/environment/common/environment';\nimport { IFileService } from 'vs/platform/files/common/files';\nimport { AdapterLogger, DEFAULT_LOG_LEVEL, ILogger, LogLevel } from 'vs/platform/log/common/log';\n\nexport interface IAutomatedWindow {\n\tcodeAutomationLog(type: string, args: any[]): void;\n\tcodeAutomationExit(code: number, logs: Array): void;\n}\n\nexport interface ILogFile {\n\treadonly relativePath: string;\n\treadonly contents: string;\n}\n\n/**\n * Only used in browser contexts where the log files are not stored on disk\n * but in IndexedDB. A method to get all logs with their contents so that\n * CI automation can persist them.\n */\nexport async function getLogs(fileService: IFileService, environmentService: IEnvironmentService): Promise {\n\tconst result: ILogFile[] = [];\n\n\tawait doGetLogs(fileService, result, environmentService.logsHome, environmentService.logsHome);\n\n\treturn result;\n}\n\nasync function doGetLogs(fileService: IFileService, logs: ILogFile[], curFolder: URI, logsHome: URI): Promise {\n\tconst stat = await fileService.resolve(curFolder);\n\n\tfor (const { resource, isDirectory } of stat.children || []) {\n\t\tif (isDirectory) {\n\t\t\tawait doGetLogs(fileService, logs, resource, logsHome);\n\t\t} else {\n\t\t\tconst contents = (await fileService.readFile(resource)).value.toString();\n\t\t\tif (contents) {\n\t\t\t\tconst path = relativePath(logsHome, resource);\n\t\t\t\tif (path) {\n\t\t\t\t\tlogs.push({ relativePath: path, contents });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction logLevelToString(level: LogLevel): string {\n\tswitch (level) {\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}\n\treturn 'info';\n}\n\n/**\n * A logger that is used when VSCode is running in the web with\n * an automation such as playwright. We expect a global codeAutomationLog\n * to be defined that we can use to log to.\n */\nexport class ConsoleLogInAutomationLogger extends AdapterLogger implements ILogger {\n\n\tdeclare codeAutomationLog: any;\n\n\tconstructor(logLevel: LogLevel = DEFAULT_LOG_LEVEL) {\n\t\tsuper({ log: (level, args) => this.consoleLog(logLevelToString(level), args) }, logLevel);\n\t}\n\n\tprivate consoleLog(type: string, args: any[]): void {\n\t\tconst automatedWindow = mainWindow as unknown as IAutomatedWindow;\n\t\tif (typeof automatedWindow.codeAutomationLog === 'function') {\n\t\t\ttry {\n\t\t\t\tautomatedWindow.codeAutomationLog(type, args);\n\t\t\t} catch (err) {\n\t\t\t\t// see https://github.com/microsoft/vscode-test-web/issues/69\n\t\t\t\tconsole.error('Problems writing to codeAutomationLog', err);\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 { AbstractMessageLogger, DEFAULT_LOG_LEVEL, ILogger, log, LogLevel } from 'vs/platform/log/common/log';\n\ninterface ILog {\n\tlevel: LogLevel;\n\tmessage: string;\n}\n\nexport class BufferLogger extends AbstractMessageLogger {\n\n\tdeclare readonly _serviceBrand: undefined;\n\tprivate buffer: ILog[] = [];\n\tprivate _logger: ILogger | undefined = undefined;\n\n\tconstructor(logLevel: LogLevel = DEFAULT_LOG_LEVEL) {\n\t\tsuper();\n\t\tthis.setLevel(logLevel);\n\t\tthis._register(this.onDidChangeLogLevel(level => {\n\t\t\tthis._logger?.setLevel(level);\n\t\t}));\n\t}\n\n\tset logger(logger: ILogger) {\n\t\tthis._logger = logger;\n\n\t\tfor (const { level, message } of this.buffer) {\n\t\t\tlog(logger, level, message);\n\t\t}\n\n\t\tthis.buffer = [];\n\t}\n\n\tprotected log(level: LogLevel, message: string): void {\n\t\tif (this._logger) {\n\t\t\tlog(this._logger, level, message);\n\t\t} else if (this.getLevel() <= level) {\n\t\t\tthis.buffer.push({ level, message });\n\t\t}\n\t}\n\n\toverride dispose(): void {\n\t\tthis._logger?.dispose();\n\t\tsuper.dispose();\n\t}\n\n\toverride flush(): void {\n\t\tthis._logger?.flush();\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { VSBuffer } from 'vs/base/common/buffer';\nimport { basename, dirname, joinPath } from 'vs/base/common/resources';\nimport { URI } from 'vs/base/common/uri';\nimport { ByteSize, FileOperationError, FileOperationResult, IFileService, whenProviderRegistered } from 'vs/platform/files/common/files';\nimport { BufferLogger } from 'vs/platform/log/common/bufferLog';\nimport { AbstractLoggerService, AbstractMessageLogger, ILogger, ILoggerOptions, ILoggerService, LogLevel } from 'vs/platform/log/common/log';\n\nconst MAX_FILE_SIZE = 5 * ByteSize.MB;\n\nclass FileLogger extends AbstractMessageLogger implements ILogger {\n\n\tprivate readonly initializePromise: Promise;\n\tprivate readonly flushDelayer: ThrottledDelayer;\n\tprivate backupIndex: number = 1;\n\tprivate buffer: string = '';\n\n\tconstructor(\n\t\tprivate readonly resource: URI,\n\t\tlevel: LogLevel,\n\t\tprivate readonly donotUseFormatters: boolean,\n\t\t@IFileService private readonly fileService: IFileService\n\t) {\n\t\tsuper();\n\t\tthis.setLevel(level);\n\t\tthis.flushDelayer = new ThrottledDelayer(100 /* buffer saves over a short time */);\n\t\tthis.initializePromise = this.initialize();\n\t}\n\n\toverride async flush(): Promise {\n\t\tif (!this.buffer) {\n\t\t\treturn;\n\t\t}\n\t\tawait this.initializePromise;\n\t\tlet content = await this.loadContent();\n\t\tif (content.length > MAX_FILE_SIZE) {\n\t\t\tawait this.fileService.writeFile(this.getBackupResource(), VSBuffer.fromString(content));\n\t\t\tcontent = '';\n\t\t}\n\t\tif (this.buffer) {\n\t\t\tcontent += this.buffer;\n\t\t\tthis.buffer = '';\n\t\t\tawait this.fileService.writeFile(this.resource, VSBuffer.fromString(content));\n\t\t}\n\t}\n\n\tprivate async initialize(): Promise {\n\t\ttry {\n\t\t\tawait this.fileService.createFile(this.resource);\n\t\t} catch (error) {\n\t\t\tif ((error).fileOperationResult !== FileOperationResult.FILE_MODIFIED_SINCE) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected log(level: LogLevel, message: string): void {\n\t\tif (this.donotUseFormatters) {\n\t\t\tthis.buffer += message;\n\t\t} else {\n\t\t\tthis.buffer += `${this.getCurrentTimestamp()} [${this.stringifyLogLevel(level)}] ${message}\\n`;\n\t\t}\n\t\tthis.flushDelayer.trigger(() => this.flush());\n\t}\n\n\tprivate getCurrentTimestamp(): string {\n\t\tconst toTwoDigits = (v: number) => v < 10 ? `0${v}` : v;\n\t\tconst toThreeDigits = (v: number) => v < 10 ? `00${v}` : v < 100 ? `0${v}` : v;\n\t\tconst currentTime = new Date();\n\t\treturn `${currentTime.getFullYear()}-${toTwoDigits(currentTime.getMonth() + 1)}-${toTwoDigits(currentTime.getDate())} ${toTwoDigits(currentTime.getHours())}:${toTwoDigits(currentTime.getMinutes())}:${toTwoDigits(currentTime.getSeconds())}.${toThreeDigits(currentTime.getMilliseconds())}`;\n\t}\n\n\tprivate getBackupResource(): URI {\n\t\tthis.backupIndex = this.backupIndex > 5 ? 1 : this.backupIndex;\n\t\treturn joinPath(dirname(this.resource), `${basename(this.resource)}_${this.backupIndex++}`);\n\t}\n\n\tprivate async loadContent(): Promise {\n\t\ttry {\n\t\t\tconst content = await this.fileService.readFile(this.resource);\n\t\t\treturn content.value.toString();\n\t\t} catch (e) {\n\t\t\treturn '';\n\t\t}\n\t}\n\n\tprivate stringifyLogLevel(level: LogLevel): string {\n\t\tswitch (level) {\n\t\t\tcase LogLevel.Debug: return 'debug';\n\t\t\tcase LogLevel.Error: return 'error';\n\t\t\tcase LogLevel.Info: return 'info';\n\t\t\tcase LogLevel.Trace: return 'trace';\n\t\t\tcase LogLevel.Warning: return 'warning';\n\t\t}\n\t\treturn '';\n\t}\n\n}\n\nexport class FileLoggerService extends AbstractLoggerService implements ILoggerService {\n\n\tconstructor(\n\t\tlogLevel: LogLevel,\n\t\tlogsHome: URI,\n\t\tprivate readonly fileService: IFileService,\n\t) {\n\t\tsuper(logLevel, logsHome);\n\t}\n\n\tprotected doCreateLogger(resource: URI, logLevel: LogLevel, options?: ILoggerOptions): ILogger {\n\t\tconst logger = new BufferLogger(logLevel);\n\t\twhenProviderRegistered(resource, this.fileService).then(() => logger.logger = new FileLogger(resource, logger.getLevel(), !!options?.donotUseFormatters, this.fileService));\n\t\treturn logger;\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { Event } from 'vs/base/common/event';\nimport { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';\nimport { AbstractLoggerService, AbstractMessageLogger, AdapterLogger, DidChangeLoggersEvent, ILogger, ILoggerOptions, ILoggerResource, ILoggerService, isLogLevel, LogLevel } from 'vs/platform/log/common/log';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { IURITransformer } from 'vs/base/common/uriIpc';\n\nexport class LoggerChannelClient extends AbstractLoggerService implements ILoggerService {\n\n\tconstructor(private readonly windowId: number | undefined, logLevel: LogLevel, logsHome: URI, loggers: ILoggerResource[], private readonly channel: IChannel) {\n\t\tsuper(logLevel, logsHome, loggers);\n\t\tthis._register(channel.listen('onDidChangeLogLevel', windowId)(arg => {\n\t\t\tif (isLogLevel(arg)) {\n\t\t\t\tsuper.setLogLevel(arg);\n\t\t\t} else {\n\t\t\t\tsuper.setLogLevel(URI.revive(arg[0]), arg[1]);\n\t\t\t}\n\t\t}));\n\t\tthis._register(channel.listen<[URI, boolean]>('onDidChangeVisibility', windowId)(([resource, visibility]) => super.setVisibility(URI.revive(resource), visibility)));\n\t\tthis._register(channel.listen('onDidChangeLoggers', windowId)(({ added, removed }) => {\n\t\t\tfor (const loggerResource of added) {\n\t\t\t\tsuper.registerLogger({ ...loggerResource, resource: URI.revive(loggerResource.resource) });\n\t\t\t}\n\t\t\tfor (const loggerResource of removed) {\n\t\t\t\tsuper.deregisterLogger(loggerResource.resource);\n\t\t\t}\n\t\t}));\n\t}\n\n\tcreateConsoleMainLogger(): ILogger {\n\t\treturn new AdapterLogger({\n\t\t\tlog: (level: LogLevel, args: any[]) => {\n\t\t\t\tthis.channel.call('consoleLog', [level, args]);\n\t\t\t}\n\t\t});\n\t}\n\n\toverride registerLogger(logger: ILoggerResource): void {\n\t\tsuper.registerLogger(logger);\n\t\tthis.channel.call('registerLogger', [logger, this.windowId]);\n\t}\n\n\toverride deregisterLogger(resource: URI): void {\n\t\tsuper.deregisterLogger(resource);\n\t\tthis.channel.call('deregisterLogger', [resource, this.windowId]);\n\t}\n\n\toverride setLogLevel(logLevel: LogLevel): void;\n\toverride setLogLevel(resource: URI, logLevel: LogLevel): void;\n\toverride setLogLevel(arg1: any, arg2?: any): void {\n\t\tsuper.setLogLevel(arg1, arg2);\n\t\tthis.channel.call('setLogLevel', [arg1, arg2]);\n\t}\n\n\toverride setVisibility(resourceOrId: URI | string, visibility: boolean): void {\n\t\tsuper.setVisibility(resourceOrId, visibility);\n\t\tthis.channel.call('setVisibility', [this.toResource(resourceOrId), visibility]);\n\t}\n\n\tprotected doCreateLogger(file: URI, logLevel: LogLevel, options?: ILoggerOptions): ILogger {\n\t\treturn new Logger(this.channel, file, logLevel, options, this.windowId);\n\t}\n\n\tpublic static setLogLevel(channel: IChannel, level: LogLevel): Promise;\n\tpublic static setLogLevel(channel: IChannel, resource: URI, level: LogLevel): Promise;\n\tpublic static setLogLevel(channel: IChannel, arg1: any, arg2?: any): Promise {\n\t\treturn channel.call('setLogLevel', [arg1, arg2]);\n\t}\n\n}\n\nclass Logger extends AbstractMessageLogger {\n\n\tprivate isLoggerCreated: boolean = false;\n\tprivate buffer: [LogLevel, string][] = [];\n\n\tconstructor(\n\t\tprivate readonly channel: IChannel,\n\t\tprivate readonly file: URI,\n\t\tlogLevel: LogLevel,\n\t\tloggerOptions?: ILoggerOptions,\n\t\twindowId?: number | undefined\n\t) {\n\t\tsuper(loggerOptions?.logLevel === 'always');\n\t\tthis.setLevel(logLevel);\n\t\tthis.channel.call('createLogger', [file, loggerOptions, windowId])\n\t\t\t.then(() => {\n\t\t\t\tthis.doLog(this.buffer);\n\t\t\t\tthis.isLoggerCreated = true;\n\t\t\t});\n\t}\n\n\tprotected log(level: LogLevel, message: string) {\n\t\tconst messages: [LogLevel, string][] = [[level, message]];\n\t\tif (this.isLoggerCreated) {\n\t\t\tthis.doLog(messages);\n\t\t} else {\n\t\t\tthis.buffer.push(...messages);\n\t\t}\n\t}\n\n\tprivate doLog(messages: [LogLevel, string][]) {\n\t\tthis.channel.call('log', [this.file, messages]);\n\t}\n}\n\nexport class LoggerChannel implements IServerChannel {\n\n\tconstructor(private readonly loggerService: ILoggerService, private getUriTransformer: (requestContext: any) => IURITransformer) { }\n\n\tlisten(context: any, event: string): Event {\n\t\tconst uriTransformer = this.getUriTransformer(context);\n\t\tswitch (event) {\n\t\t\tcase 'onDidChangeLoggers': return Event.map(this.loggerService.onDidChangeLoggers, (e) =>\n\t\t\t({\n\t\t\t\tadded: [...e.added].map(logger => this.transformLogger(logger, uriTransformer)),\n\t\t\t\tremoved: [...e.removed].map(logger => this.transformLogger(logger, uriTransformer)),\n\t\t\t}));\n\t\t\tcase 'onDidChangeVisibility': return Event.map<[URI, boolean], [URI, boolean]>(this.loggerService.onDidChangeVisibility, e => [uriTransformer.transformOutgoingURI(e[0]), e[1]]);\n\t\t\tcase 'onDidChangeLogLevel': return Event.map(this.loggerService.onDidChangeLogLevel, e => isLogLevel(e) ? e : [uriTransformer.transformOutgoingURI(e[0]), e[1]]);\n\t\t}\n\t\tthrow new Error(`Event not found: ${event}`);\n\t}\n\n\tasync call(context: any, command: string, arg?: any): Promise {\n\t\tconst uriTransformer: IURITransformer | null = this.getUriTransformer(context);\n\t\tswitch (command) {\n\t\t\tcase 'setLogLevel': return isLogLevel(arg[0]) ? this.loggerService.setLogLevel(arg[0]) : this.loggerService.setLogLevel(URI.revive(uriTransformer.transformIncoming(arg[0][0])), arg[0][1]);\n\t\t\tcase 'getRegisteredLoggers': return Promise.resolve([...this.loggerService.getRegisteredLoggers()].map(logger => this.transformLogger(logger, uriTransformer)));\n\t\t}\n\n\t\tthrow new Error(`Call not found: ${command}`);\n\t}\n\n\tprivate transformLogger(logger: ILoggerResource, transformer: IURITransformer): ILoggerResource {\n\t\treturn {\n\t\t\t...logger,\n\t\t\tresource: transformer.transformOutgoingURI(logger.resource)\n\t\t};\n\t}\n\n}\n\nexport class RemoteLoggerChannelClient extends Disposable {\n\n\tconstructor(loggerService: ILoggerService, channel: IChannel) {\n\t\tsuper();\n\n\t\tchannel.call('setLogLevel', [loggerService.getLogLevel()]);\n\t\tthis._register(loggerService.onDidChangeLogLevel(arg => channel.call('setLogLevel', [arg])));\n\n\t\tchannel.call('getRegisteredLoggers').then(loggers => {\n\t\t\tfor (const loggerResource of loggers) {\n\t\t\t\tloggerService.registerLogger({ ...loggerResource, resource: URI.revive(loggerResource.resource) });\n\t\t\t}\n\t\t});\n\n\t\tthis._register(channel.listen<[URI, boolean]>('onDidChangeVisibility')(([resource, visibility]) => loggerService.setVisibility(URI.revive(resource), visibility)));\n\n\t\tthis._register(channel.listen('onDidChangeLoggers')(({ added, removed }) => {\n\t\t\tfor (const loggerResource of added) {\n\t\t\t\tloggerService.registerLogger({ ...loggerResource, resource: URI.revive(loggerResource.resource) });\n\t\t\t}\n\t\t\tfor (const loggerResource of removed) {\n\t\t\t\tloggerService.deregisterLogger(loggerResource.resource);\n\t\t\t}\n\t\t}));\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 { 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\tflush(): void {\n\t\tthis.logger.flush();\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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\tgetStatistics(): MarkerStatistics;\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, IDisposable, toDisposable } 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\tregisterProvider(provider: IMarkerListProvider): IDisposable;\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\tregisterProvider(provider: IMarkerListProvider): IDisposable {\n\t\tconst remove = this._provider.unshift(provider);\n\t\treturn toDisposable(() => remove());\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([Schemas.inMemory, Schemas.vscodeSourceControl, Schemas.walkThrough, Schemas.walkThroughSnippet]);\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\tgetStatistics(): MarkerStatistics {\n\t\treturn this._stats;\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","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 } from 'vs/base/common/actions';\nimport { Event } from 'vs/base/common/event';\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 enum NotificationPriority {\n\n\t/**\n\t * Default priority: notification will be visible unless do not disturb mode is enabled.\n\t */\n\tDEFAULT,\n\n\t/**\n\t * Silent priority: notification will only be visible from the notifications center.\n\t */\n\tSILENT,\n\n\t/**\n\t * Urgent priority: notification will be visible even when do not disturb mode is enabled.\n\t */\n\tURGENT\n}\n\nexport interface INotificationProperties {\n\n\t/**\n\t * Sticky notifications are not automatically removed after a certain timeout.\n\t *\n\t * Currently, only 2 kinds of notifications are sticky:\n\t * - Error notifications with primary actions\n\t * - Notifications that show progress\n\t */\n\treadonly sticky?: boolean;\n\n\t/**\n\t * Allows to override the priority of the notification based on needs.\n\t */\n\treadonly priority?: NotificationPriority;\n\n\t/**\n\t * Adds an action to never show the notification again. The choice will be persisted\n\t * such as future requests will not cause the notification to show again.\n\t */\n\treadonly neverShowAgain?: INeverShowAgainOptions;\n}\n\nexport enum NeverShowAgainScope {\n\n\t/**\n\t * Will never show this notification on the current workspace again.\n\t */\n\tWORKSPACE,\n\n\t/**\n\t * Will never show this notification on any workspace of the same\n\t * profile again.\n\t */\n\tPROFILE,\n\n\t/**\n\t * Will never show this notification on any workspace across all\n\t * profiles again.\n\t */\n\tAPPLICATION\n}\n\nexport interface INeverShowAgainOptions {\n\n\t/**\n\t * The id is used to persist the selection of not showing the notification again.\n\t */\n\treadonly id: string;\n\n\t/**\n\t * By default the action will show up as primary action. Setting this to true will\n\t * make it a secondary action instead.\n\t */\n\treadonly isSecondary?: boolean;\n\n\t/**\n\t * Whether to persist the choice in the current workspace or for all workspaces. By\n\t * default it will be persisted for all workspaces across all profiles\n\t * (= `NeverShowAgainScope.APPLICATION`).\n\t */\n\treadonly scope?: NeverShowAgainScope;\n}\n\nexport interface INotificationSource {\n\n\t/**\n\t * The id of the source.\n\t */\n\treadonly id: string;\n\n\t/**\n\t * The label of the source.\n\t */\n\treadonly label: string;\n}\n\nexport function isNotificationSource(thing: unknown): thing is INotificationSource {\n\tif (thing) {\n\t\tconst candidate = thing as INotificationSource;\n\n\t\treturn typeof candidate.id === 'string' && typeof candidate.label === 'string';\n\t}\n\n\treturn false;\n}\n\nexport interface INotification extends INotificationProperties {\n\n\t/**\n\t * The id of the notification. If provided, will be used to compare\n\t * notifications with others to decide whether a notification is\n\t * duplicate or not.\n\t */\n\treadonly id?: string;\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\t/**\n\t * Actions to show as part of the notification. Primary actions show up as\n\t * buttons as part of the message and will close the notification once clicked.\n\t *\n\t * Secondary actions are meant to provide additional configuration or context\n\t * for the notification and will show up less prominent. A notification does not\n\t * close automatically when invoking a secondary action.\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\tactions?: INotificationActions;\n\n\t/**\n\t * The initial set of progress properties for the notification. To update progress\n\t * later on, access the `INotificationHandle.progress` property.\n\t */\n\treadonly progress?: INotificationProgressProperties;\n}\n\nexport interface INotificationActions {\n\n\t/**\n\t * Primary actions show up as buttons as part of the message and will close\n\t * the notification once clicked.\n\t *\n\t * Pass `ActionWithMenuAction` for an action that has additional menu actions.\n\t */\n\treadonly primary?: readonly IAction[];\n\n\t/**\n\t * Secondary actions are meant to provide additional configuration or context\n\t * for the notification and will show up less prominent. A notification does not\n\t * close automatically when invoking a secondary action.\n\t */\n\treadonly secondary?: readonly IAction[];\n}\n\nexport interface INotificationProgressProperties {\n\n\t/**\n\t * Causes the progress bar to spin infinitley.\n\t */\n\treadonly infinite?: boolean;\n\n\t/**\n\t * Indicate the total amount of work.\n\t */\n\treadonly total?: number;\n\n\t/**\n\t * Indicate that a specific chunk of work is done.\n\t */\n\treadonly worked?: number;\n}\n\nexport interface INotificationProgress {\n\n\t/**\n\t * Causes the progress bar to spin infinitley.\n\t */\n\tinfinite(): void;\n\n\t/**\n\t * Indicate the total amount of work.\n\t */\n\ttotal(value: number): void;\n\n\t/**\n\t * Indicate that a specific chunk of work is done.\n\t */\n\tworked(value: number): void;\n\n\t/**\n\t * Indicate that the long running operation is done.\n\t */\n\tdone(): void;\n}\n\nexport interface INotificationHandle {\n\n\t/**\n\t * Will be fired once the notification is closed.\n\t */\n\treadonly onDidClose: Event;\n\n\t/**\n\t * Will be fired whenever the visibility of the notification changes.\n\t * A notification can either be visible as toast or inside the notification\n\t * center if it is visible.\n\t */\n\treadonly onDidChangeVisibility: Event;\n\n\t/**\n\t * Allows to indicate progress on the notification even after the\n\t * notification is already visible.\n\t */\n\treadonly progress: INotificationProgress;\n\n\t/**\n\t * Allows to update the severity of the notification.\n\t */\n\tupdateSeverity(severity: Severity): void;\n\n\t/**\n\t * Allows to update the message of the notification even after the\n\t * notification is already visible.\n\t */\n\tupdateMessage(message: NotificationMessage): void;\n\n\t/**\n\t * Allows to update the actions of the notification even after the\n\t * notification is already visible.\n\t */\n\tupdateActions(actions?: INotificationActions): void;\n\n\t/**\n\t * Hide the notification and remove it from the notification center.\n\t */\n\tclose(): void;\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 * Whether to keep the notification open after the choice was selected\n\t * by the user. By default, will close the notification upon click.\n\t */\n\treadonly keepOpen?: boolean;\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\t/**\n\t * Primary choices show up as buttons in the notification below the message.\n\t * Secondary choices show up under the gear icon in the header of the notification.\n\t */\n\treadonly isSecondary?: boolean;\n}\n\nexport interface IPromptChoiceWithMenu extends IPromptChoice {\n\n\t/**\n\t * Additional choices those will be shown in the dropdown menu for this choice.\n\t */\n\treadonly menu: IBasePromptChoice[];\n\n\t/**\n\t * Menu is not supported on secondary choices\n\t */\n\treadonly isSecondary: false | undefined;\n}\n\nexport interface IPromptOptions extends INotificationProperties {\n\n\t/**\n\t * Will be called if the user closed the notification without picking\n\t * any of the provided choices.\n\t */\n\tonCancel?: () => void;\n}\n\nexport interface IStatusMessageOptions {\n\n\t/**\n\t * An optional timeout after which the status message should show. By default\n\t * the status message will show immediately.\n\t */\n\treadonly showAfter?: number;\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\nexport enum NotificationsFilter {\n\n\t/**\n\t * No filter is enabled.\n\t */\n\tOFF,\n\n\t/**\n\t * All notifications are silent except error notifications.\n\t*/\n\tERROR\n}\n\nexport interface INotificationSourceFilter extends INotificationSource {\n\treadonly filter: NotificationsFilter;\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 * Emitted when a new notification is added.\n\t */\n\treadonly onDidAddNotification: Event;\n\n\t/**\n\t * Emitted when a notification is removed.\n\t */\n\treadonly onDidRemoveNotification: Event;\n\n\t/**\n\t * Emitted when the notifications filter changed.\n\t */\n\treadonly onDidChangeFilter: Event;\n\n\t/**\n\t * Sets a notification filter either for all notifications\n\t * or for a specific source.\n\t */\n\tsetFilter(filter: NotificationsFilter | INotificationSourceFilter): void;\n\n\t/**\n\t * Gets the notification filter either for all notifications\n\t * or for a specific source.\n\t */\n\tgetFilter(source?: INotificationSource): NotificationsFilter;\n\n\t/**\n\t * Returns all filters with their sources.\n\t */\n\tgetFilters(): INotificationSourceFilter[];\n\n\t/**\n\t * Removes a filter for a specific source.\n\t */\n\tremoveFilter(sourceId: string): void;\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\treadonly progress = new NoOpProgress();\n\n\treadonly onDidClose = Event.None;\n\treadonly onDidChangeVisibility = Event.None;\n\n\tupdateSeverity(severity: Severity): void { }\n\tupdateMessage(message: NotificationMessage): void { }\n\tupdateActions(actions?: INotificationActions): void { }\n\n\tclose(): void { }\n}\n\nexport class NoOpProgress implements INotificationProgress {\n\tinfinite(): void { }\n\tdone(): void { }\n\ttotal(value: number): void { }\n\tworked(value: 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 { 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 * Register a participant that can validate if the URI resource be opened.\n\t * Validators are run before openers.\n\t */\n\tregisterValidator(validator: IValidator): IDisposable;\n\n\t/**\n\t * Register a participant that can resolve an external URI resource to be opened.\n\t */\n\tregisterExternalUriResolver(resolver: IExternalUriResolver): IDisposable;\n\n\t/**\n\t * Sets the handler for opening externally. If not provided,\n\t * a default handler will be used.\n\t */\n\tsetDefaultExternalOpener(opener: IExternalOpener): void;\n\n\t/**\n\t * Registers a new opener external resources openers.\n\t */\n\tregisterExternalOpener(opener: IExternalOpener): 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\t/**\n\t * Resolve a resource to its external form.\n\t * @throws whenever resolvers couldn't resolve this resource externally.\n\t */\n\tresolveExternalUri(resource: URI, options?: ResolveExternalUriOptions): Promise;\n}\n\n/**\n * Encodes selection into the `URI`.\n *\n * IMPORTANT: you MUST use `extractSelection` to separate the selection\n * again from the original `URI` before passing the `URI` into any\n * component that is not aware of selections.\n */\nexport function withSelection(uri: URI, selection: ITextEditorSelection): URI {\n\treturn uri.with({ fragment: `${selection.startLineNumber},${selection.startColumn}${selection.endLineNumber ? `-${selection.endLineNumber}${selection.endColumn ? `,${selection.endColumn}` : ''}` : ''}` });\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\tregisterValidator(validator: IValidator): IDisposable {\n\t\tconst remove = this._validators.push(validator);\n\t\treturn { dispose: remove };\n\t}\n\n\tregisterExternalUriResolver(resolver: IExternalUriResolver): IDisposable {\n\t\tconst remove = this._resolvers.push(resolver);\n\t\treturn { dispose: remove };\n\t}\n\n\tsetDefaultExternalOpener(externalOpener: IExternalOpener): void {\n\t\tthis._defaultExternalOpener = externalOpener;\n\t}\n\n\tregisterExternalOpener(opener: IExternalOpener): IDisposable {\n\t\tconst remove = this._externalOpeners.push(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, clearNode } 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';\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 textLinkForeground?: string;\n}\n\nexport class Link extends Disposable {\n\n\tprivate el: HTMLAnchorElement;\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\tset link(link: ILinkDescriptor) {\n\t\tif (typeof link.label === 'string') {\n\t\t\tthis.el.textContent = link.label;\n\t\t} else {\n\t\t\tclearNode(this.el);\n\t\t\tthis.el.appendChild(link.label);\n\t\t}\n\n\t\tthis.el.href = link.href;\n\n\t\tif (typeof link.tabIndex !== 'undefined') {\n\t\t\tthis.el.tabIndex = link.tabIndex;\n\t\t}\n\n\t\tif (typeof link.title !== 'undefined') {\n\t\t\tthis.el.title = link.title;\n\t\t}\n\n\t\tthis._link = link;\n\t}\n\n\tconstructor(\n\t\tcontainer: HTMLElement,\n\t\tprivate _link: ILinkDescriptor,\n\t\toptions: ILinkOptions = {},\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\ttitle: _link.title\n\t\t}, _link.label));\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","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { IStringDictionary } from 'vs/base/common/collections';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { Iterable } from 'vs/base/common/iterator';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\n\nexport type PolicyName = string;\nexport type PolicyValue = string | number;\nexport type PolicyDefinition = { type: 'string' | 'number' };\n\nexport const IPolicyService = createDecorator('policy');\n\nexport interface IPolicyService {\n\treadonly _serviceBrand: undefined;\n\n\treadonly onDidChange: Event;\n\tupdatePolicyDefinitions(policyDefinitions: IStringDictionary): Promise>;\n\tgetPolicyValue(name: PolicyName): PolicyValue | undefined;\n\tserialize(): IStringDictionary<{ definition: PolicyDefinition; value: PolicyValue }> | undefined;\n}\n\nexport abstract class AbstractPolicyService extends Disposable implements IPolicyService {\n\treadonly _serviceBrand: undefined;\n\n\tprotected policyDefinitions: IStringDictionary = {};\n\tprotected policies = new Map();\n\n\tprotected readonly _onDidChange = this._register(new Emitter());\n\treadonly onDidChange = this._onDidChange.event;\n\n\tasync updatePolicyDefinitions(policyDefinitions: IStringDictionary): Promise> {\n\t\tconst size = Object.keys(this.policyDefinitions).length;\n\t\tthis.policyDefinitions = { ...policyDefinitions, ...this.policyDefinitions };\n\n\t\tif (size !== Object.keys(this.policyDefinitions).length) {\n\t\t\tawait this._updatePolicyDefinitions(policyDefinitions);\n\t\t}\n\n\t\treturn Iterable.reduce(this.policies.entries(), (r, [name, value]) => ({ ...r, [name]: value }), {});\n\t}\n\n\tgetPolicyValue(name: PolicyName): PolicyValue | undefined {\n\t\treturn this.policies.get(name);\n\t}\n\n\tserialize(): IStringDictionary<{ definition: PolicyDefinition; value: PolicyValue }> {\n\t\treturn Iterable.reduce<[PolicyName, PolicyDefinition], IStringDictionary<{ definition: PolicyDefinition; value: PolicyValue }>>(Object.entries(this.policyDefinitions), (r, [name, definition]) => ({ ...r, [name]: { definition, value: this.policies.get(name)! } }), {});\n\t}\n\n\tprotected abstract _updatePolicyDefinitions(policyDefinitions: IStringDictionary): Promise;\n}\n\nexport class NullPolicyService implements IPolicyService {\n\treadonly _serviceBrand: undefined;\n\treadonly onDidChange = Event.None;\n\tasync updatePolicyDefinitions() { return {}; }\n\tgetPolicyValue() { return undefined; }\n\tserialize() { return 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 { env } from 'vs/base/common/process';\nimport { IProductConfiguration } from 'vs/base/common/product';\nimport { ISandboxConfiguration } from 'vs/base/parts/sandbox/common/sandboxTypes';\n\n/**\n * @deprecated You MUST use `IProductService` if possible.\n */\nlet product: IProductConfiguration;\n\n// Native sandbox environment\nconst vscodeGlobal = (globalThis as any).vscode;\nif (typeof vscodeGlobal !== 'undefined' && typeof vscodeGlobal.context !== 'undefined') {\n\tconst configuration: ISandboxConfiguration | undefined = vscodeGlobal.context.configuration();\n\tif (configuration) {\n\t\tproduct = configuration.product;\n\t} else {\n\t\tthrow new Error('Sandbox: unable to resolve product configuration from preload script.');\n\t}\n}\n// _VSCODE environment\nelse if (globalThis._VSCODE_PRODUCT_JSON && globalThis._VSCODE_PACKAGE_JSON) {\n\t// Obtain values from product.json and package.json-data\n\tproduct = globalThis._VSCODE_PRODUCT_JSON as unknown as IProductConfiguration;\n\n\t// Running out of sources\n\tif (env['VSCODE_DEV']) {\n\t\tObject.assign(product, {\n\t\t\tnameShort: `${product.nameShort} Dev`,\n\t\t\tnameLong: `${product.nameLong} Dev`,\n\t\t\tdataFolderName: `${product.dataFolderName}-dev`,\n\t\t\tserverDataFolderName: product.serverDataFolderName ? `${product.serverDataFolderName}-dev` : undefined\n\t\t});\n\t}\n\n\t// Version is added during built time, but we still\n\t// want to have it running out of sources so we\n\t// read it from package.json only when we need it.\n\tif (!product.version) {\n\t\tconst pkg = globalThis._VSCODE_PACKAGE_JSON as { version: string };\n\n\t\tObject.assign(product, {\n\t\t\tversion: pkg.version\n\t\t});\n\t}\n}\n\n// Web environment or unknown\nelse {\n\n\t// Built time configuration (do NOT modify)\n\tproduct = { /*BUILD->INSERT_PRODUCT_CONFIGURATION*/ } as IProductConfiguration;\n\n\t// Running out of sources\n\tif (Object.keys(product).length === 0) {\n\t\tObject.assign(product, {\n\t\t\tversion: '1.87.0-dev',\n\t\t\tnameShort: 'Code - OSS Dev',\n\t\t\tnameLong: 'Code - OSS Dev',\n\t\t\tapplicationName: 'code-oss',\n\t\t\tdataFolderName: '.vscode-oss',\n\t\t\turlProtocol: 'code-oss',\n\t\t\treportIssueUrl: 'https://github.com/microsoft/vscode/issues/new',\n\t\t\tlicenseName: 'MIT',\n\t\t\tlicenseUrl: 'https://github.com/microsoft/vscode/blob/main/LICENSE.txt',\n\t\t\tserverLicenseUrl: 'https://github.com/microsoft/vscode/blob/main/LICENSE.txt'\n\t\t});\n\t}\n}\n\n/**\n * @deprecated You MUST use `IProductService` if possible.\n */\nexport default product;\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { IProductConfiguration } from 'vs/base/common/product';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\n\nexport const IProductService = createDecorator('productService');\n\nexport interface IProductService extends Readonly {\n\n\treadonly _serviceBrand: undefined;\n\n}\n\nexport const productSchemaId = 'vscode://schemas/vscode-product';\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 } from 'vs/base/common/actions';\nimport { DeferredPromise } from 'vs/base/common/async';\nimport { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';\nimport { Disposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\nimport { INotificationSource, NotificationPriority } from 'vs/platform/notification/common/notification';\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\treadonly source?: string | INotificationSource;\n\treadonly total?: number;\n\treadonly cancellable?: boolean;\n\treadonly buttons?: string[];\n}\n\nexport interface IProgressNotificationOptions extends IProgressOptions {\n\treadonly location: ProgressLocation.Notification;\n\treadonly primaryActions?: readonly IAction[];\n\treadonly secondaryActions?: readonly IAction[];\n\treadonly delay?: number;\n\treadonly priority?: NotificationPriority;\n\treadonly type?: 'syncing' | 'loading';\n}\n\nexport interface IProgressDialogOptions extends IProgressOptions {\n\treadonly delay?: number;\n\treadonly detail?: string;\n\treadonly sticky?: boolean;\n}\n\nexport interface IProgressWindowOptions extends IProgressOptions {\n\treadonly location: ProgressLocation.Window;\n\treadonly command?: string;\n\treadonly type?: 'syncing' | 'loading';\n}\n\nexport interface IProgressCompositeOptions extends IProgressOptions {\n\treadonly location: ProgressLocation.Explorer | ProgressLocation.Extensions | ProgressLocation.Scm | string;\n\treadonly delay?: number;\n}\n\nexport interface IProgressStep {\n\tmessage?: string;\n\tincrement?: number;\n\ttotal?: number;\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\tget value(): T | undefined { return this._value; }\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 class AsyncProgress implements IProgress {\n\n\tprivate _value?: T;\n\tget value(): T | undefined { return this._value; }\n\n\tprivate _asyncQueue?: T[];\n\tprivate _processingAsyncQueue?: boolean;\n\tprivate _drainListener: (() => void) | undefined;\n\n\tconstructor(private callback: (data: T) => unknown) { }\n\n\treport(item: T) {\n\t\tif (!this._asyncQueue) {\n\t\t\tthis._asyncQueue = [item];\n\t\t} else {\n\t\t\tthis._asyncQueue.push(item);\n\t\t}\n\t\tthis._processAsyncQueue();\n\t}\n\n\tprivate async _processAsyncQueue() {\n\t\tif (this._processingAsyncQueue) {\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\tthis._processingAsyncQueue = true;\n\n\t\t\twhile (this._asyncQueue && this._asyncQueue.length) {\n\t\t\t\tconst item = this._asyncQueue.shift()!;\n\t\t\t\tthis._value = item;\n\t\t\t\tawait this.callback(this._value);\n\t\t\t}\n\n\t\t} finally {\n\t\t\tthis._processingAsyncQueue = false;\n\t\t\tconst drainListener = this._drainListener;\n\t\t\tthis._drainListener = undefined;\n\t\t\tdrainListener?.();\n\t\t}\n\t}\n\n\tdrain(): Promise {\n\t\tif (this._processingAsyncQueue) {\n\t\t\treturn new Promise(resolve => {\n\t\t\t\tconst prevListener = this._drainListener;\n\t\t\t\tthis._drainListener = () => {\n\t\t\t\t\tprevListener?.();\n\t\t\t\t\tresolve();\n\t\t\t\t};\n\t\t\t});\n\t\t}\n\t\treturn Promise.resolve();\n\t}\n}\n\n/**\n * A helper to show progress during a long running operation. If the operation\n * is started multiple times, only the last invocation will drive the progress.\n */\nexport interface IOperation {\n\tid: number;\n\tisCurrent: () => boolean;\n\ttoken: CancellationToken;\n\tstop(): void;\n}\n\n/**\n * RAII-style progress instance that allows imperative reporting and hides\n * once `dispose()` is called.\n */\nexport class UnmanagedProgress extends Disposable {\n\tprivate readonly deferred = new DeferredPromise();\n\tprivate reporter?: IProgress;\n\tprivate lastStep?: IProgressStep;\n\n\tconstructor(\n\t\toptions: IProgressOptions | IProgressDialogOptions | IProgressNotificationOptions | IProgressWindowOptions | IProgressCompositeOptions,\n\t\t@IProgressService progressService: IProgressService,\n\t) {\n\t\tsuper();\n\t\tprogressService.withProgress(options, reporter => {\n\t\t\tthis.reporter = reporter;\n\t\t\tif (this.lastStep) {\n\t\t\t\treporter.report(this.lastStep);\n\t\t\t}\n\n\t\t\treturn this.deferred.p;\n\t\t});\n\n\t\tthis._register(toDisposable(() => this.deferred.complete()));\n\t}\n\n\treport(step: IProgressStep) {\n\t\tif (this.reporter) {\n\t\t\tthis.reporter.report(step);\n\t\t} else {\n\t\t\tthis.lastStep = step;\n\t\t}\n\t}\n}\n\nexport class LongRunningOperation extends Disposable {\n\tprivate currentOperationId = 0;\n\tprivate readonly currentOperationDisposables = this._register(new DisposableStore());\n\tprivate currentProgressRunner: IProgressRunner | undefined;\n\tprivate currentProgressTimeout: any;\n\n\tconstructor(\n\t\tprivate progressIndicator: IProgressIndicator\n\t) {\n\t\tsuper();\n\t}\n\n\tstart(progressDelay: number): IOperation {\n\n\t\t// Stop any previous operation\n\t\tthis.stop();\n\n\t\t// Start new\n\t\tconst newOperationId = ++this.currentOperationId;\n\t\tconst newOperationToken = new CancellationTokenSource();\n\t\tthis.currentProgressTimeout = setTimeout(() => {\n\t\t\tif (newOperationId === this.currentOperationId) {\n\t\t\t\tthis.currentProgressRunner = this.progressIndicator.show(true);\n\t\t\t}\n\t\t}, progressDelay);\n\n\t\tthis.currentOperationDisposables.add(toDisposable(() => clearTimeout(this.currentProgressTimeout)));\n\t\tthis.currentOperationDisposables.add(toDisposable(() => newOperationToken.cancel()));\n\t\tthis.currentOperationDisposables.add(toDisposable(() => this.currentProgressRunner ? this.currentProgressRunner.done() : undefined));\n\n\t\treturn {\n\t\t\tid: newOperationId,\n\t\t\ttoken: newOperationToken.token,\n\t\t\tstop: () => this.doStop(newOperationId),\n\t\t\tisCurrent: () => this.currentOperationId === newOperationId\n\t\t};\n\t}\n\n\tstop(): void {\n\t\tthis.doStop(this.currentOperationId);\n\t}\n\n\tprivate doStop(operationId: number): void {\n\t\tif (this.currentOperationId === operationId) {\n\t\t\tthis.currentOperationDisposables.clear();\n\t\t}\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 } 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 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\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\t// Trigger the pick with button index if button triggered\n\t\tdisposables.add(picker.onDidTriggerItemButton(async ({ button, item }) => {\n\t\t\tif (typeof item.trigger === 'function') {\n\t\t\t\tconst buttonIndex = item.buttons?.indexOf(button) ?? -1;\n\t\t\t\tif (buttonIndex >= 0) {\n\t\t\t\t\tconst result = item.trigger(buttonIndex, picker.keyMods);\n\t\t\t\t\tconst action = (typeof result === 'number') ? result : await result;\n\n\t\t\t\t\tif (token.isCancellationRequested) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tswitch (action) {\n\t\t\t\t\t\tcase TriggerAction.NO_ACTION:\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase TriggerAction.CLOSE_PICKER:\n\t\t\t\t\t\t\tpicker.hide();\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase TriggerAction.REFRESH_PICKER:\n\t\t\t\t\t\t\tupdatePickerItems();\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase TriggerAction.REMOVE_ITEM: {\n\t\t\t\t\t\t\tconst index = picker.items.indexOf(item);\n\t\t\t\t\t\t\tif (index !== -1) {\n\t\t\t\t\t\t\t\tconst items = picker.items.slice();\n\t\t\t\t\t\t\t\tconst removed = items.splice(index, 1);\n\t\t\t\t\t\t\t\tconst activeItems = picker.activeItems.filter(activeItem => activeItem !== removed[0]);\n\t\t\t\t\t\t\t\tconst keepScrollPositionBefore = picker.keepScrollPosition;\n\t\t\t\t\t\t\t\tpicker.keepScrollPosition = true;\n\t\t\t\t\t\t\t\tpicker.items = items;\n\t\t\t\t\t\t\t\tif (activeItems) {\n\t\t\t\t\t\t\t\t\tpicker.activeItems = activeItems;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tpicker.keepScrollPosition = keepScrollPositionBefore;\n\t\t\t\t\t\t\t}\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\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 { StandardMouseEvent } from 'vs/base/browser/mouseEvent';\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\tonMouseDown = (handler: (event: StandardMouseEvent) => void): IDisposable => {\n\t\treturn dom.addStandardDisposableListener(this.findInput.inputBox.inputElement, dom.EventType.MOUSE_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\tisSelectionAtEnd(): boolean {\n\t\treturn this.findInput.inputBox.isSelectionAtEnd();\n\t}\n\n\tsetPlaceholder(placeholder: string): void {\n\t\tthis.findInput.inputBox.setPlaceHolder(placeholder);\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\thasFocus(): boolean {\n\t\treturn this.findInput.inputBox.hasFocus();\n\t}\n\n\tsetAttribute(name: string, value: string): void {\n\t\tthis.findInput.inputBox.inputElement.setAttribute(name, value);\n\t}\n\n\tremoveAttribute(name: string): void {\n\t\tthis.findInput.inputBox.inputElement.removeAttribute(name);\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 { Codicon } from 'vs/base/common/codicons';\nimport { localize } from 'vs/nls';\nimport { IQuickPick, IQuickPickItem, QuickPickItem } from 'vs/platform/quickinput/common/quickInput';\nimport { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';\nimport { ThemeIcon } from 'vs/base/common/themables';\n\nconst pinButtonClass = ThemeIcon.asClassName(Codicon.pin);\nconst pinnedButtonClass = ThemeIcon.asClassName(Codicon.pinned);\nconst buttonClasses = [pinButtonClass, pinnedButtonClass];\n/**\n * Initially, adds pin buttons to all @param quickPick items.\n * When pinned, a copy of the item will be moved to the end of the pinned list and any duplicate within the pinned list will\n * be removed if @param filterDupliates has been provided. Pin and pinned button events trigger updates to the underlying storage.\n * Shows the quickpick once formatted.\n */\nexport async function showWithPinnedItems(storageService: IStorageService, storageKey: string, quickPick: IQuickPick, filterDuplicates?: boolean): Promise {\n\tconst itemsWithoutPinned = quickPick.items;\n\tlet itemsWithPinned = _formatPinnedItems(storageKey, quickPick, storageService, undefined, filterDuplicates);\n\tquickPick.onDidTriggerItemButton(async buttonEvent => {\n\t\tconst expectedButton = buttonEvent.button.iconClass && buttonClasses.includes(buttonEvent.button.iconClass);\n\t\tif (expectedButton) {\n\t\t\tquickPick.items = itemsWithoutPinned;\n\t\t\titemsWithPinned = _formatPinnedItems(storageKey, quickPick, storageService, buttonEvent.item, filterDuplicates);\n\t\t\tquickPick.items = quickPick.value ? itemsWithoutPinned : itemsWithPinned;\n\t\t}\n\t});\n\tquickPick.onDidChangeValue(async value => {\n\t\tif (quickPick.items === itemsWithPinned && value) {\n\t\t\tquickPick.items = itemsWithoutPinned;\n\t\t} else if (quickPick.items === itemsWithoutPinned && !value) {\n\t\t\tquickPick.items = itemsWithPinned;\n\t\t}\n\t});\n\n\tquickPick.items = quickPick.value ? itemsWithoutPinned : itemsWithPinned;\n\tquickPick.show();\n}\n\nfunction _formatPinnedItems(storageKey: string, quickPick: IQuickPick, storageService: IStorageService, changedItem?: IQuickPickItem, filterDuplicates?: boolean): QuickPickItem[] {\n\tconst formattedItems: QuickPickItem[] = [];\n\tlet pinnedItems;\n\tif (changedItem) {\n\t\tpinnedItems = updatePinnedItems(storageKey, changedItem, storageService);\n\t} else {\n\t\tpinnedItems = getPinnedItems(storageKey, storageService);\n\t}\n\tif (pinnedItems.length) {\n\t\tformattedItems.push({ type: 'separator', label: localize(\"terminal.commands.pinned\", 'pinned') });\n\t}\n\tconst pinnedIds = new Set();\n\tfor (const itemToFind of pinnedItems) {\n\t\tconst itemToPin = quickPick.items.find(item => itemsMatch(item, itemToFind));\n\t\tif (itemToPin) {\n\t\t\tconst pinnedItemId = getItemIdentifier(itemToPin);\n\t\t\tconst pinnedItem: IQuickPickItem = Object.assign({} as IQuickPickItem, itemToPin);\n\t\t\tif (!filterDuplicates || !pinnedIds.has(pinnedItemId)) {\n\t\t\t\tpinnedIds.add(pinnedItemId);\n\t\t\t\tupdateButtons(pinnedItem, false);\n\t\t\t\tformattedItems.push(pinnedItem);\n\t\t\t}\n\t\t}\n\t}\n\n\tfor (const item of quickPick.items) {\n\t\tupdateButtons(item, true);\n\t\tformattedItems.push(item);\n\t}\n\treturn formattedItems;\n}\n\nfunction getItemIdentifier(item: QuickPickItem): string {\n\treturn item.type === 'separator' ? '' : item.id || `${item.label}${item.description}${item.detail}}`;\n}\n\nfunction updateButtons(item: QuickPickItem, removePin: boolean): void {\n\tif (item.type === 'separator') {\n\t\treturn;\n\t}\n\n\t// remove button classes before adding the new one\n\tconst newButtons = item.buttons?.filter(button => button.iconClass && !buttonClasses.includes(button.iconClass)) ?? [];\n\tnewButtons.unshift({\n\t\ticonClass: removePin ? pinButtonClass : pinnedButtonClass,\n\t\ttooltip: removePin ? localize('pinCommand', \"Pin command\") : localize('pinnedCommand', \"Pinned command\"),\n\t\talwaysVisible: false\n\t});\n\titem.buttons = newButtons;\n}\n\nfunction itemsMatch(itemA: QuickPickItem, itemB: QuickPickItem): boolean {\n\treturn getItemIdentifier(itemA) === getItemIdentifier(itemB);\n}\n\nfunction updatePinnedItems(storageKey: string, changedItem: IQuickPickItem, storageService: IStorageService): IQuickPickItem[] {\n\tconst removePin = changedItem.buttons?.find(b => b.iconClass === pinnedButtonClass);\n\tlet items = getPinnedItems(storageKey, storageService);\n\tif (removePin) {\n\t\titems = items.filter(item => getItemIdentifier(item) !== getItemIdentifier(changedItem));\n\t} else {\n\t\titems.push(changedItem);\n\t}\n\tstorageService.store(storageKey, JSON.stringify(items), StorageScope.WORKSPACE, StorageTarget.MACHINE);\n\treturn items;\n}\n\nfunction getPinnedItems(storageKey: string, storageService: IStorageService): IQuickPickItem[] {\n\tconst items = storageService.get(storageKey, StorageScope.WORKSPACE);\n\treturn items ? JSON.parse(items) : [];\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { Schemas } from 'vs/base/common/network';\nimport Severity from 'vs/base/common/severity';\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\tid?: string;\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\talwaysShow?: boolean;\n}\n\nexport interface IQuickPickSeparator {\n\ttype: 'separator';\n\tid?: string;\n\tlabel?: 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 interface IInputOptions {\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 * the value to prefill in the input box\n\t */\n\tvalue?: string;\n\n\t/**\n\t * the selection of value, default to the whole prefilled value\n\t */\n\tvalueSelection?: readonly [number, number];\n\n\t/**\n\t * the text to display underneath the input box\n\t */\n\tprompt?: string;\n\n\t/**\n\t * an optional string to show as placeholder in the input box to guide the user what to type\n\t */\n\tplaceHolder?: string;\n\n\t/**\n\t * Controls if a password input is shown. Password input hides the typed text.\n\t */\n\tpassword?: boolean;\n\n\t/**\n\t * an optional flag to not close the input on focus lost\n\t */\n\tignoreFocusLost?: boolean;\n\n\t/**\n\t * an optional function that is used to validate user input.\n\t */\n\tvalidateInput?: (input: string) => Promise;\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 * 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 * An event that is fired when the quick input is hidden.\n\t */\n\treadonly onDidHide: Event;\n\n\t/**\n\t * An event that is fired when the quick input is disposed.\n\t */\n\treadonly onDispose: Event;\n\n\t/**\n\t * The title of the quick input.\n\t */\n\ttitle: string | undefined;\n\n\t/**\n\t * The description of the quick input. This is rendered right below the input box.\n\t */\n\tdescription: string | undefined;\n\n\t/**\n\t * An HTML widget rendered below the input.\n\t * @deprecated Use an IQuickWidget instead.\n\t */\n\twidget: any | undefined;\n\n\t/**\n\t * The current step of the quick input rendered in the titlebar.\n\t */\n\tstep: number | undefined;\n\n\t/**\n\t * The total number of steps in the quick input rendered in the titlebar.\n\t */\n\ttotalSteps: number | undefined;\n\n\t/**\n\t * The buttons displayed in the quick input titlebar.\n\t */\n\tbuttons: ReadonlyArray;\n\n\t/**\n\t * An event that is fired when a button in the quick input is triggered.\n\t */\n\treadonly onDidTriggerButton: Event;\n\n\t/**\n\t * Indicates whether the input is enabled.\n\t */\n\tenabled: boolean;\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\nexport interface IQuickWidget extends IQuickInput {\n\t/**\n\t * Should be an HTMLElement (TODO: move this entire file into browser)\n\t * @override\n\t */\n\twidget: any | undefined;\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 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 * The OK button state. It can be a boolean value or the string 'default'.\n\t */\n\tok: boolean | 'default';\n\n\t/**\n\t * An event that is fired when the custom button is triggered. The custom button is a button with text rendered to the right of the input.\n\t */\n\treadonly onDidCustom: Event;\n\n\t/**\n\t * Whether to show the custom button. The custom button is a button with text rendered to the right of the input.\n\t */\n\tcustomButton: boolean;\n\n\t/**\n\t * The label for the custom button. The custom button is a button with text rendered to the right of the input.\n\t */\n\tcustomLabel: string | undefined;\n\n\t/**\n\t * The hover text for the custom button. The custom button is a button with text rendered to the right of the input.\n\t */\n\tcustomHover: string | undefined;\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 * The mode to filter the label with. It can be 'fuzzy' or 'contiguous'. Defaults to 'fuzzy'.\n\t */\n\tmatchOnLabelMode: 'fuzzy' | 'contiguous';\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 * The validation message for the quick pick. This is rendered below the input.\n\t */\n\tvalidationMessage: string | undefined;\n\n\t/**\n\t * The severity of the validation message.\n\t */\n\tseverity: Severity;\n\n\t/**\n\t * Checks if the quick pick input has focus.\n\t * @returns `true` if the quick pick input has focus, `false` otherwise.\n\t */\n\tinputHasFocus(): boolean;\n\n\t/**\n\t * Focuses on the quick pick input.\n\t */\n\tfocusOnInput(): void;\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 * Controls whether the count for the items should be shown.\n\t */\n\thideCountBadge: boolean;\n\n\t/**\n\t * Whether to hide the \"Check All\" checkbox.\n\t */\n\thideCheckAll: boolean;\n\n\t/**\n\t * The toggle buttons to be added to the input box.\n\t */\n\ttoggles: IQuickInputToggle[] | undefined;\n}\n\n/**\n * Represents a toggle for quick input.\n */\nexport interface IQuickInputToggle {\n\t/**\n\t * Event that is fired when the toggle value changes.\n\t * The boolean value indicates whether the change was triggered via keyboard.\n\t */\n\tonChange: Event;\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 * Provide start and end values to be selected in the input box.\n\t */\n\tvalueSelection: Readonly<[number, number]> | undefined;\n\n\t/**\n\t * Value shown as example for input.\n\t */\n\tplaceholder: string | undefined;\n\n\t/**\n\t * Determines if the input value should be hidden while typing.\n\t */\n\tpassword: boolean;\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 * Text show below the input box.\n\t */\n\tprompt: string | undefined;\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\t/**\n\t * Severity of the input validation message.\n\t */\n\tseverity: Severity;\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\tgetItemLabel(entry: IQuickPickItemWithResource): string {\n\t\treturn entry.label;\n\t}\n\n\tgetItemDescription(entry: IQuickPickItemWithResource): string | undefined {\n\t\tif (this.options?.skipDescription) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn entry.description;\n\t}\n\n\tgetItemPath(entry: IQuickPickItemWithResource): string | undefined {\n\t\tif (this.options?.skipPath) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (entry.resource?.scheme === Schemas.file) {\n\t\t\treturn entry.resource.fsPath;\n\t\t}\n\n\t\treturn entry.resource?.path;\n\t}\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 back button in quick input.\n\t */\n\treadonly backButton: IQuickInputButton;\n\n\t/**\n\t * Provides access to the quick access providers.\n\t */\n\treadonly quickAccess: IQuickAccessController;\n\n\t/**\n\t * Allows to register on the event that quick input is showing.\n\t */\n\treadonly onShow: Event;\n\n\t/**\n\t * Allows to register on the event that quick input is hiding.\n\t */\n\treadonly onHide: Event;\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 * Opens the quick input box for text input and returns a promise with the user typed value if any.\n\t */\n\tinput(options?: IInputOptions, 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 * Provides raw access to the quick widget controller.\n\t */\n\tcreateQuickWidget(): IQuickWidget;\n\n\t/**\n\t * Moves focus into quick input.\n\t */\n\tfocus(): void;\n\n\t/**\n\t * Toggle the checked state of the selected item.\n\t */\n\ttoggle(): void;\n\n\t/**\n\t * Navigate inside the opened quick input list.\n\t */\n\tnavigate(next: boolean, quickNavigate?: IQuickNavigateConfiguration): void;\n\n\t/**\n\t * Navigate back in a multi-step quick input.\n\t */\n\tback(): Promise;\n\n\t/**\n\t * Accept the selected item.\n\t *\n\t * @param keyMods allows to override the state of key\n\t * modifiers that should be present when invoking.\n\t */\n\taccept(keyMods?: IKeyMods): Promise;\n\n\t/**\n\t * Cancels quick input and closes it.\n\t */\n\tcancel(): 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 * 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 true iff there is an extension with the provided id.\n\t * @param id an extension identifier\n\t */\n\tknows(id: string): boolean;\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 knows(id: string): boolean {\n\t\treturn this.data.has(id);\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","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { mainWindow } from 'vs/base/browser/window';\nimport { DragMouseEvent } from 'vs/base/browser/mouseEvent';\nimport { coalesce } from 'vs/base/common/arrays';\nimport { DeferredPromise } from 'vs/base/common/async';\nimport { VSBuffer } from 'vs/base/common/buffer';\nimport { ResourceMap } from 'vs/base/common/map';\nimport { parse } from 'vs/base/common/marshalling';\nimport { Schemas } from 'vs/base/common/network';\nimport { isWeb } from 'vs/base/common/platform';\nimport { URI } from 'vs/base/common/uri';\nimport { localize } from 'vs/nls';\nimport { IDialogService } from 'vs/platform/dialogs/common/dialogs';\nimport { IBaseTextResourceEditorInput } from 'vs/platform/editor/common/editor';\nimport { HTMLFileSystemProvider } from 'vs/platform/files/browser/htmlFileSystemProvider';\nimport { WebFileSystemAccess } from 'vs/platform/files/browser/webFileSystemAccess';\nimport { ByteSize, IFileService } from 'vs/platform/files/common/files';\nimport { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';\nimport { extractSelection } from 'vs/platform/opener/common/opener';\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 IDraggedResourceEditorInput extends IBaseTextResourceEditorInput {\n\tresource: URI | undefined;\n\n\t/**\n\t * A hint that the source of the dragged editor input\n\t * might not be the application but some external tool.\n\t */\n\tisExternal?: boolean;\n\n\t/**\n\t * Whether we probe for the dropped editor to be a workspace\n\t * (i.e. code-workspace file or even a folder), allowing to\n\t * open it as workspace instead of opening as editor.\n\t */\n\tallowWorkspaceOpen?: boolean;\n}\n\nexport function extractEditorsDropData(e: DragEvent): Array {\n\tconst editors: IDraggedResourceEditorInput[] = [];\n\tif (e.dataTransfer && e.dataTransfer.types.length > 0) {\n\n\t\t// Data Transfer: Code Editors\n\t\tconst rawEditorsData = e.dataTransfer.getData(CodeDataTransfers.EDITORS);\n\t\tif (rawEditorsData) {\n\t\t\ttry {\n\t\t\t\teditors.push(...parse(rawEditorsData));\n\t\t\t} catch (error) {\n\t\t\t\t// Invalid transfer\n\t\t\t}\n\t\t}\n\n\t\t// Data Transfer: Resources\n\t\telse {\n\t\t\ttry {\n\t\t\t\tconst rawResourcesData = e.dataTransfer.getData(DataTransfers.RESOURCES);\n\t\t\t\teditors.push(...createDraggedEditorInputFromRawResourcesData(rawResourcesData));\n\t\t\t} catch (error) {\n\t\t\t\t// Invalid transfer\n\t\t\t}\n\t\t}\n\n\t\t// Check for native file transfer\n\t\tif (e.dataTransfer?.files) {\n\t\t\tfor (let i = 0; i < e.dataTransfer.files.length; i++) {\n\t\t\t\tconst file = e.dataTransfer.files[i];\n\t\t\t\tif (file && (file as FileAdditionalNativeProperties).path /* Electron only */) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\teditors.push({ resource: URI.file((file as FileAdditionalNativeProperties).path!), isExternal: true, allowWorkspaceOpen: true });\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t// Invalid URI\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Check for CodeFiles transfer\n\t\tconst rawCodeFiles = e.dataTransfer.getData(CodeDataTransfers.FILES);\n\t\tif (rawCodeFiles) {\n\t\t\ttry {\n\t\t\t\tconst codeFiles: string[] = JSON.parse(rawCodeFiles);\n\t\t\t\tfor (const codeFile of codeFiles) {\n\t\t\t\t\teditors.push({ resource: URI.file(codeFile), isExternal: true, allowWorkspaceOpen: true });\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\t// Invalid transfer\n\t\t\t}\n\t\t}\n\n\t\t// Workbench contributions\n\t\tconst contributions = Registry.as(Extensions.DragAndDropContribution).getAll();\n\t\tfor (const contribution of contributions) {\n\t\t\tconst data = e.dataTransfer.getData(contribution.dataFormatKey);\n\t\t\tif (data) {\n\t\t\t\ttry {\n\t\t\t\t\teditors.push(...contribution.getEditorInputs(data));\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// Invalid transfer\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Prevent duplicates: it is possible that we end up with the same\n\t// dragged editor multiple times because multiple data transfers\n\t// are being used (https://github.com/microsoft/vscode/issues/128925)\n\n\tconst coalescedEditors: IDraggedResourceEditorInput[] = [];\n\tconst seen = new ResourceMap();\n\tfor (const editor of editors) {\n\t\tif (!editor.resource) {\n\t\t\tcoalescedEditors.push(editor);\n\t\t} else if (!seen.has(editor.resource)) {\n\t\t\tcoalescedEditors.push(editor);\n\t\t\tseen.set(editor.resource, true);\n\t\t}\n\t}\n\n\treturn coalescedEditors;\n}\n\nexport async function extractEditorsAndFilesDropData(accessor: ServicesAccessor, e: DragEvent): Promise> {\n\tconst editors = extractEditorsDropData(e);\n\n\t// Web: Check for file transfer\n\tif (e.dataTransfer && isWeb && containsDragType(e, DataTransfers.FILES)) {\n\t\tconst files = e.dataTransfer.items;\n\t\tif (files) {\n\t\t\tconst instantiationService = accessor.get(IInstantiationService);\n\t\t\tconst filesData = await instantiationService.invokeFunction(accessor => extractFilesDropData(accessor, e));\n\t\t\tfor (const fileData of filesData) {\n\t\t\t\teditors.push({ resource: fileData.resource, contents: fileData.contents?.toString(), isExternal: true, allowWorkspaceOpen: fileData.isDirectory });\n\t\t\t}\n\t\t}\n\t}\n\n\treturn editors;\n}\n\nexport function createDraggedEditorInputFromRawResourcesData(rawResourcesData: string | undefined): IDraggedResourceEditorInput[] {\n\tconst editors: IDraggedResourceEditorInput[] = [];\n\n\tif (rawResourcesData) {\n\t\tconst resourcesRaw: string[] = JSON.parse(rawResourcesData);\n\t\tfor (const resourceRaw of resourcesRaw) {\n\t\t\tif (resourceRaw.indexOf(':') > 0) { // mitigate https://github.com/microsoft/vscode/issues/124946\n\t\t\t\tconst { selection, uri } = extractSelection(URI.parse(resourceRaw));\n\t\t\t\teditors.push({ resource: uri, options: { selection } });\n\t\t\t}\n\t\t}\n\t}\n\n\treturn editors;\n}\n\n\ninterface IFileTransferData {\n\tresource: URI;\n\tisDirectory?: boolean;\n\tcontents?: VSBuffer;\n}\n\nasync function extractFilesDropData(accessor: ServicesAccessor, event: DragEvent): Promise {\n\n\t// Try to extract via `FileSystemHandle`\n\tif (WebFileSystemAccess.supported(mainWindow)) {\n\t\tconst items = event.dataTransfer?.items;\n\t\tif (items) {\n\t\t\treturn extractFileTransferData(accessor, items);\n\t\t}\n\t}\n\n\t// Try to extract via `FileList`\n\tconst files = event.dataTransfer?.files;\n\tif (!files) {\n\t\treturn [];\n\t}\n\n\treturn extractFileListData(accessor, files);\n}\n\nasync function extractFileTransferData(accessor: ServicesAccessor, items: DataTransferItemList): Promise {\n\tconst fileSystemProvider = accessor.get(IFileService).getProvider(Schemas.file);\n\tif (!(fileSystemProvider instanceof HTMLFileSystemProvider)) {\n\t\treturn []; // only supported when running in web\n\t}\n\n\tconst results: DeferredPromise[] = [];\n\n\tfor (let i = 0; i < items.length; i++) {\n\t\tconst file = items[i];\n\t\tif (file) {\n\t\t\tconst result = new DeferredPromise();\n\t\t\tresults.push(result);\n\n\t\t\t(async () => {\n\t\t\t\ttry {\n\t\t\t\t\tconst handle = await file.getAsFileSystemHandle();\n\t\t\t\t\tif (!handle) {\n\t\t\t\t\t\tresult.complete(undefined);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (WebFileSystemAccess.isFileSystemFileHandle(handle)) {\n\t\t\t\t\t\tresult.complete({\n\t\t\t\t\t\t\tresource: await fileSystemProvider.registerFileHandle(handle),\n\t\t\t\t\t\t\tisDirectory: false\n\t\t\t\t\t\t});\n\t\t\t\t\t} else if (WebFileSystemAccess.isFileSystemDirectoryHandle(handle)) {\n\t\t\t\t\t\tresult.complete({\n\t\t\t\t\t\t\tresource: await fileSystemProvider.registerDirectoryHandle(handle),\n\t\t\t\t\t\t\tisDirectory: true\n\t\t\t\t\t\t});\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresult.complete(undefined);\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tresult.complete(undefined);\n\t\t\t\t}\n\t\t\t})();\n\t\t}\n\t}\n\n\treturn coalesce(await Promise.all(results.map(result => result.p)));\n}\n\nexport async function extractFileListData(accessor: ServicesAccessor, files: FileList): Promise {\n\tconst dialogService = accessor.get(IDialogService);\n\n\tconst results: DeferredPromise[] = [];\n\n\tfor (let i = 0; i < files.length; i++) {\n\t\tconst file = files.item(i);\n\t\tif (file) {\n\n\t\t\t// Skip for very large files because this operation is unbuffered\n\t\t\tif (file.size > 100 * ByteSize.MB) {\n\t\t\t\tdialogService.warn(localize('fileTooLarge', \"File is too large to open as untitled editor. Please upload it first into the file explorer and then try again.\"));\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst result = new DeferredPromise();\n\t\t\tresults.push(result);\n\n\t\t\tconst reader = new FileReader();\n\n\t\t\treader.onerror = () => result.complete(undefined);\n\t\t\treader.onabort = () => result.complete(undefined);\n\n\t\t\treader.onload = async event => {\n\t\t\t\tconst name = file.name;\n\t\t\t\tconst loadResult = event.target?.result ?? undefined;\n\t\t\t\tif (typeof name !== 'string' || typeof loadResult === 'undefined') {\n\t\t\t\t\tresult.complete(undefined);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tresult.complete({\n\t\t\t\t\tresource: URI.from({ scheme: Schemas.untitled, path: name }),\n\t\t\t\t\tcontents: typeof loadResult === 'string' ? VSBuffer.fromString(loadResult) : VSBuffer.wrap(new Uint8Array(loadResult))\n\t\t\t\t});\n\t\t\t};\n\n\t\t\t// Start reading\n\t\t\treader.readAsArrayBuffer(file);\n\t\t}\n\t}\n\n\treturn coalesce(await Promise.all(results.map(result => result.p)));\n}\n\n//#endregion\n\nexport function containsDragType(event: DragEvent, ...dragTypesToFind: string[]): boolean {\n\tif (!event.dataTransfer) {\n\t\treturn false;\n\t}\n\n\tconst dragTypes = event.dataTransfer.types;\n\tconst lowercaseDragTypes: string[] = [];\n\tfor (let i = 0; i < dragTypes.length; i++) {\n\t\tlowercaseDragTypes.push(dragTypes[i].toLowerCase()); // somehow the types are lowercase\n\t}\n\n\tfor (const dragType of dragTypesToFind) {\n\t\tif (lowercaseDragTypes.indexOf(dragType.toLowerCase()) >= 0) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n\n//#region DND contributions\n\nexport interface IResourceStat {\n\tresource: URI;\n\tisDirectory?: boolean;\n}\n\nexport interface IDragAndDropContributionRegistry {\n\t/**\n\t * Registers a drag and drop contribution.\n\t */\n\tregister(contribution: IDragAndDropContribution): void;\n\n\t/**\n\t * Returns all registered drag and drop contributions.\n\t */\n\tgetAll(): IterableIterator;\n}\n\ninterface IDragAndDropContribution {\n\treadonly dataFormatKey: string;\n\tgetEditorInputs(data: string): IDraggedResourceEditorInput[];\n\tsetData(resources: IResourceStat[], event: DragMouseEvent | DragEvent): void;\n}\n\nclass DragAndDropContributionRegistry implements IDragAndDropContributionRegistry {\n\tprivate readonly _contributions = new Map();\n\n\tregister(contribution: IDragAndDropContribution): void {\n\t\tif (this._contributions.has(contribution.dataFormatKey)) {\n\t\t\tthrow new Error(`A drag and drop contributiont with key '${contribution.dataFormatKey}' was already registered.`);\n\t\t}\n\t\tthis._contributions.set(contribution.dataFormatKey, contribution);\n\t}\n\n\tgetAll(): IterableIterator {\n\t\treturn this._contributions.values();\n\t}\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\tclearData(proto: T): void {\n\t\tif (this.hasData(proto)) {\n\t\t\tthis.proto = undefined;\n\t\t\tthis.data = undefined;\n\t\t}\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\tsetData(data: T[], proto: T): void {\n\t\tif (proto) {\n\t\t\tthis.data = data;\n\t\t\tthis.proto = proto;\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 { 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, Event } 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 ISchemaContributions {\n\tschemas: { [id: string]: IJSONSchema };\n}\n\nexport interface IJSONContributionRegistry {\n\n\treadonly onDidChangeSchema: Event;\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\t/**\n\t * Get all schemas\n\t */\n\tgetSchemaContributions(): ISchemaContributions;\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\treadonly onDidChangeSchema: Event = this._onDidChangeSchema.event;\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\tpublic getSchemaContributions(): ISchemaContributions {\n\t\treturn {\n\t\t\tschemas: this.schemasById,\n\t\t};\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, Event } 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 enum EditPresentationTypes {\n\tMultiline = 'multilineText',\n\tSingleline = 'singlelineText'\n}\n\nexport const Extensions = {\n\tConfiguration: 'base.contributions.configuration'\n};\n\nexport interface IConfigurationDelta {\n\tremovedDefaults?: IConfigurationDefaults[];\n\tremovedConfigurations?: IConfigurationNode[];\n\taddedDefaults?: IConfigurationDefaults[];\n\taddedConfigurations?: IConfigurationNode[];\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 configurations to the registry.\n\t */\n\tregisterConfigurations(configurations: IConfigurationNode[], validate?: boolean): void;\n\n\t/**\n\t * Deregister multiple configurations from the registry.\n\t */\n\tderegisterConfigurations(configurations: IConfigurationNode[]): void;\n\n\t/**\n\t * update the configuration registry by\n\t * \t- registering the configurations to add\n\t * \t- dereigstering the configurations to remove\n\t */\n\tupdateConfigurations(configurations: { add: IConfigurationNode[]; remove: 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 * Deregister multiple default configurations from the registry.\n\t */\n\tderegisterDefaultConfigurations(defaultConfigurations: IConfigurationDefaults[]): void;\n\n\t/**\n\t * Bulk update of the configuration registry (default and configurations, remove and add)\n\t * @param delta\n\t */\n\tdeltaConfiguration(delta: IConfigurationDelta): void;\n\n\t/**\n\t * Return the registered configuration defaults overrides\n\t */\n\tgetConfigurationDefaultsOverrides(): Map;\n\n\t/**\n\t * Signal that the schema of a configuration setting has changes. It is currently only supported to change enumeration values.\n\t * Property or default value changes are not allowed.\n\t */\n\tnotifyConfigurationSchemaUpdated(...configurations: IConfigurationNode[]): void;\n\n\t/**\n\t * Event that fires whenever a configuration has been\n\t * registered.\n\t */\n\treadonly onDidSchemaChange: Event;\n\n\t/**\n\t * Event that fires whenever a configuration has been\n\t * registered.\n\t */\n\treadonly onDidUpdateConfiguration: Event<{ properties: ReadonlySet; defaultsOverrides?: boolean }>;\n\n\t/**\n\t * Returns all configuration nodes contributed to this registry.\n\t */\n\tgetConfigurations(): IConfigurationNode[];\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 * Return all configurations by policy name\n\t */\n\tgetPolicyConfigurations(): Map;\n\n\t/**\n\t * Returns all excluded configurations settings of all configuration nodes contributed to this registry.\n\t */\n\tgetExcludedConfigurationProperties(): 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\t/**\n\t * The Code version in which this policy was introduced.\n\t */\n\treadonly minimumVersion: `${number}.${number}`;\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 enabled this setting is ignored during sync and user can override this.\n\t */\n\tignoreSync?: boolean;\n\n\t/**\n\t * When enabled this setting is ignored during sync and user cannot override this.\n\t */\n\tdisallowSyncIgnore?: boolean;\n\n\t/**\n\t * Labels for enumeration items\n\t */\n\tenumItemLabels?: string[];\n\n\t/**\n\t * When specified, controls the presentation format of string settings.\n\t * Otherwise, the presentation format defaults to `singleline`.\n\t */\n\teditPresentation?: EditPresentationTypes;\n\n\t/**\n\t * When specified, gives an order number for the setting\n\t * within the settings editor. Otherwise, the setting is placed at the end.\n\t */\n\torder?: number;\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\tid: string;\n\tdisplayName?: string;\n}\n\nexport interface IConfigurationNode {\n\tid?: string;\n\torder?: number;\n\ttype?: string | string[];\n\ttitle?: string;\n\tdescription?: 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';\nexport const configurationDefaultsSchemaId = 'vscode://schemas/settings/configurationDefaults';\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\treadonly onDidSchemaChange: Event = this._onDidSchemaChange.event;\n\n\tprivate readonly _onDidUpdateConfiguration = new Emitter<{ properties: ReadonlySet; defaultsOverrides?: boolean }>();\n\treadonly onDidUpdateConfiguration = this._onDidUpdateConfiguration.event;\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 deregisterConfigurations(configurations: IConfigurationNode[]): void {\n\t\tconst properties = new Set();\n\t\tthis.doDeregisterConfigurations(configurations, 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 updateConfigurations({ add, remove }: { add: IConfigurationNode[]; remove: IConfigurationNode[] }): void {\n\t\tconst properties = new Set();\n\t\tthis.doDeregisterConfigurations(remove, properties);\n\t\tthis.doRegisterConfigurations(add, false, 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 deregisterDefaultConfigurations(defaultConfigurations: IConfigurationDefaults[]): void {\n\t\tconst properties = new Set();\n\t\tthis.doDeregisterDefaultConfigurations(defaultConfigurations, properties);\n\t\tthis._onDidSchemaChange.fire();\n\t\tthis._onDidUpdateConfiguration.fire({ properties, defaultsOverrides: true });\n\t}\n\n\tprivate doDeregisterDefaultConfigurations(defaultConfigurations: IConfigurationDefaults[], bucket: Set): void {\n\n\t\tfor (const { overrides, source } of defaultConfigurations) {\n\t\t\tfor (const key in overrides) {\n\t\t\t\tconst configurationDefaultsOverride = this.configurationDefaultsOverrides.get(key);\n\t\t\t\tconst id = types.isString(source) ? source : source?.id;\n\t\t\t\tconst configurationDefaultsOverrideSourceId = types.isString(configurationDefaultsOverride?.source) ? configurationDefaultsOverride?.source : configurationDefaultsOverride?.source?.id;\n\t\t\t\tif (id !== configurationDefaultsOverrideSourceId) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tbucket.add(key);\n\t\t\t\tthis.configurationDefaultsOverrides.delete(key);\n\t\t\t\tif (OVERRIDE_PROPERTY_REGEX.test(key)) {\n\t\t\t\t\tdelete this.configurationProperties[key];\n\t\t\t\t\tdelete this.defaultLanguageConfigurationOverridesNode.properties![key];\n\t\t\t\t} else {\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.updateOverridePropertyPatternKey();\n\t}\n\n\tpublic deltaConfiguration(delta: IConfigurationDelta): void {\n\t\t// defaults: remove\n\t\tlet defaultsOverrides = false;\n\t\tconst properties = new Set();\n\t\tif (delta.removedDefaults) {\n\t\t\tthis.doDeregisterDefaultConfigurations(delta.removedDefaults, properties);\n\t\t\tdefaultsOverrides = true;\n\t\t}\n\t\t// defaults: add\n\t\tif (delta.addedDefaults) {\n\t\t\tthis.doRegisterDefaultConfigurations(delta.addedDefaults, properties);\n\t\t\tdefaultsOverrides = true;\n\t\t}\n\t\t// configurations: remove\n\t\tif (delta.removedConfigurations) {\n\t\t\tthis.doDeregisterConfigurations(delta.removedConfigurations, properties);\n\t\t}\n\t\t// configurations: add\n\t\tif (delta.addedConfigurations) {\n\t\t\tthis.doRegisterConfigurations(delta.addedConfigurations, false, properties);\n\t\t}\n\t\tthis._onDidSchemaChange.fire();\n\t\tthis._onDidUpdateConfiguration.fire({ properties, defaultsOverrides });\n\t}\n\n\tpublic notifyConfigurationSchemaUpdated(...configurations: IConfigurationNode[]) {\n\t\tthis._onDidSchemaChange.fire();\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 doDeregisterConfigurations(configurations: IConfigurationNode[], bucket: Set): void {\n\n\t\tconst deregisterConfiguration = (configuration: IConfigurationNode) => {\n\t\t\tif (configuration.properties) {\n\t\t\t\tfor (const key in configuration.properties) {\n\t\t\t\t\tbucket.add(key);\n\t\t\t\t\tconst property = this.configurationProperties[key];\n\t\t\t\t\tif (property?.policy?.name) {\n\t\t\t\t\t\tthis.policyConfigurations.delete(property.policy.name);\n\t\t\t\t\t}\n\t\t\t\t\tdelete this.configurationProperties[key];\n\t\t\t\t\tthis.removeFromSchema(key, configuration.properties[key]);\n\t\t\t\t}\n\t\t\t}\n\t\t\tconfiguration.allOf?.forEach(node => deregisterConfiguration(node));\n\t\t};\n\t\tfor (const configuration of configurations) {\n\t\t\tderegisterConfiguration(configuration);\n\t\t\tconst index = this.configurationContributors.indexOf(configuration);\n\t\t\tif (index !== -1) {\n\t\t\t\tthis.configurationContributors.splice(index, 1);\n\t\t\t}\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\t// TODO: @sandy081 - Remove this method and include required info in getConfigurationProperties\n\tgetConfigurations(): IConfigurationNode[] {\n\t\treturn this.configurationContributors;\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\tgetExcludedConfigurationProperties(): IStringDictionary {\n\t\treturn this.excludedConfigurationProperties;\n\t}\n\n\tgetConfigurationDefaultsOverrides(): Map {\n\t\treturn this.configurationDefaultsOverrides;\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 removeFromSchema(key: string, property: IConfigurationPropertySchema): void {\n\t\tdelete allSettings.properties[key];\n\t\tswitch (property.scope) {\n\t\t\tcase ConfigurationScope.APPLICATION:\n\t\t\t\tdelete applicationSettings.properties[key];\n\t\t\t\tbreak;\n\t\t\tcase ConfigurationScope.MACHINE:\n\t\t\t\tdelete machineSettings.properties[key];\n\t\t\t\tbreak;\n\t\t\tcase ConfigurationScope.MACHINE_OVERRIDABLE:\n\t\t\t\tdelete machineOverridableSettings.properties[key];\n\t\t\t\tbreak;\n\t\t\tcase ConfigurationScope.WINDOW:\n\t\t\t\tdelete windowSettings.properties[key];\n\t\t\t\tbreak;\n\t\t\tcase ConfigurationScope.RESOURCE:\n\t\t\tcase ConfigurationScope.LANGUAGE_OVERRIDABLE:\n\t\t\t\tdelete resourceSettings.properties[key];\n\t\t\t\tdelete this.resourceLanguageSettingsSchema.properties![key];\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 keyFromOverrideIdentifiers(overrideIdentifiers: string[]): string {\n\treturn overrideIdentifiers.reduce((result, overrideIdentifier) => `${result}[${overrideIdentifier}]`, '');\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\nexport function getScopes(): [string, ConfigurationScope | undefined][] {\n\tconst scopes: [string, ConfigurationScope | undefined][] = [];\n\tconst configurationProperties = configurationRegistry.getConfigurationProperties();\n\tfor (const key of Object.keys(configurationProperties)) {\n\t\tscopes.push([key, configurationProperties[key].scope]);\n\t}\n\tscopes.push(['launch', ConfigurationScope.RESOURCE]);\n\tscopes.push(['task', ConfigurationScope.RESOURCE]);\n\treturn scopes;\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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.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 { IHoverTarget, IHoverOptions } from 'vs/platform/hover/browser/hover';\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 { IHoverWidget } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate';\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 = Math.min(...targetBounds.map(e => e.top));\n\t\tconst right = Math.max(...targetBounds.map(e => e.right));\n\t\tconst bottom = Math.max(...targetBounds.map(e => e.bottom));\n\t\tconst left = Math.min(...targetBounds.map(e => e.left));\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\t// When force position is enabled, restrict max width\n\t\tif (this._forcePosition) {\n\t\t\tconst padding = (this._hoverPointer ? Constants.PointerSize : 0) + 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) {\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) {\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) {\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) {\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 <= 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\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 < 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 > 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 hide(): void {\n\t\tthis.dispose();\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, onUnexpectedError } 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 { IChange } from 'vs/editor/common/diff/legacyLinesDiffComputer';\nimport { IDocumentDiff, IDocumentDiffProviderOptions } from 'vs/editor/common/diff/documentDiffProvider';\nimport { ILinesDiffComputerOptions, 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 { $window } 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 canComputeDirtyDiff(original: URI, modified: URI): boolean {\n\t\treturn (canSyncModel(this._modelService, original) && canSyncModel(this._modelService, modified));\n\t}\n\n\tpublic computeDirtyDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean): Promise {\n\t\treturn this._workerManager.withWorker().then(client => client.computeDirtyDiff(original, modified, ignoreTrimWhitespace));\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 computeHumanReadableDiff(resource: URI, edits: languages.TextEdit[] | null | undefined): 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.computeHumanReadableDiff(resource, edits,\n\t\t\t\t{ ignoreTrimWhitespace: false, maxComputationTimeMs: 1000, computeMoves: false, })).catch((err) => {\n\t\t\t\t\tonUnexpectedError(err);\n\t\t\t\t\t// In case of an exception, fall back to computeMoreMinimalEdits\n\t\t\t\t\treturn this.computeMoreMinimalEdits(resource, edits, true);\n\t\t\t\t});\n\t\t\tresult.finally(() => this._logService.trace('FORMAT#computeHumanReadableDiff', resource.toString(true), sw.elapsed()));\n\t\t\treturn result;\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\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), $window);\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 computeDirtyDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean): Promise {\n\t\treturn this._withSyncedResources([original, modified]).then(proxy => {\n\t\t\treturn proxy.computeDirtyDiff(original.toString(), modified.toString(), ignoreTrimWhitespace);\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 computeHumanReadableDiff(resource: URI, edits: languages.TextEdit[], options: ILinesDiffComputerOptions): Promise {\n\t\treturn this._withSyncedResources([resource]).then(proxy => {\n\t\t\treturn proxy.computeHumanReadableDiff(resource.toString(), edits, options);\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\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 revealPrimary(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 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.revealPrimary(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.revealPrimary(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 getPosition(): Position {\n\t\treturn this._cursors.getPrimaryCursor().modelState.position;\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.revealPrimary(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 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): string[] {\n\tif (icon) {\n\t\treturn [`codicon-${icon.id}`, 'predefined-file-icon'];\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\nexport function getIconClassesForLanguageId(languageId: string): string[] {\n\treturn ['file-icon', `${cssEscape(languageId)}-lang-file-icon`];\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\n/**\n * Associate a language to the registry (configured).\n * * **NOTE**: This association will win over associations registered using `registerPlatformLanguageAssociation`.\n * * **NOTE**: Use `clearConfiguredLanguageAssociations` to remove all associations registered using this function.\n */\nexport function registerConfiguredLanguageAssociation(association: ILanguageAssociation): void {\n\t_registerLanguageAssociation(association, true, false);\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\n/**\n * Clear language associations from the registry (configured).\n */\nexport function clearConfiguredLanguageAssociations(): void {\n\tregisteredAssociations = registeredAssociations.filter(a => !a.userConfigured);\n\tuserRegisteredAssociations = [];\n}\n\ninterface IdAndMime {\n\tid: string;\n\tmime: string;\n}\n\n/**\n * Given a file, return the best matching mime types for it\n * based on the registered language associations.\n */\nexport function getMimeTypes(resource: URI | null, firstLine?: string): string[] {\n\treturn getAssociations(resource, firstLine).map(item => item.mime);\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, IDisposable } from 'vs/base/common/lifecycle';\nimport { compareIgnoreCase, 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, ILanguageNameIdPair, 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\tpublic setDynamicLanguages(def: ILanguageExtensionPoint[]): void {\n\t\tthis._dynamicLanguages = def;\n\t\tthis._initializeFromRegistry();\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\tregisterLanguage(desc: ILanguageExtensionPoint): IDisposable {\n\t\treturn ModesRegistry.registerLanguage(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 getSortedRegisteredLanguageNames(): ILanguageNameIdPair[] {\n\t\tconst result: ILanguageNameIdPair[] = [];\n\t\tfor (const languageName in this._nameMap) {\n\t\t\tif (hasOwnProperty.call(this._nameMap, languageName)) {\n\t\t\t\tresult.push({\n\t\t\t\t\tlanguageName: languageName,\n\t\t\t\t\tlanguageId: this._nameMap[languageName]\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tresult.sort((a, b) => compareIgnoreCase(a.languageName, b.languageName));\n\t\treturn result;\n\t}\n\n\tpublic getLanguageName(languageId: string): string | null {\n\t\tif (!hasOwnProperty.call(this._languages, languageId)) {\n\t\t\treturn null;\n\t\t}\n\t\treturn this._languages[languageId].name;\n\t}\n\n\tpublic getMimeType(languageId: string): string | null {\n\t\tif (!hasOwnProperty.call(this._languages, languageId)) {\n\t\t\treturn null;\n\t\t}\n\t\tconst language = this._languages[languageId];\n\t\treturn (language.mimetypes[0] || null);\n\t}\n\n\tpublic getExtensions(languageId: string): ReadonlyArray {\n\t\tif (!hasOwnProperty.call(this._languages, languageId)) {\n\t\t\treturn [];\n\t\t}\n\t\treturn this._languages[languageId].extensions;\n\t}\n\n\tpublic getFilenames(languageId: string): ReadonlyArray {\n\t\tif (!hasOwnProperty.call(this._languages, languageId)) {\n\t\t\treturn [];\n\t\t}\n\t\treturn this._languages[languageId].filenames;\n\t}\n\n\tpublic getIcon(languageId: string): ILanguageIcon | null {\n\t\tif (!hasOwnProperty.call(this._languages, languageId)) {\n\t\t\treturn null;\n\t\t}\n\t\tconst language = this._languages[languageId];\n\t\treturn (language.icons[0] || null);\n\t}\n\n\tpublic getConfigurationFiles(languageId: string): ReadonlyArray {\n\t\tif (!hasOwnProperty.call(this._languages, languageId)) {\n\t\t\treturn [];\n\t\t}\n\t\treturn this._languages[languageId].configurationFiles || [];\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 { ILanguageNameIdPair, ILanguageSelection, ILanguageService, ILanguageIcon, ILanguageExtensionPoint } 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 registerLanguage(def: ILanguageExtensionPoint): IDisposable {\n\t\treturn this._registry.registerLanguage(def);\n\t}\n\n\tpublic isRegisteredLanguageId(languageId: string | null | undefined): boolean {\n\t\treturn this._registry.isRegisteredLanguageId(languageId);\n\t}\n\n\tpublic getRegisteredLanguageIds(): string[] {\n\t\treturn this._registry.getRegisteredLanguageIds();\n\t}\n\n\tpublic getSortedRegisteredLanguageNames(): ILanguageNameIdPair[] {\n\t\treturn this._registry.getSortedRegisteredLanguageNames();\n\t}\n\n\tpublic getLanguageName(languageId: string): string | null {\n\t\treturn this._registry.getLanguageName(languageId);\n\t}\n\n\tpublic getMimeType(languageId: string): string | null {\n\t\treturn this._registry.getMimeType(languageId);\n\t}\n\n\tpublic getIcon(languageId: string): ILanguageIcon | null {\n\t\treturn this._registry.getIcon(languageId);\n\t}\n\n\tpublic getExtensions(languageId: string): ReadonlyArray {\n\t\treturn this._registry.getExtensions(languageId);\n\t}\n\n\tpublic getFilenames(languageId: string): ReadonlyArray {\n\t\treturn this._registry.getFilenames(languageId);\n\t}\n\n\tpublic getConfigurationFiles(languageId: string): ReadonlyArray {\n\t\treturn this._registry.getConfigurationFiles(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 createByMimeType(mimeType: string | null | undefined): ILanguageSelection {\n\t\treturn new LanguageSelection(this.onDidChange, () => {\n\t\t\tconst languageId = this.getLanguageIdByMimeType(mimeType);\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 { asArray } from 'vs/base/common/arrays';\nimport { IMarkdownString, isEmptyMarkdownString } from 'vs/base/common/htmlContent';\nimport { Disposable, 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 { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { ILanguageService } from 'vs/editor/common/languages/language';\nimport { HoverOperation, HoverStartMode, IHoverComputer } 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 { GlyphMarginLane } from 'vs/editor/common/model';\n\nconst $ = dom.$;\n\nexport interface IHoverMessage {\n\tvalue: IMarkdownString;\n}\n\ntype LaneOrLineNumber = GlyphMarginLane | 'lineNo';\n\nexport class MarginHoverWidget extends Disposable implements IOverlayWidget {\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 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\nclass 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 { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';\nimport { matchesSubString } from 'vs/base/common/filters';\nimport { Disposable, IDisposable, MutableDisposable } from 'vs/base/common/lifecycle';\nimport { IObservable, IReader, ITransaction, derived, disposableObservableValue, transaction } from 'vs/base/common/observable';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\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 { SingleTextEdit } 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&& equals(this.context.selectedSuggestionInfo, other.context.selectedSuggestionInfo, (v1, v2) => v1.equals(v2))\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\nfunction equals(v1: T | undefined, v2: T | undefined, equals: (v1: T, v2: T) => boolean): boolean {\n\tif (!v1 || !v2) {\n\t\treturn v1 === v2;\n\t}\n\treturn equals(v1, v2);\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\tprivate _rangeVersionIdValue = 0;\n\tprivate readonly _rangeVersionId = derived(this, reader => {\n\t\tthis.versionId.read(reader);\n\t\tlet changed = false;\n\t\tfor (const i of this._inlineCompletions) {\n\t\t\tchanged = changed || i._updateRange(this.textModel);\n\t\t}\n\t\tif (changed) {\n\t\t\tthis._rangeVersionIdValue++;\n\t\t}\n\t\treturn this._rangeVersionIdValue;\n\t});\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._rangeVersionId)\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._rangeVersionId, range));\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\tprivate _updatedRange: Range;\n\tprivate _isValid = true;\n\n\tpublic get forwardStable() {\n\t\treturn this.inlineCompletion.source.inlineCompletions.enableForwardStability ?? false;\n\t}\n\n\tconstructor(\n\t\tpublic readonly inlineCompletion: InlineCompletionItem,\n\t\tpublic readonly decorationId: string,\n\t\tprivate readonly rangeVersion: IObservable,\n\t\tinitialRange?: Range,\n\t) {\n\t\tthis._updatedRange = initialRange ?? inlineCompletion.range;\n\t}\n\n\tpublic toInlineCompletion(reader: IReader | undefined): InlineCompletionItem {\n\t\treturn this.inlineCompletion.withRange(this._getUpdatedRange(reader));\n\t}\n\n\tpublic toSingleTextEdit(reader: IReader | undefined): SingleTextEdit {\n\t\treturn new SingleTextEdit(this._getUpdatedRange(reader), this.inlineCompletion.insertText);\n\t}\n\n\tpublic isVisible(model: ITextModel, cursorPosition: Position, reader: IReader | undefined): boolean {\n\t\tconst minimizedReplacement = this._toFilterTextReplacement(reader).removeCommonPrefix(model);\n\n\t\tif (\n\t\t\t!this._isValid\n\t\t\t|| !this.inlineCompletion.range.getStartPosition().equals(this._getUpdatedRange(reader).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 result = this._isValid\n\t\t\t&& this._getUpdatedRange(undefined).containsPosition(position)\n\t\t\t&& this.isVisible(model, position, undefined)\n\t\t\t&& !this._isSmallerThanOriginal(undefined);\n\t\treturn result;\n\t}\n\n\tprivate _toFilterTextReplacement(reader: IReader | undefined): SingleTextEdit {\n\t\treturn new SingleTextEdit(this._getUpdatedRange(reader), this.inlineCompletion.filterText);\n\t}\n\n\tprivate _isSmallerThanOriginal(reader: IReader | undefined): boolean {\n\t\treturn length(this._getUpdatedRange(reader)).isBefore(length(this.inlineCompletion.range));\n\t}\n\n\tprivate _getUpdatedRange(reader: IReader | undefined): Range {\n\t\tthis.rangeVersion.read(reader); // This makes sure all the ranges are updated.\n\t\treturn this._updatedRange;\n\t}\n\n\tpublic _updateRange(textModel: ITextModel): boolean {\n\t\tconst range = textModel.getDecorationRange(this.decorationId);\n\t\tif (!range) {\n\t\t\t// A setValue call might flush all decorations.\n\t\t\tthis._isValid = false;\n\t\t\treturn true;\n\t\t}\n\t\tif (!this._updatedRange.equalsRange(range)) {\n\t\t\tthis._updatedRange = range;\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n}\n\nfunction length(range: Range): Position {\n\tif (range.startLineNumber === range.endLineNumber) {\n\t\treturn new Position(1, 1 + range.endColumn - range.startColumn);\n\t} else {\n\t\treturn new Position(1 + range.endLineNumber - range.startLineNumber, range.endColumn);\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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/browser/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 { Emitter, Event } from 'vs/base/common/event';\nimport * as json from 'vs/base/common/json';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { getOrSet, ResourceMap } from 'vs/base/common/map';\nimport * as objects from 'vs/base/common/objects';\nimport { IExtUri } from 'vs/base/common/resources';\nimport * as types from 'vs/base/common/types';\nimport { URI, UriComponents } from 'vs/base/common/uri';\nimport { addToValueTree, ConfigurationTarget, getConfigurationValue, IConfigurationChange, IConfigurationChangeEvent, IConfigurationCompareResult, 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 { FileOperation, IFileService } from 'vs/platform/files/common/files';\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\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>\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('');\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).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\tgetKeysForOverrideIdentifier(identifier: string): string[] {\n\t\tconst keys: string[] = [];\n\t\tfor (const override of this.overrides) {\n\t\t\tif (override.identifiers.includes(identifier)) {\n\t\t\t\tkeys.push(...override.keys);\n\t\t\t}\n\t\t}\n\t\treturn arrays.distinct(keys);\n\t}\n\n\tgetAllOverrideIdentifiers(): string[] {\n\t\tconst result: string[] = [];\n\t\tfor (const override of this.overrides) {\n\t\t\tresult.push(...override.identifiers);\n\t\t}\n\t\treturn arrays.distinct(result);\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);\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);\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 => console.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 => console.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\tprivate _parseErrors: any[] = [];\n\n\tconstructor(protected readonly _name: string) { }\n\n\tget configurationModel(): ConfigurationModel {\n\t\treturn this._configurationModel || new ConfigurationModel();\n\t}\n\n\tget restrictedConfigurations(): string[] {\n\t\treturn this._restrictedConfigurations;\n\t}\n\n\tget errors(): any[] {\n\t\treturn this._parseErrors;\n\t}\n\n\tpublic parse(content: string | null | undefined, options?: ConfigurationParseOptions): void {\n\t\tif (!types.isUndefinedOrNull(content)) {\n\t\t\tconst raw = this.doParseContent(content);\n\t\t\tthis.parseRaw(raw, options);\n\t\t}\n\t}\n\n\tpublic reparse(options: ConfigurationParseOptions): void {\n\t\tif (this._raw) {\n\t\t\tthis.parseRaw(this._raw, options);\n\t\t}\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 */);\n\t\tthis._restrictedConfigurations = restricted || [];\n\t}\n\n\tprivate doParseContent(content: string): any {\n\t\tlet raw: any = {};\n\t\tlet currentProperty: string | null = null;\n\t\tlet currentParent: any = [];\n\t\tconst previousParents: any[] = [];\n\t\tconst parseErrors: json.ParseError[] = [];\n\n\t\tfunction onValue(value: any) {\n\t\t\tif (Array.isArray(currentParent)) {\n\t\t\t\t(currentParent).push(value);\n\t\t\t} else if (currentProperty !== null) {\n\t\t\t\tcurrentParent[currentProperty] = value;\n\t\t\t}\n\t\t}\n\n\t\tconst visitor: json.JSONVisitor = {\n\t\t\tonObjectBegin: () => {\n\t\t\t\tconst object = {};\n\t\t\t\tonValue(object);\n\t\t\t\tpreviousParents.push(currentParent);\n\t\t\t\tcurrentParent = object;\n\t\t\t\tcurrentProperty = null;\n\t\t\t},\n\t\t\tonObjectProperty: (name: string) => {\n\t\t\t\tcurrentProperty = name;\n\t\t\t},\n\t\t\tonObjectEnd: () => {\n\t\t\t\tcurrentParent = previousParents.pop();\n\t\t\t},\n\t\t\tonArrayBegin: () => {\n\t\t\t\tconst array: any[] = [];\n\t\t\t\tonValue(array);\n\t\t\t\tpreviousParents.push(currentParent);\n\t\t\t\tcurrentParent = array;\n\t\t\t\tcurrentProperty = null;\n\t\t\t},\n\t\t\tonArrayEnd: () => {\n\t\t\t\tcurrentParent = previousParents.pop();\n\t\t\t},\n\t\t\tonLiteralValue: onValue,\n\t\t\tonError: (error: json.ParseErrorCode, offset: number, length: number) => {\n\t\t\t\tparseErrors.push({ error, offset, length });\n\t\t\t}\n\t\t};\n\t\tif (content) {\n\t\t\ttry {\n\t\t\t\tjson.visit(content, visitor);\n\t\t\t\traw = currentParent[0] || {};\n\t\t\t} catch (e) {\n\t\t\t\tconsole.error(`Error while parsing settings file ${this._name}: ${e}`);\n\t\t\t\tthis._parseErrors = [e];\n\t\t\t}\n\t\t}\n\n\t\treturn raw;\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 => console.error(`Conflict in settings file ${this._name}: ${message}`));\n\t\tconst keys = Object.keys(raw);\n\t\tconst overrides = this.toOverrides(raw, message => console.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\nexport class UserSettings extends Disposable {\n\n\tprivate readonly parser: ConfigurationModelParser;\n\tprotected readonly _onDidChange: Emitter = this._register(new Emitter());\n\treadonly onDidChange: Event = this._onDidChange.event;\n\n\tconstructor(\n\t\tprivate readonly userSettingsResource: URI,\n\t\tprotected parseOptions: ConfigurationParseOptions,\n\t\textUri: IExtUri,\n\t\tprivate readonly fileService: IFileService\n\t) {\n\t\tsuper();\n\t\tthis.parser = new ConfigurationModelParser(this.userSettingsResource.toString());\n\t\tthis._register(this.fileService.watch(extUri.dirname(this.userSettingsResource)));\n\t\t// Also listen to the resource incase the resource is a symlink - https://github.com/microsoft/vscode/issues/118134\n\t\tthis._register(this.fileService.watch(this.userSettingsResource));\n\t\tthis._register(Event.any(\n\t\t\tEvent.filter(this.fileService.onDidFilesChange, e => e.contains(this.userSettingsResource)),\n\t\t\tEvent.filter(this.fileService.onDidRunOperation, e => (e.isOperation(FileOperation.CREATE) || e.isOperation(FileOperation.COPY) || e.isOperation(FileOperation.DELETE) || e.isOperation(FileOperation.WRITE)) && extUri.isEqual(e.resource, userSettingsResource))\n\t\t)(() => this._onDidChange.fire()));\n\t}\n\n\tasync loadConfiguration(): Promise {\n\t\ttry {\n\t\t\tconst content = await this.fileService.readFile(this.userSettingsResource);\n\t\t\tthis.parser.parse(content.value.toString() || '{}', this.parseOptions);\n\t\t\treturn this.parser.configurationModel;\n\t\t} catch (e) {\n\t\t\treturn new ConfigurationModel();\n\t\t}\n\t}\n\n\treparse(parseOptions?: ConfigurationParseOptions): ConfigurationModel {\n\t\tif (parseOptions) {\n\t\t\tthis.parseOptions = parseOptions;\n\t\t}\n\t\tthis.parser.reparse(this.parseOptions);\n\t\treturn this.parser.configurationModel;\n\t}\n\n\tgetRestrictedSettings(): string[] {\n\t\treturn this.parser.restrictedConfigurations;\n\t}\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\tget value(): V | undefined {\n\t\treturn freeze(this._value);\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 _defaultInspectValue: InspectValue | undefined;\n\tprivate get defaultInspectValue(): InspectValue {\n\t\tif (!this._defaultInspectValue) {\n\t\t\tthis._defaultInspectValue = this.defaultConfiguration.inspect(this.key, this.overrides.overrideIdentifier);\n\t\t}\n\t\treturn this._defaultInspectValue;\n\t}\n\n\tget defaultValue(): V | undefined {\n\t\treturn this.defaultInspectValue.merged;\n\t}\n\n\tget default(): IInspectValue | undefined {\n\t\treturn this.toInspectValue(this.defaultInspectValue);\n\t}\n\n\tprivate _policyInspectValue: InspectValue | undefined | null;\n\tprivate get policyInspectValue(): InspectValue | null {\n\t\tif (this._policyInspectValue === undefined) {\n\t\t\tthis._policyInspectValue = this.policyConfiguration ? this.policyConfiguration.inspect(this.key) : null;\n\t\t}\n\t\treturn this._policyInspectValue;\n\t}\n\n\tget policyValue(): V | undefined {\n\t\treturn this.policyInspectValue?.merged;\n\t}\n\n\tget policy(): IInspectValue | undefined {\n\t\treturn this.policyInspectValue?.value !== undefined ? { value: this.policyInspectValue.value } : undefined;\n\t}\n\n\tprivate _applicationInspectValue: InspectValue | undefined | null;\n\tprivate get applicationInspectValue(): InspectValue | null {\n\t\tif (this._applicationInspectValue === undefined) {\n\t\t\tthis._applicationInspectValue = this.applicationConfiguration ? this.applicationConfiguration.inspect(this.key) : null;\n\t\t}\n\t\treturn this._applicationInspectValue;\n\t}\n\n\tget applicationValue(): V | undefined {\n\t\treturn this.applicationInspectValue?.merged;\n\t}\n\n\tget application(): IInspectValue | undefined {\n\t\treturn this.toInspectValue(this.applicationInspectValue);\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 userValue(): V | undefined {\n\t\treturn this.userInspectValue.merged;\n\t}\n\n\tget user(): IInspectValue | undefined {\n\t\treturn this.toInspectValue(this.userInspectValue);\n\t}\n\n\tprivate _userLocalInspectValue: InspectValue | undefined;\n\tprivate get userLocalInspectValue(): InspectValue {\n\t\tif (!this._userLocalInspectValue) {\n\t\t\tthis._userLocalInspectValue = this.localUserConfiguration.inspect(this.key, this.overrides.overrideIdentifier);\n\t\t}\n\t\treturn this._userLocalInspectValue;\n\t}\n\n\tget userLocalValue(): V | undefined {\n\t\treturn this.userLocalInspectValue.merged;\n\t}\n\n\tget userLocal(): IInspectValue | undefined {\n\t\treturn this.toInspectValue(this.userLocalInspectValue);\n\t}\n\n\tprivate _userRemoteInspectValue: InspectValue | undefined;\n\tprivate get userRemoteInspectValue(): InspectValue {\n\t\tif (!this._userRemoteInspectValue) {\n\t\t\tthis._userRemoteInspectValue = this.remoteUserConfiguration.inspect(this.key, this.overrides.overrideIdentifier);\n\t\t}\n\t\treturn this._userRemoteInspectValue;\n\t}\n\n\tget userRemoteValue(): V | undefined {\n\t\treturn this.userRemoteInspectValue.merged;\n\t}\n\n\tget userRemote(): IInspectValue | undefined {\n\t\treturn this.toInspectValue(this.userRemoteInspectValue);\n\t}\n\n\tprivate _workspaceInspectValue: InspectValue | undefined | null;\n\tprivate get workspaceInspectValue(): InspectValue | null {\n\t\tif (this._workspaceInspectValue === undefined) {\n\t\t\tthis._workspaceInspectValue = this.workspaceConfiguration ? this.workspaceConfiguration.inspect(this.key, this.overrides.overrideIdentifier) : null;\n\t\t}\n\t\treturn this._workspaceInspectValue;\n\t}\n\n\tget workspaceValue(): V | undefined {\n\t\treturn this.workspaceInspectValue?.merged;\n\t}\n\n\tget workspace(): IInspectValue | undefined {\n\t\treturn this.toInspectValue(this.workspaceInspectValue);\n\t}\n\n\tprivate _workspaceFolderInspectValue: InspectValue | undefined | null;\n\tprivate get workspaceFolderInspectValue(): InspectValue | null {\n\t\tif (this._workspaceFolderInspectValue === undefined) {\n\t\t\tthis._workspaceFolderInspectValue = this.folderConfigurationModel ? this.folderConfigurationModel.inspect(this.key, this.overrides.overrideIdentifier) : null;\n\t\t}\n\t\treturn this._workspaceFolderInspectValue;\n\t}\n\n\tget workspaceFolderValue(): V | undefined {\n\t\treturn this.workspaceFolderInspectValue?.merged;\n\t}\n\n\tget workspaceFolder(): IInspectValue | undefined {\n\t\treturn this.toInspectValue(this.workspaceFolderInspectValue);\n\t}\n\n\tprivate _memoryInspectValue: InspectValue | undefined;\n\tprivate get memoryInspectValue(): InspectValue {\n\t\tif (this._memoryInspectValue === undefined) {\n\t\t\tthis._memoryInspectValue = this.memoryConfigurationModel.inspect(this.key, this.overrides.overrideIdentifier);\n\t\t}\n\t\treturn this._memoryInspectValue;\n\t}\n\n\tget memoryValue(): V | undefined {\n\t\treturn this.memoryInspectValue.merged;\n\t}\n\n\tget memory(): IInspectValue | undefined {\n\t\treturn this.toInspectValue(this.memoryInspectValue);\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 = new ConfigurationModel(),\n\t\tprivate _workspaceConfiguration: ConfigurationModel = new ConfigurationModel(),\n\t\tprivate _folderConfigurations: ResourceMap = new ResourceMap(),\n\t\tprivate _memoryConfiguration: ConfigurationModel = new ConfigurationModel(),\n\t\tprivate _memoryConfigurationByResource: ResourceMap = new ResourceMap()\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 = new ConfigurationModel();\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\tkeys(workspace: Workspace | undefined): {\n\t\tdefault: string[];\n\t\tuser: string[];\n\t\tworkspace: string[];\n\t\tworkspaceFolder: string[];\n\t} {\n\t\tconst folderConfigurationModel = this.getFolderConfigurationModelForResource(undefined, workspace);\n\t\treturn {\n\t\t\tdefault: this._defaultConfiguration.keys.slice(0),\n\t\t\tuser: this.userConfiguration.keys.slice(0),\n\t\t\tworkspace: this._workspaceConfiguration.keys.slice(0),\n\t\t\tworkspaceFolder: folderConfigurationModel ? folderConfigurationModel.keys.slice(0) : []\n\t\t};\n\t}\n\n\tupdateDefaultConfiguration(defaultConfiguration: ConfigurationModel): void {\n\t\tthis._defaultConfiguration = defaultConfiguration;\n\t\tthis._workspaceConsolidatedConfiguration = null;\n\t\tthis._foldersConsolidatedConfigurations.clear();\n\t}\n\n\tupdatePolicyConfiguration(policyConfiguration: ConfigurationModel): void {\n\t\tthis._policyConfiguration = policyConfiguration;\n\t}\n\n\tupdateApplicationConfiguration(applicationConfiguration: ConfigurationModel): void {\n\t\tthis._applicationConfiguration = applicationConfiguration;\n\t\tthis._workspaceConsolidatedConfiguration = null;\n\t\tthis._foldersConsolidatedConfigurations.clear();\n\t}\n\n\tupdateLocalUserConfiguration(localUserConfiguration: ConfigurationModel): void {\n\t\tthis._localUserConfiguration = localUserConfiguration;\n\t\tthis._userConfiguration = null;\n\t\tthis._workspaceConsolidatedConfiguration = null;\n\t\tthis._foldersConsolidatedConfigurations.clear();\n\t}\n\n\tupdateRemoteUserConfiguration(remoteUserConfiguration: ConfigurationModel): void {\n\t\tthis._remoteUserConfiguration = remoteUserConfiguration;\n\t\tthis._userConfiguration = null;\n\t\tthis._workspaceConsolidatedConfiguration = null;\n\t\tthis._foldersConsolidatedConfigurations.clear();\n\t}\n\n\tupdateWorkspaceConfiguration(workspaceConfiguration: ConfigurationModel): void {\n\t\tthis._workspaceConfiguration = workspaceConfiguration;\n\t\tthis._workspaceConsolidatedConfiguration = null;\n\t\tthis._foldersConsolidatedConfigurations.clear();\n\t}\n\n\tupdateFolderConfiguration(resource: URI, configuration: ConfigurationModel): void {\n\t\tthis._folderConfigurations.set(resource, configuration);\n\t\tthis._foldersConsolidatedConfigurations.delete(resource);\n\t}\n\n\tdeleteFolderConfiguration(resource: URI): void {\n\t\tthis.folderConfigurations.delete(resource);\n\t\tthis._foldersConsolidatedConfigurations.delete(resource);\n\t}\n\n\tcompareAndUpdateDefaultConfiguration(defaults: ConfigurationModel, keys?: string[]): IConfigurationChange {\n\t\tconst overrides: [string, string[]][] = [];\n\t\tif (!keys) {\n\t\t\tconst { added, updated, removed } = compare(this._defaultConfiguration, defaults);\n\t\t\tkeys = [...added, ...updated, ...removed];\n\t\t}\n\t\tfor (const key of keys) {\n\t\t\tfor (const overrideIdentifier of overrideIdentifiersFromKey(key)) {\n\t\t\t\tconst fromKeys = this._defaultConfiguration.getKeysForOverrideIdentifier(overrideIdentifier);\n\t\t\t\tconst toKeys = defaults.getKeysForOverrideIdentifier(overrideIdentifier);\n\t\t\t\tconst keys = [\n\t\t\t\t\t...toKeys.filter(key => fromKeys.indexOf(key) === -1),\n\t\t\t\t\t...fromKeys.filter(key => toKeys.indexOf(key) === -1),\n\t\t\t\t\t...fromKeys.filter(key => !objects.equals(this._defaultConfiguration.override(overrideIdentifier).getValue(key), defaults.override(overrideIdentifier).getValue(key)))\n\t\t\t\t];\n\t\t\t\toverrides.push([overrideIdentifier, keys]);\n\t\t\t}\n\t\t}\n\t\tthis.updateDefaultConfiguration(defaults);\n\t\treturn { keys, overrides };\n\t}\n\n\tcompareAndUpdatePolicyConfiguration(policyConfiguration: ConfigurationModel): IConfigurationChange {\n\t\tconst { added, updated, removed } = compare(this._policyConfiguration, policyConfiguration);\n\t\tconst keys = [...added, ...updated, ...removed];\n\t\tif (keys.length) {\n\t\t\tthis.updatePolicyConfiguration(policyConfiguration);\n\t\t}\n\t\treturn { keys, overrides: [] };\n\t}\n\n\tcompareAndUpdateApplicationConfiguration(application: ConfigurationModel): IConfigurationChange {\n\t\tconst { added, updated, removed, overrides } = compare(this.applicationConfiguration, application);\n\t\tconst keys = [...added, ...updated, ...removed];\n\t\tif (keys.length) {\n\t\t\tthis.updateApplicationConfiguration(application);\n\t\t}\n\t\treturn { keys, overrides };\n\t}\n\n\tcompareAndUpdateLocalUserConfiguration(user: ConfigurationModel): IConfigurationChange {\n\t\tconst { added, updated, removed, overrides } = compare(this.localUserConfiguration, user);\n\t\tconst keys = [...added, ...updated, ...removed];\n\t\tif (keys.length) {\n\t\t\tthis.updateLocalUserConfiguration(user);\n\t\t}\n\t\treturn { keys, overrides };\n\t}\n\n\tcompareAndUpdateRemoteUserConfiguration(user: ConfigurationModel): IConfigurationChange {\n\t\tconst { added, updated, removed, overrides } = compare(this.remoteUserConfiguration, user);\n\t\tconst keys = [...added, ...updated, ...removed];\n\t\tif (keys.length) {\n\t\t\tthis.updateRemoteUserConfiguration(user);\n\t\t}\n\t\treturn { keys, overrides };\n\t}\n\n\tcompareAndUpdateWorkspaceConfiguration(workspaceConfiguration: ConfigurationModel): IConfigurationChange {\n\t\tconst { added, updated, removed, overrides } = compare(this.workspaceConfiguration, workspaceConfiguration);\n\t\tconst keys = [...added, ...updated, ...removed];\n\t\tif (keys.length) {\n\t\t\tthis.updateWorkspaceConfiguration(workspaceConfiguration);\n\t\t}\n\t\treturn { keys, overrides };\n\t}\n\n\tcompareAndUpdateFolderConfiguration(resource: URI, folderConfiguration: ConfigurationModel): IConfigurationChange {\n\t\tconst currentFolderConfiguration = this.folderConfigurations.get(resource);\n\t\tconst { added, updated, removed, overrides } = compare(currentFolderConfiguration, folderConfiguration);\n\t\tconst keys = [...added, ...updated, ...removed];\n\t\tif (keys.length || !currentFolderConfiguration) {\n\t\t\tthis.updateFolderConfiguration(resource, folderConfiguration);\n\t\t}\n\t\treturn { keys, overrides };\n\t}\n\n\tcompareAndDeleteFolderConfiguration(folder: URI): IConfigurationChange {\n\t\tconst folderConfig = this.folderConfigurations.get(folder);\n\t\tif (!folderConfig) {\n\t\t\tthrow new Error('Unknown folder');\n\t\t}\n\t\tthis.deleteFolderConfiguration(folder);\n\t\tconst { added, updated, removed, overrides } = compare(folderConfig, undefined);\n\t\treturn { keys: [...added, ...updated, ...removed], overrides };\n\t}\n\n\tget defaults(): ConfigurationModel {\n\t\treturn this._defaultConfiguration;\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\tget workspaceConfiguration(): ConfigurationModel {\n\t\treturn this._workspaceConfiguration;\n\t}\n\n\tget folderConfigurations(): ResourceMap {\n\t\treturn this._folderConfigurations;\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\tallKeys(): string[] {\n\t\tconst keys: Set = new Set();\n\t\tthis._defaultConfiguration.keys.forEach(key => keys.add(key));\n\t\tthis.userConfiguration.keys.forEach(key => keys.add(key));\n\t\tthis._workspaceConfiguration.keys.forEach(key => keys.add(key));\n\t\tthis._folderConfigurations.forEach(folderConfiguration => folderConfiguration.keys.forEach(key => keys.add(key)));\n\t\treturn [...keys.values()];\n\t}\n\n\tprotected allOverrideIdentifiers(): string[] {\n\t\tconst keys: Set = new Set();\n\t\tthis._defaultConfiguration.getAllOverrideIdentifiers().forEach(key => keys.add(key));\n\t\tthis.userConfiguration.getAllOverrideIdentifiers().forEach(key => keys.add(key));\n\t\tthis._workspaceConfiguration.getAllOverrideIdentifiers().forEach(key => keys.add(key));\n\t\tthis._folderConfigurations.forEach(folderConfiguration => folderConfiguration.getAllOverrideIdentifiers().forEach(key => keys.add(key)));\n\t\treturn [...keys.values()];\n\t}\n\n\tprotected getAllKeysForOverrideIdentifier(overrideIdentifier: string): string[] {\n\t\tconst keys: Set = new Set();\n\t\tthis._defaultConfiguration.getKeysForOverrideIdentifier(overrideIdentifier).forEach(key => keys.add(key));\n\t\tthis.userConfiguration.getKeysForOverrideIdentifier(overrideIdentifier).forEach(key => keys.add(key));\n\t\tthis._workspaceConfiguration.getKeysForOverrideIdentifier(overrideIdentifier).forEach(key => keys.add(key));\n\t\tthis._folderConfigurations.forEach(folderConfiguration => folderConfiguration.getKeysForOverrideIdentifier(overrideIdentifier).forEach(key => keys.add(key)));\n\t\treturn [...keys.values()];\n\t}\n\n\tstatic parse(data: IConfigurationData): Configuration {\n\t\tconst defaultConfiguration = this.parseConfigurationModel(data.defaults);\n\t\tconst policyConfiguration = this.parseConfigurationModel(data.policy);\n\t\tconst applicationConfiguration = this.parseConfigurationModel(data.application);\n\t\tconst userConfiguration = this.parseConfigurationModel(data.user);\n\t\tconst workspaceConfiguration = this.parseConfigurationModel(data.workspace);\n\t\tconst folders: ResourceMap = data.folders.reduce((result, value) => {\n\t\t\tresult.set(URI.revive(value[0]), this.parseConfigurationModel(value[1]));\n\t\t\treturn result;\n\t\t}, new ResourceMap());\n\t\treturn new Configuration(defaultConfiguration, policyConfiguration, applicationConfiguration, userConfiguration, new ConfigurationModel(), workspaceConfiguration, folders, new ConfigurationModel(), new ResourceMap());\n\t}\n\n\tprivate static parseConfigurationModel(model: IConfigurationModel): ConfigurationModel {\n\t\treturn new ConfigurationModel(model.contents, model.keys, model.overrides);\n\t}\n\n}\n\nexport function mergeChanges(...changes: IConfigurationChange[]): IConfigurationChange {\n\tif (changes.length === 0) {\n\t\treturn { keys: [], overrides: [] };\n\t}\n\tif (changes.length === 1) {\n\t\treturn changes[0];\n\t}\n\tconst keysSet = new Set();\n\tconst overridesMap = new Map>();\n\tfor (const change of changes) {\n\t\tchange.keys.forEach(key => keysSet.add(key));\n\t\tchange.overrides.forEach(([identifier, keys]) => {\n\t\t\tconst result = getOrSet(overridesMap, identifier, new Set());\n\t\t\tkeys.forEach(key => result.add(key));\n\t\t});\n\t}\n\tconst overrides: [string, string[]][] = [];\n\toverridesMap.forEach((keys, identifier) => overrides.push([identifier, [...keys.values()]]));\n\treturn { keys: [...keysSet.values()], overrides };\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(readonly change: IConfigurationChange, private readonly previous: { workspace?: Workspace; data: IConfigurationData } | undefined, private readonly currentConfiguraiton: Configuration, private readonly currentWorkspace?: Workspace) {\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);\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\nfunction compare(from: ConfigurationModel | undefined, to: ConfigurationModel | undefined): IConfigurationCompareResult {\n\tconst { added, removed, updated } = compareConfigurationContents(to?.rawConfiguration, from?.rawConfiguration);\n\tconst overrides: [string, string[]][] = [];\n\n\tconst fromOverrideIdentifiers = from?.getAllOverrideIdentifiers() || [];\n\tconst toOverrideIdentifiers = to?.getAllOverrideIdentifiers() || [];\n\n\tif (to) {\n\t\tconst addedOverrideIdentifiers = toOverrideIdentifiers.filter(key => !fromOverrideIdentifiers.includes(key));\n\t\tfor (const identifier of addedOverrideIdentifiers) {\n\t\t\toverrides.push([identifier, to.getKeysForOverrideIdentifier(identifier)]);\n\t\t}\n\t}\n\n\tif (from) {\n\t\tconst removedOverrideIdentifiers = fromOverrideIdentifiers.filter(key => !toOverrideIdentifiers.includes(key));\n\t\tfor (const identifier of removedOverrideIdentifiers) {\n\t\t\toverrides.push([identifier, from.getKeysForOverrideIdentifier(identifier)]);\n\t\t}\n\t}\n\n\tif (to && from) {\n\t\tfor (const identifier of fromOverrideIdentifiers) {\n\t\t\tif (toOverrideIdentifiers.includes(identifier)) {\n\t\t\t\tconst result = compareConfigurationContents({ contents: from.getOverrideValue(undefined, identifier) || {}, keys: from.getKeysForOverrideIdentifier(identifier) }, { contents: to.getOverrideValue(undefined, identifier) || {}, keys: to.getKeysForOverrideIdentifier(identifier) });\n\t\t\t\toverrides.push([identifier, [...result.added, ...result.removed, ...result.updated]]);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { added, removed, updated, overrides };\n}\n\nfunction compareConfigurationContents(to: { keys: string[]; contents: any } | undefined, from: { keys: string[]; contents: any } | undefined) {\n\tconst added = to\n\t\t? from ? to.keys.filter(key => from.keys.indexOf(key) === -1) : [...to.keys]\n\t\t: [];\n\tconst removed = from\n\t\t? to ? from.keys.filter(key => to.keys.indexOf(key) === -1) : [...from.keys]\n\t\t: [];\n\tconst updated: string[] = [];\n\n\tif (to && from) {\n\t\tfor (const key of from.keys) {\n\t\t\tif (to.keys.indexOf(key) !== -1) {\n\t\t\t\tconst value1 = getConfigurationValue(from.contents, key);\n\t\t\t\tconst value2 = getConfigurationValue(to.contents, key);\n\t\t\t\tif (!objects.equals(value1, value2)) {\n\t\t\t\t\tupdated.push(key);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn { added, removed, updated };\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { IStringDictionary } from 'vs/base/common/collections';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { equals } from 'vs/base/common/objects';\nimport { isEmptyObject } from 'vs/base/common/types';\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 { IPolicyService, PolicyDefinition, PolicyName, PolicyValue } from 'vs/platform/policy/common/policy';\nimport { Registry } from 'vs/platform/registry/common/platform';\n\nexport class DefaultConfiguration extends Disposable {\n\n\tprivate readonly _onDidChangeConfiguration = this._register(new Emitter<{ defaults: ConfigurationModel; properties: string[] }>());\n\treadonly onDidChangeConfiguration = this._onDidChangeConfiguration.event;\n\n\tprivate _configurationModel = new ConfigurationModel();\n\tget configurationModel(): ConfigurationModel {\n\t\treturn this._configurationModel;\n\t}\n\n\tasync initialize(): Promise {\n\t\tthis.resetConfigurationModel();\n\t\tthis._register(Registry.as(Extensions.Configuration).onDidUpdateConfiguration(({ properties, defaultsOverrides }) => this.onDidUpdateConfiguration(Array.from(properties), defaultsOverrides)));\n\t\treturn this.configurationModel;\n\t}\n\n\treload(): ConfigurationModel {\n\t\tthis.resetConfigurationModel();\n\t\treturn this.configurationModel;\n\t}\n\n\tprotected onDidUpdateConfiguration(properties: string[], defaultsOverrides?: boolean): void {\n\t\tthis.updateConfigurationModel(properties, Registry.as(Extensions.Configuration).getConfigurationProperties());\n\t\tthis._onDidChangeConfiguration.fire({ defaults: this.configurationModel, properties });\n\t}\n\n\tprotected getConfigurationDefaultOverrides(): IStringDictionary {\n\t\treturn {};\n\t}\n\n\tprivate resetConfigurationModel(): void {\n\t\tthis._configurationModel = new ConfigurationModel();\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\nexport interface IPolicyConfiguration {\n\treadonly onDidChangeConfiguration: Event;\n\treadonly configurationModel: ConfigurationModel;\n\tinitialize(): Promise;\n}\n\nexport class NullPolicyConfiguration implements IPolicyConfiguration {\n\treadonly onDidChangeConfiguration = Event.None;\n\treadonly configurationModel = new ConfigurationModel();\n\tasync initialize() { return this.configurationModel; }\n}\n\nexport class PolicyConfiguration extends Disposable implements IPolicyConfiguration {\n\n\tprivate readonly _onDidChangeConfiguration = this._register(new Emitter());\n\treadonly onDidChangeConfiguration = this._onDidChangeConfiguration.event;\n\n\tprivate _configurationModel = new ConfigurationModel();\n\tget configurationModel() { return this._configurationModel; }\n\n\tconstructor(\n\t\tprivate readonly defaultConfiguration: DefaultConfiguration,\n\t\t@IPolicyService private readonly policyService: IPolicyService,\n\t\t@ILogService private readonly logService: ILogService\n\t) {\n\t\tsuper();\n\t}\n\n\tasync initialize(): Promise {\n\t\tthis.logService.trace('PolicyConfiguration#initialize');\n\t\tthis.update(await this.updatePolicyDefinitions(this.defaultConfiguration.configurationModel.keys), false);\n\t\tthis._register(this.policyService.onDidChange(policyNames => this.onDidChangePolicies(policyNames)));\n\t\tthis._register(this.defaultConfiguration.onDidChangeConfiguration(async ({ properties }) => this.update(await this.updatePolicyDefinitions(properties), true)));\n\t\treturn this._configurationModel;\n\t}\n\n\tprivate async updatePolicyDefinitions(properties: string[]): Promise {\n\t\tthis.logService.trace('PolicyConfiguration#updatePolicyDefinitions', properties);\n\t\tconst policyDefinitions: IStringDictionary = {};\n\t\tconst keys: string[] = [];\n\t\tconst configurationProperties = Registry.as(Extensions.Configuration).getConfigurationProperties();\n\n\t\tfor (const key of properties) {\n\t\t\tconst config = configurationProperties[key];\n\t\t\tif (!config) {\n\t\t\t\t// Config is removed. So add it to the list if in case it was registered as policy before\n\t\t\t\tkeys.push(key);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (config.policy) {\n\t\t\t\tif (config.type !== 'string' && config.type !== 'number') {\n\t\t\t\t\tthis.logService.warn(`Policy ${config.policy.name} has unsupported type ${config.type}`);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tkeys.push(key);\n\t\t\t\tpolicyDefinitions[config.policy.name] = { type: config.type };\n\t\t\t}\n\t\t}\n\n\t\tif (!isEmptyObject(policyDefinitions)) {\n\t\t\tawait this.policyService.updatePolicyDefinitions(policyDefinitions);\n\t\t}\n\n\t\treturn keys;\n\t}\n\n\tprivate onDidChangePolicies(policyNames: readonly PolicyName[]): void {\n\t\tthis.logService.trace('PolicyConfiguration#onDidChangePolicies', policyNames);\n\t\tconst policyConfigurations = Registry.as(Extensions.Configuration).getPolicyConfigurations();\n\t\tconst keys = coalesce(policyNames.map(policyName => policyConfigurations.get(policyName)));\n\t\tthis.update(keys, true);\n\t}\n\n\tprivate update(keys: string[], trigger: boolean): void {\n\t\tthis.logService.trace('PolicyConfiguration#update', keys);\n\t\tconst configurationProperties = Registry.as(Extensions.Configuration).getConfigurationProperties();\n\t\tconst changed: [string, PolicyValue | undefined][] = [];\n\t\tconst wasEmpty = this._configurationModel.isEmpty();\n\n\t\tfor (const key of keys) {\n\t\t\tconst policyName = configurationProperties[key]?.policy?.name;\n\t\t\tif (policyName) {\n\t\t\t\tconst policyValue = this.policyService.getPolicyValue(policyName);\n\t\t\t\tif (wasEmpty ? policyValue !== undefined : !equals(this._configurationModel.getValue(key), policyValue)) {\n\t\t\t\t\tchanged.push([key, policyValue]);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (this._configurationModel.getValue(key) !== undefined) {\n\t\t\t\t\tchanged.push([key, undefined]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (changed.length) {\n\t\t\tthis.logService.trace('PolicyConfiguration#changed', changed);\n\t\t\tconst old = this._configurationModel;\n\t\t\tthis._configurationModel = new ConfigurationModel();\n\t\t\tfor (const key of old.keys) {\n\t\t\t\tthis._configurationModel.setValue(key, old.getValue(key));\n\t\t\t}\n\t\t\tfor (const [key, policyValue] of changed) {\n\t\t\t\tif (policyValue === undefined) {\n\t\t\t\t\tthis._configurationModel.removeValue(key);\n\t\t\t\t} else {\n\t\t\t\t\tthis._configurationModel.setValue(key, policyValue);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (trigger) {\n\t\t\t\tthis._onDidChangeConfiguration.fire(this._configurationModel);\n\t\t\t}\n\t\t}\n\t}\n\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\twhen?: ContextKeyExpression | null | undefined;\n}\n\nexport interface IExtensionKeybindingRule {\n\tkeybinding: Keybinding | null;\n\tid: string;\n\targs?: any;\n\tweight: number;\n\twhen: ContextKeyExpression | undefined;\n\textensionId?: string;\n\tisBuiltinExtension?: boolean;\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\tsetExtensionKeybindings(rules: IExtensionKeybindingRule[]): void;\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 setExtensionKeybindings(rules: IExtensionKeybindingRule[]): void {\n\t\tconst result: IKeybindingItem[] = [];\n\t\tlet keybindingsLen = 0;\n\t\tfor (const rule of rules) {\n\t\t\tif (rule.keybinding) {\n\t\t\t\tresult[keybindingsLen++] = {\n\t\t\t\t\tkeybinding: rule.keybinding,\n\t\t\t\t\tcommand: rule.id,\n\t\t\t\t\tcommandArgs: rule.args,\n\t\t\t\t\twhen: rule.when,\n\t\t\t\t\tweight1: rule.weight,\n\t\t\t\t\tweight2: 0,\n\t\t\t\t\textensionId: rule.extensionId || null,\n\t\t\t\t\tisBuiltinExtension: rule.isBuiltinExtension || false\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tthis._extensionKeybindings = result;\n\t\tthis._cachedMergedKeybindings = null;\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, 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\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 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 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 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 ChatMessageTitle = new MenuId('ChatMessageTitle');\n\tstatic readonly ChatExecute = new MenuId('ChatExecute');\n\tstatic readonly ChatInputSide = new MenuId('ChatInputSide');\n\tstatic readonly AccessibleView = new MenuId('AccessibleView');\n\tstatic readonly MultiDiffEditorFileToolbar = new MenuId('MultiDiffEditorFileToolbar');\n\n\t/**\n\t * Create or reuse a `MenuId` with the given identifier\n\t */\n\tstatic for(identifier: string): MenuId {\n\t\treturn MenuId._instances.get(identifier) ?? new MenuId(identifier);\n\t}\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\tgetCommand(id: string): ICommandAction | undefined;\n\tgetCommands(): ICommandsMap;\n\n\t/**\n\t * @deprecated Use `appendMenuItem` or most likely use `registerAction2` instead. There should be no strong\n\t * reason to use this directly.\n\t */\n\tappendMenuItems(items: Iterable<{ id: MenuId; item: IMenuItem | ISubmenuItem }>): 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\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, 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\tcategory?: keyof typeof Categories | ILocalizedString;\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 = new DisposableStore();\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.add(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.add(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.add(MenuRegistry.appendMenuItem(menu.id, { command: { ...command, precondition: menu.precondition === null ? undefined : command.precondition }, ...menu }));\n\t}\n\tif (f1) {\n\t\tdisposables.add(MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command, when: command.precondition }));\n\t\tdisposables.add(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.add(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.add(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 disposables;\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\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 { localize2 } from 'vs/nls';\nimport { Categories } from 'vs/platform/action/common/actionCommonCategories';\nimport { Action2, IMenuService } from 'vs/platform/actions/common/actions';\nimport { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';\nimport { ILogService } from 'vs/platform/log/common/log';\n\nexport class MenuHiddenStatesReset extends Action2 {\n\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'menu.resetHiddenStates',\n\t\t\ttitle: localize2('title', \"Reset All Menus\"),\n\t\t\tcategory: Categories.View,\n\t\t\tf1: true\n\t\t});\n\t}\n\n\trun(accessor: ServicesAccessor): void {\n\t\taccessor.get(IMenuService).resetHiddenStates();\n\t\taccessor.get(ILogService).info('did RESET all menu hidden states');\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { HistoryInputBox, IHistoryInputOptions } from 'vs/base/browser/ui/inputbox/inputBox';\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 ContextScopedHistoryInputBox extends HistoryInputBox {\n\n\tconstructor(container: HTMLElement, contextViewProvider: IContextViewProvider | undefined, options: IHistoryInputOptions,\n\t\t@IContextKeyService contextKeyService: IContextKeyService\n\t) {\n\t\tsuper(container, contextViewProvider, options);\n\t\tconst scopedContextKeyService = this._register(contextKeyService.createScoped(this.element));\n\t\tthis._register(registerAndCreateHistoryNavigationContext(scopedContextKeyService, this));\n\t}\n\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_brand!: 'ISuggestionItem';\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 function setSnippetSuggestSupport(support: languages.CompletionItemProvider): languages.CompletionItemProvider {\n\tconst old = _snippetSuggestSupport;\n\t_snippetSuggestSupport = support;\n\treturn old;\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 * as nls from 'vs/nls';\nimport { IConfigurationService } from 'vs/platform/configuration/common/configuration';\nimport { OS, OperatingSystem } from 'vs/base/common/platform';\nimport { ConfigurationScope, Extensions as ConfigExtensions, IConfigurationNode, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';\nimport { Registry } from 'vs/platform/registry/common/platform';\n\nexport const enum DispatchConfig {\n\tCode,\n\tKeyCode\n}\n\nexport interface IKeyboardConfig {\n\tdispatch: DispatchConfig;\n\tmapAltGrToCtrlAlt: boolean;\n}\n\nexport function readKeyboardConfig(configurationService: IConfigurationService): IKeyboardConfig {\n\tconst keyboard = configurationService.getValue<{ dispatch: any; mapAltGrToCtrlAlt: any } | undefined>('keyboard');\n\tconst dispatch = (keyboard?.dispatch === 'keyCode' ? DispatchConfig.KeyCode : DispatchConfig.Code);\n\tconst mapAltGrToCtrlAlt = Boolean(keyboard?.mapAltGrToCtrlAlt);\n\treturn { dispatch, mapAltGrToCtrlAlt };\n}\n\nconst configurationRegistry = Registry.as(ConfigExtensions.Configuration);\nconst keyboardConfiguration: IConfigurationNode = {\n\t'id': 'keyboard',\n\t'order': 15,\n\t'type': 'object',\n\t'title': nls.localize('keyboardConfigurationTitle', \"Keyboard\"),\n\t'properties': {\n\t\t'keyboard.dispatch': {\n\t\t\tscope: ConfigurationScope.APPLICATION,\n\t\t\ttype: 'string',\n\t\t\tenum: ['code', 'keyCode'],\n\t\t\tdefault: 'code',\n\t\t\tmarkdownDescription: nls.localize('dispatch', \"Controls the dispatching logic for key presses to use either `code` (recommended) or `keyCode`.\"),\n\t\t\tincluded: OS === OperatingSystem.Macintosh || OS === OperatingSystem.Linux\n\t\t},\n\t\t'keyboard.mapAltGrToCtrlAlt': {\n\t\t\tscope: ConfigurationScope.APPLICATION,\n\t\t\ttype: 'boolean',\n\t\t\tdefault: false,\n\t\t\tmarkdownDescription: nls.localize('mapAltGrToCtrlAlt', \"Controls if the AltGraph+ modifier should be treated as Ctrl+Alt+.\"),\n\t\t\tincluded: OS === OperatingSystem.Windows\n\t\t}\n\t}\n};\n\nconfigurationRegistry.registerConfiguration(keyboardConfiguration);\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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}\n\n/**\n * The specific options for the AnythingQuickAccessProvider. Put here to share between layers.\n */\nexport interface AnythingQuickAccessProviderRunOptions extends IQuickAccessProviderRunOptions {\n\treadonly includeHelp?: boolean;\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\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\t/**\n\t * Same as `show()` but instead of executing the selected pick item,\n\t * it will be returned. May return `undefined` in case no item was\n\t * picked by the user.\n\t */\n\tpick(value?: string, options?: IQuickAccessOptions): Promise;\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\t/**\n\t * The order of help entries in the Command Center.\n\t * Lower values will be placed above higher values.\n\t * No value will hide this help entry from the Command Center.\n\t */\n\treadonly commandCenterOrder?: number;\n\n\t/**\n\t * An optional label to use for the Command Center entry. If not set\n\t * the description will be used instead.\n\t */\n\treadonly commandCenterLabel?: 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\tclear(): Function {\n\t\tconst providers = [...this.providers];\n\t\tconst defaultProvider = this.defaultProvider;\n\n\t\tthis.providers = [];\n\t\tthis.defaultProvider = undefined;\n\n\t\treturn () => {\n\t\t\tthis.providers = providers;\n\t\t\tthis.defaultProvider = defaultProvider;\n\t\t};\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 { 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, IQuickAccessProviderRunOptions, 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\tpick(value = '', options?: IQuickAccessOptions): Promise {\n\t\treturn this.doShowOrPick(value, true, options);\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);\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// 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 = 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?.providerOptions));\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// 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\tproviderOptions?: IQuickAccessProviderRunOptions\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);\n\t\t\tif (providerForValue !== provider) {\n\t\t\t\tthis.show(value, {\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\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): [IQuickAccessProvider | undefined, IQuickAccessProviderDescriptor | undefined] {\n\t\tconst providerDescriptor = this.registry.getQuickAccessProvider(value);\n\t\tif (!providerDescriptor) {\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 { VSBuffer, encodeBase64 } from 'vs/base/common/buffer';\nimport { Emitter, Event, PauseableEmitter } from 'vs/base/common/event';\nimport { Disposable, DisposableStore } from 'vs/base/common/lifecycle';\nimport { ISocket, SocketCloseEvent, SocketDiagnostics, SocketDiagnosticsEventType } from 'vs/base/parts/ipc/common/ipc.net';\n\nexport const makeRawSocketHeaders = (path: string, query: string, deubgLabel: string) => {\n\t// https://tools.ietf.org/html/rfc6455#section-4\n\tconst buffer = new Uint8Array(16);\n\tfor (let i = 0; i < 16; i++) {\n\t\tbuffer[i] = Math.round(Math.random() * 256);\n\t}\n\tconst nonce = encodeBase64(VSBuffer.wrap(buffer));\n\n\tconst headers = [\n\t\t`GET ws://localhost${path}?${query}&skipWebSocketFrames=true HTTP/1.1`,\n\t\t`Connection: Upgrade`,\n\t\t`Upgrade: websocket`,\n\t\t`Sec-WebSocket-Key: ${nonce}`\n\t];\n\n\treturn headers.join('\\r\\n') + '\\r\\n\\r\\n';\n};\n\nexport const socketRawEndHeaderSequence = VSBuffer.fromString('\\r\\n\\r\\n');\n\nexport interface RemoteSocketHalf {\n\tonData: Emitter;\n\tonClose: Emitter;\n\tonEnd: Emitter;\n}\n\n/** Should be called immediately after making a ManagedSocket to make it ready for data flow. */\nexport async function connectManagedSocket(\n\tsocket: T,\n\tpath: string, query: string, debugLabel: string,\n\thalf: RemoteSocketHalf\n): Promise {\n\tsocket.write(VSBuffer.fromString(makeRawSocketHeaders(path, query, debugLabel)));\n\n\tconst d = new DisposableStore();\n\ttry {\n\t\treturn await new Promise((resolve, reject) => {\n\t\t\tlet dataSoFar: VSBuffer | undefined;\n\t\t\td.add(socket.onData(d_1 => {\n\t\t\t\tif (!dataSoFar) {\n\t\t\t\t\tdataSoFar = d_1;\n\t\t\t\t} else {\n\t\t\t\t\tdataSoFar = VSBuffer.concat([dataSoFar, d_1], dataSoFar.byteLength + d_1.byteLength);\n\t\t\t\t}\n\n\t\t\t\tconst index = dataSoFar.indexOf(socketRawEndHeaderSequence);\n\t\t\t\tif (index === -1) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tresolve(socket);\n\t\t\t\t// pause data events until the socket consumer is hooked up. We may\n\t\t\t\t// immediately emit remaining data, but if not there may still be\n\t\t\t\t// microtasks queued which would fire data into the abyss.\n\t\t\t\tsocket.pauseData();\n\n\t\t\t\tconst rest = dataSoFar.slice(index + socketRawEndHeaderSequence.byteLength);\n\t\t\t\tif (rest.byteLength) {\n\t\t\t\t\thalf.onData.fire(rest);\n\t\t\t\t}\n\t\t\t}));\n\n\t\t\td.add(socket.onClose(err => reject(err ?? new Error('socket closed'))));\n\t\t\td.add(socket.onEnd(() => reject(new Error('socket ended'))));\n\t\t});\n\t} catch (e) {\n\t\tsocket.dispose();\n\t\tthrow e;\n\t} finally {\n\t\td.dispose();\n\t}\n}\n\nexport abstract class ManagedSocket extends Disposable implements ISocket {\n\tprivate readonly pausableDataEmitter = this._register(new PauseableEmitter());\n\n\tpublic onData: Event = (...args) => {\n\t\tif (this.pausableDataEmitter.isPaused) {\n\t\t\tqueueMicrotask(() => this.pausableDataEmitter.resume());\n\t\t}\n\t\treturn this.pausableDataEmitter.event(...args);\n\t};\n\tpublic onClose: Event;\n\tpublic onEnd: Event;\n\n\tprivate readonly didDisposeEmitter = this._register(new Emitter());\n\tpublic onDidDispose = this.didDisposeEmitter.event;\n\n\tprivate ended = false;\n\n\tprotected constructor(\n\t\tprivate readonly debugLabel: string,\n\t\thalf: RemoteSocketHalf,\n\t) {\n\t\tsuper();\n\n\t\tthis._register(half.onData);\n\t\tthis._register(half.onData.event(data => this.pausableDataEmitter.fire(data)));\n\n\t\tthis.onClose = this._register(half.onClose).event;\n\t\tthis.onEnd = this._register(half.onEnd).event;\n\t}\n\n\t/** Pauses data events until a new listener comes in onData() */\n\tpublic pauseData() {\n\t\tthis.pausableDataEmitter.pause();\n\t}\n\n\t/** Flushes data to the socket. */\n\tpublic drain(): Promise {\n\t\treturn Promise.resolve();\n\t}\n\n\t/** Ends the remote socket. */\n\tpublic end(): void {\n\t\tthis.ended = true;\n\t\tthis.closeRemote();\n\t}\n\n\tpublic abstract write(buffer: VSBuffer): void;\n\tprotected abstract closeRemote(): void;\n\n\ttraceSocketEvent(type: SocketDiagnosticsEventType, data?: any): void {\n\t\tSocketDiagnostics.traceSocketEvent(this, this.debugLabel, type, data);\n\t}\n\n\toverride dispose(): void {\n\t\tif (!this.ended) {\n\t\t\tthis.closeRemote();\n\t\t}\n\n\t\tthis.didDisposeEmitter.fire();\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 { ErrorNoTelemetry } from 'vs/base/common/errors';\nimport { Event } from 'vs/base/common/event';\nimport { URI } from 'vs/base/common/uri';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\n\nexport const IRemoteAuthorityResolverService = createDecorator('remoteAuthorityResolverService');\n\nexport const enum RemoteConnectionType {\n\tWebSocket,\n\tManaged\n}\n\nexport class ManagedRemoteConnection {\n\tpublic readonly type = RemoteConnectionType.Managed;\n\n\tconstructor(\n\t\tpublic readonly id: number\n\t) { }\n\n\tpublic toString(): string {\n\t\treturn `Managed(${this.id})`;\n\t}\n}\n\nexport class WebSocketRemoteConnection {\n\tpublic readonly type = RemoteConnectionType.WebSocket;\n\n\tconstructor(\n\t\tpublic readonly host: string,\n\t\tpublic readonly port: number,\n\t) { }\n\n\tpublic toString(): string {\n\t\treturn `WebSocket(${this.host}:${this.port})`;\n\t}\n}\n\nexport type RemoteConnection = WebSocketRemoteConnection | ManagedRemoteConnection;\n\nexport type RemoteConnectionOfType = RemoteConnection & { type: T };\n\nexport interface ResolvedAuthority {\n\treadonly authority: string;\n\treadonly connectTo: RemoteConnection;\n\treadonly connectionToken: string | undefined;\n}\n\nexport interface ResolvedOptions {\n\treadonly extensionHostEnv?: { [key: string]: string | null };\n\treadonly isTrusted?: boolean;\n\treadonly authenticationSession?: { id: string; providerId: string };\n}\n\nexport interface TunnelDescription {\n\tremoteAddress: { port: number; host: string };\n\tlocalAddress: { port: number; host: string } | string;\n\tprivacy?: string;\n\tprotocol?: string;\n}\nexport interface TunnelPrivacy {\n\tthemeIcon: string;\n\tid: string;\n\tlabel: string;\n}\nexport interface TunnelInformation {\n\tenvironmentTunnels?: TunnelDescription[];\n\tfeatures?: {\n\t\televation: boolean;\n\t\tpublic?: boolean;\n\t\tprivacyOptions: TunnelPrivacy[];\n\t\tprotocol: boolean;\n\t};\n}\n\nexport interface ResolverResult {\n\tauthority: ResolvedAuthority;\n\toptions?: ResolvedOptions;\n\ttunnelInformation?: TunnelInformation;\n}\n\nexport interface IRemoteConnectionData {\n\tconnectTo: RemoteConnection;\n\tconnectionToken: string | undefined;\n}\n\nexport enum RemoteAuthorityResolverErrorCode {\n\tUnknown = 'Unknown',\n\tNotAvailable = 'NotAvailable',\n\tTemporarilyNotAvailable = 'TemporarilyNotAvailable',\n\tNoResolverFound = 'NoResolverFound',\n\tInvalidAuthority = 'InvalidAuthority'\n}\n\nexport class RemoteAuthorityResolverError extends ErrorNoTelemetry {\n\n\tpublic static isNotAvailable(err: any): boolean {\n\t\treturn (err instanceof RemoteAuthorityResolverError) && err._code === RemoteAuthorityResolverErrorCode.NotAvailable;\n\t}\n\n\tpublic static isTemporarilyNotAvailable(err: any): boolean {\n\t\treturn (err instanceof RemoteAuthorityResolverError) && err._code === RemoteAuthorityResolverErrorCode.TemporarilyNotAvailable;\n\t}\n\n\tpublic static isNoResolverFound(err: any): err is RemoteAuthorityResolverError {\n\t\treturn (err instanceof RemoteAuthorityResolverError) && err._code === RemoteAuthorityResolverErrorCode.NoResolverFound;\n\t}\n\n\tpublic static isInvalidAuthority(err: any): boolean {\n\t\treturn (err instanceof RemoteAuthorityResolverError) && err._code === RemoteAuthorityResolverErrorCode.InvalidAuthority;\n\t}\n\n\tpublic static isHandled(err: any): boolean {\n\t\treturn (err instanceof RemoteAuthorityResolverError) && err.isHandled;\n\t}\n\n\tpublic readonly _message: string | undefined;\n\tpublic readonly _code: RemoteAuthorityResolverErrorCode;\n\tpublic readonly _detail: any;\n\n\tpublic isHandled: boolean;\n\n\tconstructor(message?: string, code: RemoteAuthorityResolverErrorCode = RemoteAuthorityResolverErrorCode.Unknown, detail?: any) {\n\t\tsuper(message);\n\n\t\tthis._message = message;\n\t\tthis._code = code;\n\t\tthis._detail = detail;\n\n\t\tthis.isHandled = (code === RemoteAuthorityResolverErrorCode.NotAvailable) && detail === true;\n\n\t\t// workaround when extending builtin objects and when compiling to ES5, see:\n\t\t// https://github.com/microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work\n\t\tObject.setPrototypeOf(this, RemoteAuthorityResolverError.prototype);\n\t}\n}\n\nexport interface IRemoteAuthorityResolverService {\n\n\treadonly _serviceBrand: undefined;\n\n\treadonly onDidChangeConnectionData: Event;\n\n\tresolveAuthority(authority: string): Promise;\n\tgetConnectionData(authority: string): IRemoteConnectionData | null;\n\t/**\n\t * Get the canonical URI for a `vscode-remote://` URI.\n\t *\n\t * **NOTE**: This can throw e.g. in cases where there is no resolver installed for the specific remote authority.\n\t *\n\t * @param uri The `vscode-remote://` URI\n\t */\n\tgetCanonicalURI(uri: URI): Promise;\n\n\t_clearResolvedAuthority(authority: string): void;\n\t_setResolvedAuthority(resolvedAuthority: ResolvedAuthority, resolvedOptions?: ResolvedOptions): void;\n\t_setResolvedAuthorityError(authority: string, err: any): void;\n\t_setAuthorityConnectionToken(authority: string, connectionToken: string): void;\n\t_setCanonicalURIProvider(provider: (uri: URI) => Promise): void;\n}\n\nexport function getRemoteAuthorityPrefix(remoteAuthority: string): string {\n\tconst plusIndex = remoteAuthority.indexOf('+');\n\tif (plusIndex === -1) {\n\t\treturn remoteAuthority;\n\t}\n\treturn remoteAuthority.substring(0, plusIndex);\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { RunOnceScheduler } from 'vs/base/common/async';\nimport { VSBuffer } from 'vs/base/common/buffer';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { Disposable, IDisposable } from 'vs/base/common/lifecycle';\nimport { ISocket, SocketCloseEvent, SocketCloseEventType, SocketDiagnostics, SocketDiagnosticsEventType } from 'vs/base/parts/ipc/common/ipc.net';\nimport { ISocketFactory } from 'vs/platform/remote/common/remoteSocketFactoryService';\nimport { RemoteAuthorityResolverError, RemoteAuthorityResolverErrorCode, RemoteConnectionType, WebSocketRemoteConnection } from 'vs/platform/remote/common/remoteAuthorityResolver';\nimport { mainWindow } from 'vs/base/browser/window';\n\nexport interface IWebSocketFactory {\n\tcreate(url: string, debugLabel: string): IWebSocket;\n}\n\nexport interface IWebSocketCloseEvent {\n\t/**\n\t * Returns the WebSocket connection close code provided by the server.\n\t */\n\treadonly code: number;\n\t/**\n\t * Returns the WebSocket connection close reason provided by the server.\n\t */\n\treadonly reason: string;\n\t/**\n\t * Returns true if the connection closed cleanly; false otherwise.\n\t */\n\treadonly wasClean: boolean;\n\t/**\n\t * Underlying event.\n\t */\n\treadonly event: any | undefined;\n}\n\nexport interface IWebSocket {\n\treadonly onData: Event;\n\treadonly onOpen: Event;\n\treadonly onClose: Event;\n\treadonly onError: Event;\n\n\ttraceSocketEvent?(type: SocketDiagnosticsEventType, data?: VSBuffer | Uint8Array | ArrayBuffer | ArrayBufferView | any): void;\n\tsend(data: ArrayBuffer | ArrayBufferView): void;\n\tclose(): void;\n}\n\nclass BrowserWebSocket extends Disposable implements IWebSocket {\n\n\tprivate readonly _onData = new Emitter();\n\tpublic readonly onData = this._onData.event;\n\n\tprivate readonly _onOpen = this._register(new Emitter());\n\tpublic readonly onOpen = this._onOpen.event;\n\n\tprivate readonly _onClose = this._register(new Emitter());\n\tpublic readonly onClose = this._onClose.event;\n\n\tprivate readonly _onError = this._register(new Emitter());\n\tpublic readonly onError = this._onError.event;\n\n\tprivate readonly _debugLabel: string;\n\tprivate readonly _socket: WebSocket;\n\tprivate readonly _fileReader: FileReader;\n\tprivate readonly _queue: Blob[];\n\tprivate _isReading: boolean;\n\tprivate _isClosed: boolean;\n\n\tprivate readonly _socketMessageListener: (ev: MessageEvent) => void;\n\n\tpublic traceSocketEvent(type: SocketDiagnosticsEventType, data?: VSBuffer | Uint8Array | ArrayBuffer | ArrayBufferView | any): void {\n\t\tSocketDiagnostics.traceSocketEvent(this._socket, this._debugLabel, type, data);\n\t}\n\n\tconstructor(url: string, debugLabel: string) {\n\t\tsuper();\n\t\tthis._debugLabel = debugLabel;\n\t\tthis._socket = new WebSocket(url);\n\t\tthis.traceSocketEvent(SocketDiagnosticsEventType.Created, { type: 'BrowserWebSocket', url });\n\t\tthis._fileReader = new FileReader();\n\t\tthis._queue = [];\n\t\tthis._isReading = false;\n\t\tthis._isClosed = false;\n\n\t\tthis._fileReader.onload = (event) => {\n\t\t\tthis._isReading = false;\n\t\t\tconst buff = (event.target).result;\n\n\t\t\tthis.traceSocketEvent(SocketDiagnosticsEventType.Read, buff);\n\t\t\tthis._onData.fire(buff);\n\n\t\t\tif (this._queue.length > 0) {\n\t\t\t\tenqueue(this._queue.shift()!);\n\t\t\t}\n\t\t};\n\n\t\tconst enqueue = (blob: Blob) => {\n\t\t\tif (this._isReading) {\n\t\t\t\tthis._queue.push(blob);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis._isReading = true;\n\t\t\tthis._fileReader.readAsArrayBuffer(blob);\n\t\t};\n\n\t\tthis._socketMessageListener = (ev: MessageEvent) => {\n\t\t\tconst blob = (ev.data);\n\t\t\tthis.traceSocketEvent(SocketDiagnosticsEventType.BrowserWebSocketBlobReceived, { type: blob.type, size: blob.size });\n\t\t\tenqueue(blob);\n\t\t};\n\t\tthis._socket.addEventListener('message', this._socketMessageListener);\n\n\t\tthis._register(dom.addDisposableListener(this._socket, 'open', (e) => {\n\t\t\tthis.traceSocketEvent(SocketDiagnosticsEventType.Open);\n\t\t\tthis._onOpen.fire();\n\t\t}));\n\n\t\t// WebSockets emit error events that do not contain any real information\n\t\t// Our only chance of getting to the root cause of an error is to\n\t\t// listen to the close event which gives out some real information:\n\t\t// - https://www.w3.org/TR/websockets/#closeevent\n\t\t// - https://tools.ietf.org/html/rfc6455#section-11.7\n\t\t//\n\t\t// But the error event is emitted before the close event, so we therefore\n\t\t// delay the error event processing in the hope of receiving a close event\n\t\t// with more information\n\n\t\tlet pendingErrorEvent: any | null = null;\n\n\t\tconst sendPendingErrorNow = () => {\n\t\t\tconst err = pendingErrorEvent;\n\t\t\tpendingErrorEvent = null;\n\t\t\tthis._onError.fire(err);\n\t\t};\n\n\t\tconst errorRunner = this._register(new RunOnceScheduler(sendPendingErrorNow, 0));\n\n\t\tconst sendErrorSoon = (err: any) => {\n\t\t\terrorRunner.cancel();\n\t\t\tpendingErrorEvent = err;\n\t\t\terrorRunner.schedule();\n\t\t};\n\n\t\tconst sendErrorNow = (err: any) => {\n\t\t\terrorRunner.cancel();\n\t\t\tpendingErrorEvent = err;\n\t\t\tsendPendingErrorNow();\n\t\t};\n\n\t\tthis._register(dom.addDisposableListener(this._socket, 'close', (e: CloseEvent) => {\n\t\t\tthis.traceSocketEvent(SocketDiagnosticsEventType.Close, { code: e.code, reason: e.reason, wasClean: e.wasClean });\n\n\t\t\tthis._isClosed = true;\n\n\t\t\tif (pendingErrorEvent) {\n\t\t\t\tif (!navigator.onLine) {\n\t\t\t\t\t// The browser is offline => this is a temporary error which might resolve itself\n\t\t\t\t\tsendErrorNow(new RemoteAuthorityResolverError('Browser is offline', RemoteAuthorityResolverErrorCode.TemporarilyNotAvailable, e));\n\t\t\t\t} else {\n\t\t\t\t\t// An error event is pending\n\t\t\t\t\t// The browser appears to be online...\n\t\t\t\t\tif (!e.wasClean) {\n\t\t\t\t\t\t// Let's be optimistic and hope that perhaps the server could not be reached or something\n\t\t\t\t\t\tsendErrorNow(new RemoteAuthorityResolverError(e.reason || `WebSocket close with status code ${e.code}`, RemoteAuthorityResolverErrorCode.TemporarilyNotAvailable, e));\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// this was a clean close => send existing error\n\t\t\t\t\t\terrorRunner.cancel();\n\t\t\t\t\t\tsendPendingErrorNow();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis._onClose.fire({ code: e.code, reason: e.reason, wasClean: e.wasClean, event: e });\n\t\t}));\n\n\t\tthis._register(dom.addDisposableListener(this._socket, 'error', (err) => {\n\t\t\tthis.traceSocketEvent(SocketDiagnosticsEventType.Error, { message: err?.message });\n\t\t\tsendErrorSoon(err);\n\t\t}));\n\t}\n\n\tsend(data: ArrayBuffer | ArrayBufferView): void {\n\t\tif (this._isClosed) {\n\t\t\t// Refuse to write data to closed WebSocket...\n\t\t\treturn;\n\t\t}\n\t\tthis.traceSocketEvent(SocketDiagnosticsEventType.Write, data);\n\t\tthis._socket.send(data);\n\t}\n\n\tclose(): void {\n\t\tthis._isClosed = true;\n\t\tthis.traceSocketEvent(SocketDiagnosticsEventType.Close);\n\t\tthis._socket.close();\n\t\tthis._socket.removeEventListener('message', this._socketMessageListener);\n\t\tthis.dispose();\n\t}\n}\n\nconst defaultWebSocketFactory = new class implements IWebSocketFactory {\n\tcreate(url: string, debugLabel: string): IWebSocket {\n\t\treturn new BrowserWebSocket(url, debugLabel);\n\t}\n};\n\nclass BrowserSocket implements ISocket {\n\n\tpublic readonly socket: IWebSocket;\n\tpublic readonly debugLabel: string;\n\n\tpublic traceSocketEvent(type: SocketDiagnosticsEventType, data?: VSBuffer | Uint8Array | ArrayBuffer | ArrayBufferView | any): void {\n\t\tif (typeof this.socket.traceSocketEvent === 'function') {\n\t\t\tthis.socket.traceSocketEvent(type, data);\n\t\t} else {\n\t\t\tSocketDiagnostics.traceSocketEvent(this.socket, this.debugLabel, type, data);\n\t\t}\n\t}\n\n\tconstructor(socket: IWebSocket, debugLabel: string) {\n\t\tthis.socket = socket;\n\t\tthis.debugLabel = debugLabel;\n\t}\n\n\tpublic dispose(): void {\n\t\tthis.socket.close();\n\t}\n\n\tpublic onData(listener: (e: VSBuffer) => void): IDisposable {\n\t\treturn this.socket.onData((data) => listener(VSBuffer.wrap(new Uint8Array(data))));\n\t}\n\n\tpublic onClose(listener: (e: SocketCloseEvent) => void): IDisposable {\n\t\tconst adapter = (e: IWebSocketCloseEvent | void) => {\n\t\t\tif (typeof e === 'undefined') {\n\t\t\t\tlistener(e);\n\t\t\t} else {\n\t\t\t\tlistener({\n\t\t\t\t\ttype: SocketCloseEventType.WebSocketCloseEvent,\n\t\t\t\t\tcode: e.code,\n\t\t\t\t\treason: e.reason,\n\t\t\t\t\twasClean: e.wasClean,\n\t\t\t\t\tevent: e.event\n\t\t\t\t});\n\t\t\t}\n\t\t};\n\t\treturn this.socket.onClose(adapter);\n\t}\n\n\tpublic onEnd(listener: () => void): IDisposable {\n\t\treturn Disposable.None;\n\t}\n\n\tpublic write(buffer: VSBuffer): void {\n\t\tthis.socket.send(buffer.buffer);\n\t}\n\n\tpublic end(): void {\n\t\tthis.socket.close();\n\t}\n\n\tpublic drain(): Promise {\n\t\treturn Promise.resolve();\n\t}\n}\n\n\nexport class BrowserSocketFactory implements ISocketFactory {\n\n\tprivate readonly _webSocketFactory: IWebSocketFactory;\n\n\tconstructor(webSocketFactory: IWebSocketFactory | null | undefined) {\n\t\tthis._webSocketFactory = webSocketFactory || defaultWebSocketFactory;\n\t}\n\n\tsupports(connectTo: WebSocketRemoteConnection): boolean {\n\t\treturn true;\n\t}\n\n\tconnect({ host, port }: WebSocketRemoteConnection, path: string, query: string, debugLabel: string): Promise {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst webSocketSchema = (/^https:/.test(mainWindow.location.href) ? 'wss' : 'ws');\n\t\t\tconst socket = this._webSocketFactory.create(`${webSocketSchema}://${(/:/.test(host) && !/\\[/.test(host)) ? `[${host}]` : host}:${port}${path}?${query}&skipWebSocketFrames=false`, debugLabel);\n\t\t\tconst errorListener = socket.onError(reject);\n\t\t\tsocket.onOpen(() => {\n\t\t\t\terrorListener.dispose();\n\t\t\t\tresolve(new BrowserSocket(socket, debugLabel));\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 { URI } from 'vs/base/common/uri';\nimport { IExtensionDescription } from 'vs/platform/extensions/common/extensions';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\n\nexport const IRemoteExtensionsScannerService = createDecorator('IRemoteExtensionsScannerService');\n\nexport const RemoteExtensionsScannerChannelName = 'remoteExtensionsScanner';\n\nexport interface IRemoteExtensionsScannerService {\n\treadonly _serviceBrand: undefined;\n\n\twhenExtensionsReady(): Promise;\n\tscanExtensions(): Promise;\n\tscanSingleExtension(extensionLocation: URI, isBuiltin: 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 { Schemas } from 'vs/base/common/network';\nimport { URI } from 'vs/base/common/uri';\n\nexport function getRemoteAuthority(uri: URI): string | undefined {\n\treturn uri.scheme === Schemas.vscodeRemote ? uri.authority : undefined;\n}\n\nexport function getRemoteName(authority: string): string;\nexport function getRemoteName(authority: undefined): undefined;\nexport function getRemoteName(authority: string | undefined): string | undefined;\nexport function getRemoteName(authority: string | undefined): string | undefined {\n\tif (!authority) {\n\t\treturn undefined;\n\t}\n\tconst pos = authority.indexOf('+');\n\tif (pos < 0) {\n\t\t// e.g. localhost:8000\n\t\treturn authority;\n\t}\n\treturn authority.substr(0, pos);\n}\n\n/**\n * The root path to use when accessing the remote server. The path contains the quality and commit of the current build.\n * @param product\n * @returns\n */\nexport function getRemoteServerRootPath(product: { quality?: string; commit?: string }): string {\n\treturn `/${product.quality ?? 'oss'}-${product.commit ?? 'dev'}`;\n}\n\nexport function parseAuthorityWithPort(authority: string): { host: string; port: number } {\n\tconst { host, port } = parseAuthority(authority);\n\tif (typeof port === 'undefined') {\n\t\tthrow new Error(`Invalid remote authority: ${authority}. It must either be a remote of form + or a remote host of form :.`);\n\t}\n\treturn { host, port };\n}\n\nexport function parseAuthorityWithOptionalPort(authority: string, defaultPort: number): { host: string; port: number } {\n\tlet { host, port } = parseAuthority(authority);\n\tif (typeof port === 'undefined') {\n\t\tport = defaultPort;\n\t}\n\treturn { host, port };\n}\n\nfunction parseAuthority(authority: string): { host: string; port: number | undefined } {\n\t// check for ipv6 with port\n\tconst m1 = authority.match(/^(\\[[0-9a-z:]+\\]):(\\d+)$/);\n\tif (m1) {\n\t\treturn { host: m1[1], port: parseInt(m1[2], 10) };\n\t}\n\n\t// check for ipv6 without port\n\tconst m2 = authority.match(/^(\\[[0-9a-z:]+\\])$/);\n\tif (m2) {\n\t\treturn { host: m2[1], port: undefined };\n\t}\n\n\t// anything with a trailing port\n\tconst m3 = authority.match(/(.*):(\\d+)$/);\n\tif (m3) {\n\t\treturn { host: m3[1], port: parseInt(m3[2], 10) };\n\t}\n\n\t// doesn't contain a port\n\treturn { host: authority, port: 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 Severity from 'vs/base/common/severity';\nimport * as strings from 'vs/base/common/strings';\nimport { URI } from 'vs/base/common/uri';\nimport { ILocalizedString } from 'vs/platform/action/common/action';\nimport { ExtensionKind } from 'vs/platform/environment/common/environment';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\nimport { getRemoteName } from 'vs/platform/remote/common/remoteHosts';\n\nexport const USER_MANIFEST_CACHE_FILE = 'extensions.user.cache';\nexport const BUILTIN_MANIFEST_CACHE_FILE = 'extensions.builtin.cache';\nexport const UNDEFINED_PUBLISHER = 'undefined_publisher';\n\nexport interface ICommand {\n\tcommand: string;\n\ttitle: string | ILocalizedString;\n\tcategory?: string | ILocalizedString;\n}\n\nexport interface IConfigurationProperty {\n\tdescription: string;\n\ttype: string | string[];\n\tdefault?: any;\n}\n\nexport interface IConfiguration {\n\tid?: string;\n\torder?: number;\n\ttitle?: string;\n\tproperties: { [key: string]: IConfigurationProperty };\n}\n\nexport interface IDebugger {\n\tlabel?: string;\n\ttype: string;\n\truntime?: string;\n}\n\nexport interface IGrammar {\n\tlanguage: string;\n}\n\nexport interface IJSONValidation {\n\tfileMatch: string | string[];\n\turl: string;\n}\n\nexport interface IKeyBinding {\n\tcommand: string;\n\tkey: string;\n\twhen?: string;\n\tmac?: string;\n\tlinux?: string;\n\twin?: string;\n}\n\nexport interface ILanguage {\n\tid: string;\n\textensions: string[];\n\taliases: string[];\n}\n\nexport interface IMenu {\n\tcommand: string;\n\talt?: string;\n\twhen?: string;\n\tgroup?: string;\n}\n\nexport interface ISnippet {\n\tlanguage: string;\n}\n\nexport interface ITheme {\n\tlabel: string;\n}\n\nexport interface IViewContainer {\n\tid: string;\n\ttitle: string;\n}\n\nexport interface IView {\n\tid: string;\n\tname: string;\n}\n\nexport interface IColor {\n\tid: string;\n\tdescription: string;\n\tdefaults: { light: string; dark: string; highContrast: string };\n}\n\ninterface IWebviewEditor {\n\treadonly viewType: string;\n\treadonly priority: string;\n\treadonly selector: readonly {\n\t\treadonly filenamePattern?: string;\n\t}[];\n}\n\nexport interface ICodeActionContributionAction {\n\treadonly kind: string;\n\treadonly title: string;\n\treadonly description?: string;\n}\n\nexport interface ICodeActionContribution {\n\treadonly languages: readonly string[];\n\treadonly actions: readonly ICodeActionContributionAction[];\n}\n\nexport interface IAuthenticationContribution {\n\treadonly id: string;\n\treadonly label: string;\n}\n\nexport interface IWalkthroughStep {\n\treadonly id: string;\n\treadonly title: string;\n\treadonly description: string | undefined;\n\treadonly media:\n\t| { image: string | { dark: string; light: string; hc: string }; altText: string; markdown?: never; svg?: never }\n\t| { markdown: string; image?: never; svg?: never }\n\t| { svg: string; altText: string; markdown?: never; image?: never };\n\treadonly completionEvents?: string[];\n\t/** @deprecated use `completionEvents: 'onCommand:...'` */\n\treadonly doneOn?: { command: string };\n\treadonly when?: string;\n}\n\nexport interface IWalkthrough {\n\treadonly id: string;\n\treadonly title: string;\n\treadonly icon?: string;\n\treadonly description: string;\n\treadonly steps: IWalkthroughStep[];\n\treadonly featuredFor: string[] | undefined;\n\treadonly when?: string;\n}\n\nexport interface IStartEntry {\n\treadonly title: string;\n\treadonly description: string;\n\treadonly command: string;\n\treadonly when?: string;\n\treadonly category: 'file' | 'folder' | 'notebook';\n}\n\nexport interface INotebookEntry {\n\treadonly type: string;\n\treadonly displayName: string;\n}\n\nexport interface INotebookRendererContribution {\n\treadonly id: string;\n\treadonly displayName: string;\n\treadonly mimeTypes: string[];\n}\n\nexport interface IDebugVisualizationContribution {\n\treadonly id: string;\n\treadonly when: string;\n}\n\nexport interface ITranslation {\n\tid: string;\n\tpath: string;\n}\n\nexport interface ILocalizationContribution {\n\tlanguageId: string;\n\tlanguageName?: string;\n\tlocalizedLanguageName?: string;\n\ttranslations: ITranslation[];\n\tminimalTranslations?: { [key: string]: string };\n}\n\nexport interface IExtensionContributions {\n\tcommands?: ICommand[];\n\tconfiguration?: IConfiguration | IConfiguration[];\n\tdebuggers?: IDebugger[];\n\tgrammars?: IGrammar[];\n\tjsonValidation?: IJSONValidation[];\n\tkeybindings?: IKeyBinding[];\n\tlanguages?: ILanguage[];\n\tmenus?: { [context: string]: IMenu[] };\n\tsnippets?: ISnippet[];\n\tthemes?: ITheme[];\n\ticonThemes?: ITheme[];\n\tproductIconThemes?: ITheme[];\n\tviewsContainers?: { [location: string]: IViewContainer[] };\n\tviews?: { [location: string]: IView[] };\n\tcolors?: IColor[];\n\tlocalizations?: ILocalizationContribution[];\n\treadonly customEditors?: readonly IWebviewEditor[];\n\treadonly codeActions?: readonly ICodeActionContribution[];\n\tauthentication?: IAuthenticationContribution[];\n\twalkthroughs?: IWalkthrough[];\n\tstartEntries?: IStartEntry[];\n\treadonly notebooks?: INotebookEntry[];\n\treadonly notebookRenderer?: INotebookRendererContribution[];\n\treadonly debugVisualizers?: IDebugVisualizationContribution[];\n}\n\nexport interface IExtensionCapabilities {\n\treadonly virtualWorkspaces?: ExtensionVirtualWorkspaceSupport;\n\treadonly untrustedWorkspaces?: ExtensionUntrustedWorkspaceSupport;\n}\n\n\nexport const ALL_EXTENSION_KINDS: readonly ExtensionKind[] = ['ui', 'workspace', 'web'];\n\nexport type LimitedWorkspaceSupportType = 'limited';\nexport type ExtensionUntrustedWorkspaceSupportType = boolean | LimitedWorkspaceSupportType;\nexport type ExtensionUntrustedWorkspaceSupport = { supported: true } | { supported: false; description: string } | { supported: LimitedWorkspaceSupportType; description: string; restrictedConfigurations?: string[] };\n\nexport type ExtensionVirtualWorkspaceSupportType = boolean | LimitedWorkspaceSupportType;\nexport type ExtensionVirtualWorkspaceSupport = boolean | { supported: true } | { supported: false | LimitedWorkspaceSupportType; description: string };\n\nexport function getWorkspaceSupportTypeMessage(supportType: ExtensionUntrustedWorkspaceSupport | ExtensionVirtualWorkspaceSupport | undefined): string | undefined {\n\tif (typeof supportType === 'object' && supportType !== null) {\n\t\tif (supportType.supported !== true) {\n\t\t\treturn supportType.description;\n\t\t}\n\t}\n\treturn undefined;\n}\n\n\nexport interface IExtensionIdentifier {\n\tid: string;\n\tuuid?: string;\n}\n\nexport const EXTENSION_CATEGORIES = [\n\t'Azure',\n\t'Data Science',\n\t'Debuggers',\n\t'Extension Packs',\n\t'Education',\n\t'Formatters',\n\t'Keymaps',\n\t'Language Packs',\n\t'Linters',\n\t'Machine Learning',\n\t'Notebooks',\n\t'Programming Languages',\n\t'SCM Providers',\n\t'Snippets',\n\t'Testing',\n\t'Themes',\n\t'Visualization',\n\t'Other',\n];\n\nexport interface IRelaxedExtensionManifest {\n\tname: string;\n\tdisplayName?: string;\n\tpublisher: string;\n\tversion: string;\n\tengines: { readonly vscode: string };\n\tdescription?: string;\n\tmain?: string;\n\tbrowser?: string;\n\tpreview?: boolean;\n\t// For now this only supports pointing to l10n bundle files\n\t// but it will be used for package.l10n.json files in the future\n\tl10n?: string;\n\ticon?: string;\n\tcategories?: string[];\n\tkeywords?: string[];\n\tactivationEvents?: string[];\n\textensionDependencies?: string[];\n\textensionPack?: string[];\n\textensionKind?: ExtensionKind | ExtensionKind[];\n\tcontributes?: IExtensionContributions;\n\trepository?: { url: string };\n\tbugs?: { url: string };\n\tenabledApiProposals?: readonly string[];\n\tapi?: string;\n\tscripts?: { [key: string]: string };\n\tcapabilities?: IExtensionCapabilities;\n}\n\nexport type IExtensionManifest = Readonly;\n\nexport const enum ExtensionType {\n\tSystem,\n\tUser\n}\n\nexport const enum TargetPlatform {\n\tWIN32_X64 = 'win32-x64',\n\tWIN32_ARM64 = 'win32-arm64',\n\n\tLINUX_X64 = 'linux-x64',\n\tLINUX_ARM64 = 'linux-arm64',\n\tLINUX_ARMHF = 'linux-armhf',\n\n\tALPINE_X64 = 'alpine-x64',\n\tALPINE_ARM64 = 'alpine-arm64',\n\n\tDARWIN_X64 = 'darwin-x64',\n\tDARWIN_ARM64 = 'darwin-arm64',\n\n\tWEB = 'web',\n\n\tUNIVERSAL = 'universal',\n\tUNKNOWN = 'unknown',\n\tUNDEFINED = 'undefined',\n}\n\nexport interface IExtension {\n\treadonly type: ExtensionType;\n\treadonly isBuiltin: boolean;\n\treadonly identifier: IExtensionIdentifier;\n\treadonly manifest: IExtensionManifest;\n\treadonly location: URI;\n\treadonly targetPlatform: TargetPlatform;\n\treadonly readmeUrl?: URI;\n\treadonly changelogUrl?: URI;\n\treadonly isValid: boolean;\n\treadonly validations: readonly [Severity, string][];\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\tpublic static equals(a: ExtensionIdentifier | string | null | undefined, b: ExtensionIdentifier | string | null | undefined) {\n\t\tif (typeof a === 'undefined' || a === null) {\n\t\t\treturn (typeof b === 'undefined' || b === null);\n\t\t}\n\t\tif (typeof b === 'undefined' || b === null) {\n\t\t\treturn false;\n\t\t}\n\t\tif (typeof a === 'string' || typeof b === 'string') {\n\t\t\t// At least one of the arguments is an extension id in string form,\n\t\t\t// so we have to use the string comparison which ignores case.\n\t\t\tconst aValue = (typeof a === 'string' ? a : a.value);\n\t\t\tconst bValue = (typeof b === 'string' ? b : b.value);\n\t\t\treturn strings.equalsIgnoreCase(aValue, bValue);\n\t\t}\n\n\t\t// Now we know both arguments are ExtensionIdentifier\n\t\treturn (a._lower === b._lower);\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\tpublic get size(): number {\n\t\treturn this._set.size;\n\t}\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 delete(extensionId: ExtensionIdentifier): boolean {\n\t\treturn this._set.delete(ExtensionIdentifier.toKey(extensionId));\n\t}\n\n\tpublic has(id: ExtensionIdentifier | string): boolean {\n\t\treturn this._set.has(ExtensionIdentifier.toKey(id));\n\t}\n}\n\nexport class ExtensionIdentifierMap {\n\n\tprivate readonly _map = new Map();\n\n\tpublic clear(): void {\n\t\tthis._map.clear();\n\t}\n\n\tpublic delete(id: ExtensionIdentifier | string): void {\n\t\tthis._map.delete(ExtensionIdentifier.toKey(id));\n\t}\n\n\tpublic get(id: ExtensionIdentifier | string): T | undefined {\n\t\treturn this._map.get(ExtensionIdentifier.toKey(id));\n\t}\n\n\tpublic has(id: ExtensionIdentifier | string): boolean {\n\t\treturn this._map.has(ExtensionIdentifier.toKey(id));\n\t}\n\n\tpublic set(id: ExtensionIdentifier | string, value: T): void {\n\t\tthis._map.set(ExtensionIdentifier.toKey(id), value);\n\t}\n\n\tpublic values(): IterableIterator {\n\t\treturn this._map.values();\n\t}\n\n\tforEach(callbackfn: (value: T, key: string, map: Map) => void): void {\n\t\tthis._map.forEach(callbackfn);\n\t}\n\n\t[Symbol.iterator](): IterableIterator<[string, T]> {\n\t\treturn this._map[Symbol.iterator]();\n\t}\n}\n\nexport interface IRelaxedExtensionDescription extends IRelaxedExtensionManifest {\n\tid?: string;\n\tidentifier: ExtensionIdentifier;\n\tuuid?: string;\n\ttargetPlatform: TargetPlatform;\n\tisBuiltin: boolean;\n\tisUserBuiltin: boolean;\n\tisUnderDevelopment: boolean;\n\textensionLocation: URI;\n}\n\nexport type IExtensionDescription = Readonly;\n\nexport function isApplicationScopedExtension(manifest: IExtensionManifest): boolean {\n\treturn isLanguagePackExtension(manifest);\n}\n\nexport function isLanguagePackExtension(manifest: IExtensionManifest): boolean {\n\treturn manifest.contributes && manifest.contributes.localizations ? manifest.contributes.localizations.length > 0 : false;\n}\n\nexport function isAuthenticationProviderExtension(manifest: IExtensionManifest): boolean {\n\treturn manifest.contributes && manifest.contributes.authentication ? manifest.contributes.authentication.length > 0 : false;\n}\n\nexport function isResolverExtension(manifest: IExtensionManifest, remoteAuthority: string | undefined): boolean {\n\tif (remoteAuthority) {\n\t\tconst activationEvent = `onResolveRemoteAuthority:${getRemoteName(remoteAuthority)}`;\n\t\treturn !!manifest.activationEvents?.includes(activationEvent);\n\t}\n\treturn false;\n}\n\nexport const IBuiltinExtensionsScannerService = createDecorator('IBuiltinExtensionsScannerService');\nexport interface IBuiltinExtensionsScannerService {\n\treadonly _serviceBrand: undefined;\n\tscanBuiltinExtensions(): 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 { onUnexpectedError } from 'vs/base/common/errors';\nimport { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';\n\nexport interface IActivationEventsGenerator {\n\t(contributions: T[], result: { push(item: string): void }): void;\n}\n\nexport class ImplicitActivationEventsImpl {\n\n\tprivate readonly _generators = new Map>();\n\tprivate readonly _cache = new WeakMap();\n\n\tpublic register(extensionPointName: string, generator: IActivationEventsGenerator): void {\n\t\tthis._generators.set(extensionPointName, generator);\n\t}\n\n\t/**\n\t * This can run correctly only on the renderer process because that is the only place\n\t * where all extension points and all implicit activation events generators are known.\n\t */\n\tpublic readActivationEvents(extensionDescription: IExtensionDescription): string[] {\n\t\tif (!this._cache.has(extensionDescription)) {\n\t\t\tthis._cache.set(extensionDescription, this._readActivationEvents(extensionDescription));\n\t\t}\n\t\treturn this._cache.get(extensionDescription)!;\n\t}\n\n\t/**\n\t * This can run correctly only on the renderer process because that is the only place\n\t * where all extension points and all implicit activation events generators are known.\n\t */\n\tpublic createActivationEventsMap(extensionDescriptions: IExtensionDescription[]): { [extensionId: string]: string[] } {\n\t\tconst result: { [extensionId: string]: string[] } = Object.create(null);\n\t\tfor (const extensionDescription of extensionDescriptions) {\n\t\t\tconst activationEvents = this.readActivationEvents(extensionDescription);\n\t\t\tif (activationEvents.length > 0) {\n\t\t\t\tresult[ExtensionIdentifier.toKey(extensionDescription.identifier)] = activationEvents;\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate _readActivationEvents(desc: IExtensionDescription): string[] {\n\t\tif (typeof desc.main === 'undefined' && typeof desc.browser === 'undefined') {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst activationEvents: string[] = (Array.isArray(desc.activationEvents) ? desc.activationEvents.slice(0) : []);\n\n\t\tfor (let i = 0; i < activationEvents.length; i++) {\n\t\t\t// TODO@joao: there's no easy way to contribute this\n\t\t\tif (activationEvents[i] === 'onUri') {\n\t\t\t\tactivationEvents[i] = `onUri:${ExtensionIdentifier.toKey(desc.identifier)}`;\n\t\t\t}\n\t\t}\n\n\t\tif (!desc.contributes) {\n\t\t\t// no implicit activation events\n\t\t\treturn activationEvents;\n\t\t}\n\n\t\tfor (const extPointName in desc.contributes) {\n\t\t\tconst generator = this._generators.get(extPointName);\n\t\t\tif (!generator) {\n\t\t\t\t// There's no generator for this extension point\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst contrib = (desc.contributes as any)[extPointName];\n\t\t\tconst contribArr = Array.isArray(contrib) ? contrib : [contrib];\n\t\t\ttry {\n\t\t\t\tgenerator(contribArr, activationEvents);\n\t\t\t} catch (err) {\n\t\t\t\tonUnexpectedError(err);\n\t\t\t}\n\t\t}\n\n\t\treturn activationEvents;\n\t}\n}\n\nexport const ImplicitActivationEvents: ImplicitActivationEventsImpl = new ImplicitActivationEventsImpl();\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { DeferredPromise } from 'vs/base/common/async';\nimport * as errors from 'vs/base/common/errors';\nimport { Emitter } from 'vs/base/common/event';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { RemoteAuthorities } from 'vs/base/common/network';\nimport * as performance from 'vs/base/common/performance';\nimport { StopWatch } from 'vs/base/common/stopwatch';\nimport { URI } from 'vs/base/common/uri';\nimport { ILogService } from 'vs/platform/log/common/log';\nimport { IProductService } from 'vs/platform/product/common/productService';\nimport { IRemoteAuthorityResolverService, IRemoteConnectionData, RemoteConnectionType, ResolvedAuthority, ResolvedOptions, ResolverResult, WebSocketRemoteConnection, getRemoteAuthorityPrefix } from 'vs/platform/remote/common/remoteAuthorityResolver';\nimport { getRemoteServerRootPath, parseAuthorityWithOptionalPort } from 'vs/platform/remote/common/remoteHosts';\n\nexport class RemoteAuthorityResolverService extends Disposable implements IRemoteAuthorityResolverService {\n\n\tdeclare readonly _serviceBrand: undefined;\n\n\tprivate readonly _onDidChangeConnectionData = this._register(new Emitter());\n\tpublic readonly onDidChangeConnectionData = this._onDidChangeConnectionData.event;\n\n\tprivate readonly _resolveAuthorityRequests = new Map>();\n\tprivate readonly _cache = new Map();\n\tprivate readonly _connectionToken: Promise | string | undefined;\n\tprivate readonly _connectionTokens: Map;\n\tprivate readonly _isWorkbenchOptionsBasedResolution: boolean;\n\n\tconstructor(\n\t\tisWorkbenchOptionsBasedResolution: boolean,\n\t\tconnectionToken: Promise | string | undefined,\n\t\tresourceUriProvider: ((uri: URI) => URI) | undefined,\n\t\t@IProductService productService: IProductService,\n\t\t@ILogService private readonly _logService: ILogService,\n\t) {\n\t\tsuper();\n\t\tthis._connectionToken = connectionToken;\n\t\tthis._connectionTokens = new Map();\n\t\tthis._isWorkbenchOptionsBasedResolution = isWorkbenchOptionsBasedResolution;\n\t\tif (resourceUriProvider) {\n\t\t\tRemoteAuthorities.setDelegate(resourceUriProvider);\n\t\t}\n\t\tRemoteAuthorities.setServerRootPath(getRemoteServerRootPath(productService));\n\t}\n\n\tasync resolveAuthority(authority: string): Promise {\n\t\tlet result = this._resolveAuthorityRequests.get(authority);\n\t\tif (!result) {\n\t\t\tresult = new DeferredPromise();\n\t\t\tthis._resolveAuthorityRequests.set(authority, result);\n\t\t\tif (this._isWorkbenchOptionsBasedResolution) {\n\t\t\t\tthis._doResolveAuthority(authority).then(v => result!.complete(v), (err) => result!.error(err));\n\t\t\t}\n\t\t}\n\n\t\treturn result.p;\n\t}\n\n\tasync getCanonicalURI(uri: URI): Promise {\n\t\t// todo@connor4312 make this work for web\n\t\treturn uri;\n\t}\n\n\tgetConnectionData(authority: string): IRemoteConnectionData | null {\n\t\tif (!this._cache.has(authority)) {\n\t\t\treturn null;\n\t\t}\n\t\tconst resolverResult = this._cache.get(authority)!;\n\t\tconst connectionToken = this._connectionTokens.get(authority) || resolverResult.authority.connectionToken;\n\t\treturn {\n\t\t\tconnectTo: resolverResult.authority.connectTo,\n\t\t\tconnectionToken: connectionToken\n\t\t};\n\t}\n\n\tprivate async _doResolveAuthority(authority: string): Promise {\n\t\tconst authorityPrefix = getRemoteAuthorityPrefix(authority);\n\t\tconst sw = StopWatch.create(false);\n\t\tthis._logService.info(`Resolving connection token (${authorityPrefix})...`);\n\t\tperformance.mark(`code/willResolveConnectionToken/${authorityPrefix}`);\n\t\tconst connectionToken = await Promise.resolve(this._connectionTokens.get(authority) || this._connectionToken);\n\t\tperformance.mark(`code/didResolveConnectionToken/${authorityPrefix}`);\n\t\tthis._logService.info(`Resolved connection token (${authorityPrefix}) after ${sw.elapsed()} ms`);\n\t\tconst defaultPort = (/^https:/.test(mainWindow.location.href) ? 443 : 80);\n\t\tconst { host, port } = parseAuthorityWithOptionalPort(authority, defaultPort);\n\t\tconst result: ResolverResult = { authority: { authority, connectTo: new WebSocketRemoteConnection(host, port), connectionToken } };\n\t\tRemoteAuthorities.set(authority, host, port);\n\t\tthis._cache.set(authority, result);\n\t\tthis._onDidChangeConnectionData.fire();\n\t\treturn result;\n\t}\n\n\n\t_clearResolvedAuthority(authority: string): void {\n\t\tif (this._resolveAuthorityRequests.has(authority)) {\n\t\t\tthis._resolveAuthorityRequests.get(authority)!.cancel();\n\t\t\tthis._resolveAuthorityRequests.delete(authority);\n\t\t}\n\t}\n\n\t_setResolvedAuthority(resolvedAuthority: ResolvedAuthority, options?: ResolvedOptions): void {\n\t\tif (this._resolveAuthorityRequests.has(resolvedAuthority.authority)) {\n\t\t\tconst request = this._resolveAuthorityRequests.get(resolvedAuthority.authority)!;\n\t\t\t// For non-websocket types, it's expected the embedder passes a `remoteResourceProvider`\n\t\t\t// which is wrapped to a `IResourceUriProvider` and is not handled here.\n\t\t\tif (resolvedAuthority.connectTo.type === RemoteConnectionType.WebSocket) {\n\t\t\t\tRemoteAuthorities.set(resolvedAuthority.authority, resolvedAuthority.connectTo.host, resolvedAuthority.connectTo.port);\n\t\t\t}\n\t\t\tif (resolvedAuthority.connectionToken) {\n\t\t\t\tRemoteAuthorities.setConnectionToken(resolvedAuthority.authority, resolvedAuthority.connectionToken);\n\t\t\t}\n\t\t\trequest.complete({ authority: resolvedAuthority, options });\n\t\t\tthis._onDidChangeConnectionData.fire();\n\t\t}\n\t}\n\n\t_setResolvedAuthorityError(authority: string, err: any): void {\n\t\tif (this._resolveAuthorityRequests.has(authority)) {\n\t\t\tconst request = this._resolveAuthorityRequests.get(authority)!;\n\t\t\t// Avoid that this error makes it to telemetry\n\t\t\trequest.error(errors.ErrorNoTelemetry.fromError(err));\n\t\t}\n\t}\n\n\t_setAuthorityConnectionToken(authority: string, connectionToken: string): void {\n\t\tthis._connectionTokens.set(authority, connectionToken);\n\t\tRemoteAuthorities.setConnectionToken(authority, connectionToken);\n\t\tthis._onDidChangeConnectionData.fire();\n\t}\n\n\t_setCanonicalURIProvider(provider: (uri: URI) => Promise): 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 { CancelablePromise, createCancelablePromise, promiseWithResolvers } from 'vs/base/common/async';\nimport { VSBuffer } from 'vs/base/common/buffer';\nimport { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';\nimport { isCancellationError, onUnexpectedError } from 'vs/base/common/errors';\nimport { Emitter } from 'vs/base/common/event';\nimport { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';\nimport * as performance from 'vs/base/common/performance';\nimport { StopWatch } from 'vs/base/common/stopwatch';\nimport { generateUuid } from 'vs/base/common/uuid';\nimport { IIPCLogger } from 'vs/base/parts/ipc/common/ipc';\nimport { Client, ISocket, PersistentProtocol, SocketCloseEventType } from 'vs/base/parts/ipc/common/ipc.net';\nimport { ILogService } from 'vs/platform/log/common/log';\nimport { RemoteAgentConnectionContext } from 'vs/platform/remote/common/remoteAgentEnvironment';\nimport { RemoteAuthorityResolverError, RemoteConnection } from 'vs/platform/remote/common/remoteAuthorityResolver';\nimport { getRemoteServerRootPath } from 'vs/platform/remote/common/remoteHosts';\nimport { IRemoteSocketFactoryService } from 'vs/platform/remote/common/remoteSocketFactoryService';\nimport { ISignService } from 'vs/platform/sign/common/sign';\n\nconst RECONNECT_TIMEOUT = 30 * 1000 /* 30s */;\n\nexport const enum ConnectionType {\n\tManagement = 1,\n\tExtensionHost = 2,\n\tTunnel = 3,\n}\n\nfunction connectionTypeToString(connectionType: ConnectionType): string {\n\tswitch (connectionType) {\n\t\tcase ConnectionType.Management:\n\t\t\treturn 'Management';\n\t\tcase ConnectionType.ExtensionHost:\n\t\t\treturn 'ExtensionHost';\n\t\tcase ConnectionType.Tunnel:\n\t\t\treturn 'Tunnel';\n\t}\n}\n\nexport interface AuthRequest {\n\ttype: 'auth';\n\tauth: string;\n\tdata: string;\n}\n\nexport interface SignRequest {\n\ttype: 'sign';\n\tdata: string;\n\tsignedData: string;\n}\n\nexport interface ConnectionTypeRequest {\n\ttype: 'connectionType';\n\tcommit?: string;\n\tsignedData: string;\n\tdesiredConnectionType?: ConnectionType;\n\targs?: any;\n}\n\nexport interface ErrorMessage {\n\ttype: 'error';\n\treason: string;\n}\n\nexport interface OKMessage {\n\ttype: 'ok';\n}\n\nexport type HandshakeMessage = AuthRequest | SignRequest | ConnectionTypeRequest | ErrorMessage | OKMessage;\n\n\ninterface ISimpleConnectionOptions {\n\tcommit: string | undefined;\n\tquality: string | undefined;\n\tconnectTo: T;\n\tconnectionToken: string | undefined;\n\treconnectionToken: string;\n\treconnectionProtocol: PersistentProtocol | null;\n\tremoteSocketFactoryService: IRemoteSocketFactoryService;\n\tsignService: ISignService;\n\tlogService: ILogService;\n}\n\nfunction createTimeoutCancellation(millis: number): CancellationToken {\n\tconst source = new CancellationTokenSource();\n\tsetTimeout(() => source.cancel(), millis);\n\treturn source.token;\n}\n\nfunction combineTimeoutCancellation(a: CancellationToken, b: CancellationToken): CancellationToken {\n\tif (a.isCancellationRequested || b.isCancellationRequested) {\n\t\treturn CancellationToken.Cancelled;\n\t}\n\tconst source = new CancellationTokenSource();\n\ta.onCancellationRequested(() => source.cancel());\n\tb.onCancellationRequested(() => source.cancel());\n\treturn source.token;\n}\n\nclass PromiseWithTimeout {\n\n\tprivate _state: 'pending' | 'resolved' | 'rejected' | 'timedout';\n\tprivate readonly _disposables: DisposableStore;\n\tpublic readonly promise: Promise;\n\tprivate readonly _resolvePromise: (value: T) => void;\n\tprivate readonly _rejectPromise: (err: any) => void;\n\n\tpublic get didTimeout(): boolean {\n\t\treturn (this._state === 'timedout');\n\t}\n\n\tconstructor(timeoutCancellationToken: CancellationToken) {\n\t\tthis._state = 'pending';\n\t\tthis._disposables = new DisposableStore();\n\n\t\t({ promise: this.promise, resolve: this._resolvePromise, reject: this._rejectPromise } = promiseWithResolvers());\n\n\t\tif (timeoutCancellationToken.isCancellationRequested) {\n\t\t\tthis._timeout();\n\t\t} else {\n\t\t\tthis._disposables.add(timeoutCancellationToken.onCancellationRequested(() => this._timeout()));\n\t\t}\n\t}\n\n\tpublic registerDisposable(disposable: IDisposable): void {\n\t\tif (this._state === 'pending') {\n\t\t\tthis._disposables.add(disposable);\n\t\t} else {\n\t\t\tdisposable.dispose();\n\t\t}\n\t}\n\n\tprivate _timeout(): void {\n\t\tif (this._state !== 'pending') {\n\t\t\treturn;\n\t\t}\n\t\tthis._disposables.dispose();\n\t\tthis._state = 'timedout';\n\t\tthis._rejectPromise(this._createTimeoutError());\n\t}\n\n\tprivate _createTimeoutError(): Error {\n\t\tconst err: any = new Error('Time limit reached');\n\t\terr.code = 'ETIMEDOUT';\n\t\terr.syscall = 'connect';\n\t\treturn err;\n\t}\n\n\tpublic resolve(value: T): void {\n\t\tif (this._state !== 'pending') {\n\t\t\treturn;\n\t\t}\n\t\tthis._disposables.dispose();\n\t\tthis._state = 'resolved';\n\t\tthis._resolvePromise(value);\n\t}\n\n\tpublic reject(err: any): void {\n\t\tif (this._state !== 'pending') {\n\t\t\treturn;\n\t\t}\n\t\tthis._disposables.dispose();\n\t\tthis._state = 'rejected';\n\t\tthis._rejectPromise(err);\n\t}\n}\n\nfunction readOneControlMessage(protocol: PersistentProtocol, timeoutCancellationToken: CancellationToken): Promise {\n\tconst result = new PromiseWithTimeout(timeoutCancellationToken);\n\tresult.registerDisposable(protocol.onControlMessage(raw => {\n\t\tconst msg: T = JSON.parse(raw.toString());\n\t\tconst error = getErrorFromMessage(msg);\n\t\tif (error) {\n\t\t\tresult.reject(error);\n\t\t} else {\n\t\t\tresult.resolve(msg);\n\t\t}\n\t}));\n\treturn result.promise;\n}\n\nfunction createSocket(logService: ILogService, remoteSocketFactoryService: IRemoteSocketFactoryService, connectTo: T, path: string, query: string, debugConnectionType: string, debugLabel: string, timeoutCancellationToken: CancellationToken): Promise {\n\tconst result = new PromiseWithTimeout(timeoutCancellationToken);\n\tconst sw = StopWatch.create(false);\n\tlogService.info(`Creating a socket (${debugLabel})...`);\n\tperformance.mark(`code/willCreateSocket/${debugConnectionType}`);\n\n\tremoteSocketFactoryService.connect(connectTo, path, query, debugLabel).then((socket) => {\n\t\tif (result.didTimeout) {\n\t\t\tperformance.mark(`code/didCreateSocketError/${debugConnectionType}`);\n\t\t\tlogService.info(`Creating a socket (${debugLabel}) finished after ${sw.elapsed()} ms, but this is too late and has timed out already.`);\n\t\t\tsocket?.dispose();\n\t\t} else {\n\t\t\tperformance.mark(`code/didCreateSocketOK/${debugConnectionType}`);\n\t\t\tlogService.info(`Creating a socket (${debugLabel}) was successful after ${sw.elapsed()} ms.`);\n\t\t\tresult.resolve(socket);\n\t\t}\n\t}, (err) => {\n\t\tperformance.mark(`code/didCreateSocketError/${debugConnectionType}`);\n\t\tlogService.info(`Creating a socket (${debugLabel}) returned an error after ${sw.elapsed()} ms.`);\n\t\tlogService.error(err);\n\t\tresult.reject(err);\n\t});\n\n\treturn result.promise;\n}\n\nfunction raceWithTimeoutCancellation(promise: Promise, timeoutCancellationToken: CancellationToken): Promise {\n\tconst result = new PromiseWithTimeout(timeoutCancellationToken);\n\tpromise.then(\n\t\t(res) => {\n\t\t\tif (!result.didTimeout) {\n\t\t\t\tresult.resolve(res);\n\t\t\t}\n\t\t},\n\t\t(err) => {\n\t\t\tif (!result.didTimeout) {\n\t\t\t\tresult.reject(err);\n\t\t\t}\n\t\t}\n\t);\n\treturn result.promise;\n}\n\nasync function connectToRemoteExtensionHostAgent(options: ISimpleConnectionOptions, connectionType: ConnectionType, args: any | undefined, timeoutCancellationToken: CancellationToken): Promise<{ protocol: PersistentProtocol; ownsProtocol: boolean }> {\n\tconst logPrefix = connectLogPrefix(options, connectionType);\n\n\toptions.logService.trace(`${logPrefix} 1/6. invoking socketFactory.connect().`);\n\n\tlet socket: ISocket;\n\ttry {\n\t\tsocket = await createSocket(options.logService, options.remoteSocketFactoryService, options.connectTo, getRemoteServerRootPath(options), `reconnectionToken=${options.reconnectionToken}&reconnection=${options.reconnectionProtocol ? 'true' : 'false'}`, connectionTypeToString(connectionType), `renderer-${connectionTypeToString(connectionType)}-${options.reconnectionToken}`, timeoutCancellationToken);\n\t} catch (error) {\n\t\toptions.logService.error(`${logPrefix} socketFactory.connect() failed or timed out. Error:`);\n\t\toptions.logService.error(error);\n\t\tthrow error;\n\t}\n\n\toptions.logService.trace(`${logPrefix} 2/6. socketFactory.connect() was successful.`);\n\n\tlet protocol: PersistentProtocol;\n\tlet ownsProtocol: boolean;\n\tif (options.reconnectionProtocol) {\n\t\toptions.reconnectionProtocol.beginAcceptReconnection(socket, null);\n\t\tprotocol = options.reconnectionProtocol;\n\t\townsProtocol = false;\n\t} else {\n\t\tprotocol = new PersistentProtocol({ socket });\n\t\townsProtocol = true;\n\t}\n\n\toptions.logService.trace(`${logPrefix} 3/6. sending AuthRequest control message.`);\n\tconst message = await raceWithTimeoutCancellation(options.signService.createNewMessage(generateUuid()), timeoutCancellationToken);\n\n\tconst authRequest: AuthRequest = {\n\t\ttype: 'auth',\n\t\tauth: options.connectionToken || '00000000000000000000',\n\t\tdata: message.data\n\t};\n\tprotocol.sendControl(VSBuffer.fromString(JSON.stringify(authRequest)));\n\n\ttry {\n\t\tconst msg = await readOneControlMessage(protocol, combineTimeoutCancellation(timeoutCancellationToken, createTimeoutCancellation(10000)));\n\n\t\tif (msg.type !== 'sign' || typeof msg.data !== 'string') {\n\t\t\tconst error: any = new Error('Unexpected handshake message');\n\t\t\terror.code = 'VSCODE_CONNECTION_ERROR';\n\t\t\tthrow error;\n\t\t}\n\n\t\toptions.logService.trace(`${logPrefix} 4/6. received SignRequest control message.`);\n\n\t\tconst isValid = await raceWithTimeoutCancellation(options.signService.validate(message, msg.signedData), timeoutCancellationToken);\n\t\tif (!isValid) {\n\t\t\tconst error: any = new Error('Refused to connect to unsupported server');\n\t\t\terror.code = 'VSCODE_CONNECTION_ERROR';\n\t\t\tthrow error;\n\t\t}\n\n\t\tconst signed = await raceWithTimeoutCancellation(options.signService.sign(msg.data), timeoutCancellationToken);\n\t\tconst connTypeRequest: ConnectionTypeRequest = {\n\t\t\ttype: 'connectionType',\n\t\t\tcommit: options.commit,\n\t\t\tsignedData: signed,\n\t\t\tdesiredConnectionType: connectionType\n\t\t};\n\t\tif (args) {\n\t\t\tconnTypeRequest.args = args;\n\t\t}\n\n\t\toptions.logService.trace(`${logPrefix} 5/6. sending ConnectionTypeRequest control message.`);\n\t\tprotocol.sendControl(VSBuffer.fromString(JSON.stringify(connTypeRequest)));\n\n\t\treturn { protocol, ownsProtocol };\n\n\t} catch (error) {\n\t\tif (error && error.code === 'ETIMEDOUT') {\n\t\t\toptions.logService.error(`${logPrefix} the handshake timed out. Error:`);\n\t\t\toptions.logService.error(error);\n\t\t}\n\t\tif (error && error.code === 'VSCODE_CONNECTION_ERROR') {\n\t\t\toptions.logService.error(`${logPrefix} received error control message when negotiating connection. Error:`);\n\t\t\toptions.logService.error(error);\n\t\t}\n\t\tif (ownsProtocol) {\n\t\t\tsafeDisposeProtocolAndSocket(protocol);\n\t\t}\n\t\tthrow error;\n\t}\n}\n\ninterface IManagementConnectionResult {\n\tprotocol: PersistentProtocol;\n}\n\nasync function connectToRemoteExtensionHostAgentAndReadOneMessage(options: ISimpleConnectionOptions, connectionType: ConnectionType, args: any | undefined, timeoutCancellationToken: CancellationToken): Promise<{ protocol: PersistentProtocol; firstMessage: T }> {\n\tconst startTime = Date.now();\n\tconst logPrefix = connectLogPrefix(options, connectionType);\n\tconst { protocol, ownsProtocol } = await connectToRemoteExtensionHostAgent(options, connectionType, args, timeoutCancellationToken);\n\tconst result = new PromiseWithTimeout<{ protocol: PersistentProtocol; firstMessage: T }>(timeoutCancellationToken);\n\tresult.registerDisposable(protocol.onControlMessage(raw => {\n\t\tconst msg: T = JSON.parse(raw.toString());\n\t\tconst error = getErrorFromMessage(msg);\n\t\tif (error) {\n\t\t\toptions.logService.error(`${logPrefix} received error control message when negotiating connection. Error:`);\n\t\t\toptions.logService.error(error);\n\t\t\tif (ownsProtocol) {\n\t\t\t\tsafeDisposeProtocolAndSocket(protocol);\n\t\t\t}\n\t\t\tresult.reject(error);\n\t\t} else {\n\t\t\toptions.reconnectionProtocol?.endAcceptReconnection();\n\t\t\toptions.logService.trace(`${logPrefix} 6/6. handshake finished, connection is up and running after ${logElapsed(startTime)}!`);\n\t\t\tresult.resolve({ protocol, firstMessage: msg });\n\t\t}\n\t}));\n\treturn result.promise;\n}\n\nasync function doConnectRemoteAgentManagement(options: ISimpleConnectionOptions, timeoutCancellationToken: CancellationToken): Promise {\n\tconst { protocol } = await connectToRemoteExtensionHostAgentAndReadOneMessage(options, ConnectionType.Management, undefined, timeoutCancellationToken);\n\treturn { protocol };\n}\n\nexport interface IRemoteExtensionHostStartParams {\n\tlanguage: string;\n\tdebugId?: string;\n\tbreak?: boolean;\n\tport?: number | null;\n\tenv?: { [key: string]: string | null };\n}\n\ninterface IExtensionHostConnectionResult {\n\tprotocol: PersistentProtocol;\n\tdebugPort?: number;\n}\n\nasync function doConnectRemoteAgentExtensionHost(options: ISimpleConnectionOptions, startArguments: IRemoteExtensionHostStartParams, timeoutCancellationToken: CancellationToken): Promise {\n\tconst { protocol, firstMessage } = await connectToRemoteExtensionHostAgentAndReadOneMessage<{ debugPort?: number }>(options, ConnectionType.ExtensionHost, startArguments, timeoutCancellationToken);\n\tconst debugPort = firstMessage && firstMessage.debugPort;\n\treturn { protocol, debugPort };\n}\n\nexport interface ITunnelConnectionStartParams {\n\thost: string;\n\tport: number;\n}\n\nasync function doConnectRemoteAgentTunnel(options: ISimpleConnectionOptions, startParams: ITunnelConnectionStartParams, timeoutCancellationToken: CancellationToken): Promise {\n\tconst startTime = Date.now();\n\tconst logPrefix = connectLogPrefix(options, ConnectionType.Tunnel);\n\tconst { protocol } = await connectToRemoteExtensionHostAgent(options, ConnectionType.Tunnel, startParams, timeoutCancellationToken);\n\toptions.logService.trace(`${logPrefix} 6/6. handshake finished, connection is up and running after ${logElapsed(startTime)}!`);\n\treturn protocol;\n}\n\nexport interface IConnectionOptions {\n\tcommit: string | undefined;\n\tquality: string | undefined;\n\taddressProvider: IAddressProvider;\n\tremoteSocketFactoryService: IRemoteSocketFactoryService;\n\tsignService: ISignService;\n\tlogService: ILogService;\n\tipcLogger: IIPCLogger | null;\n}\n\nasync function resolveConnectionOptions(options: IConnectionOptions, reconnectionToken: string, reconnectionProtocol: PersistentProtocol | null): Promise> {\n\tconst { connectTo, connectionToken } = await options.addressProvider.getAddress();\n\treturn {\n\t\tcommit: options.commit,\n\t\tquality: options.quality,\n\t\tconnectTo,\n\t\tconnectionToken: connectionToken,\n\t\treconnectionToken: reconnectionToken,\n\t\treconnectionProtocol: reconnectionProtocol,\n\t\tremoteSocketFactoryService: options.remoteSocketFactoryService,\n\t\tsignService: options.signService,\n\t\tlogService: options.logService\n\t};\n}\n\nexport interface IAddress {\n\tconnectTo: T;\n\tconnectionToken: string | undefined;\n}\n\nexport interface IAddressProvider {\n\tgetAddress(): Promise>;\n}\n\nexport async function connectRemoteAgentManagement(options: IConnectionOptions, remoteAuthority: string, clientId: string): Promise {\n\treturn createInitialConnection(\n\t\toptions,\n\t\tasync (simpleOptions) => {\n\t\t\tconst { protocol } = await doConnectRemoteAgentManagement(simpleOptions, CancellationToken.None);\n\t\t\treturn new ManagementPersistentConnection(options, remoteAuthority, clientId, simpleOptions.reconnectionToken, protocol);\n\t\t}\n\t);\n}\n\nexport async function connectRemoteAgentExtensionHost(options: IConnectionOptions, startArguments: IRemoteExtensionHostStartParams): Promise {\n\treturn createInitialConnection(\n\t\toptions,\n\t\tasync (simpleOptions) => {\n\t\t\tconst { protocol, debugPort } = await doConnectRemoteAgentExtensionHost(simpleOptions, startArguments, CancellationToken.None);\n\t\t\treturn new ExtensionHostPersistentConnection(options, startArguments, simpleOptions.reconnectionToken, protocol, debugPort);\n\t\t}\n\t);\n}\n\n/**\n * Will attempt to connect 5 times. If it fails 5 consecutive times, it will give up.\n */\nasync function createInitialConnection(options: IConnectionOptions, connectionFactory: (simpleOptions: ISimpleConnectionOptions) => Promise): Promise {\n\tconst MAX_ATTEMPTS = 5;\n\n\tfor (let attempt = 1; ; attempt++) {\n\t\ttry {\n\t\t\tconst reconnectionToken = generateUuid();\n\t\t\tconst simpleOptions = await resolveConnectionOptions(options, reconnectionToken, null);\n\t\t\tconst result = await connectionFactory(simpleOptions);\n\t\t\treturn result;\n\t\t} catch (err) {\n\t\t\tif (attempt < MAX_ATTEMPTS) {\n\t\t\t\toptions.logService.error(`[remote-connection][attempt ${attempt}] An error occurred in initial connection! Will retry... Error:`);\n\t\t\t\toptions.logService.error(err);\n\t\t\t} else {\n\t\t\t\toptions.logService.error(`[remote-connection][attempt ${attempt}] An error occurred in initial connection! It will be treated as a permanent error. Error:`);\n\t\t\t\toptions.logService.error(err);\n\t\t\t\tPersistentConnection.triggerPermanentFailure(0, 0, RemoteAuthorityResolverError.isHandled(err));\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport async function connectRemoteAgentTunnel(options: IConnectionOptions, tunnelRemoteHost: string, tunnelRemotePort: number): Promise {\n\tconst simpleOptions = await resolveConnectionOptions(options, generateUuid(), null);\n\tconst protocol = await doConnectRemoteAgentTunnel(simpleOptions, { host: tunnelRemoteHost, port: tunnelRemotePort }, CancellationToken.None);\n\treturn protocol;\n}\n\nfunction sleep(seconds: number): CancelablePromise {\n\treturn createCancelablePromise(token => {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst timeout = setTimeout(resolve, seconds * 1000);\n\t\t\ttoken.onCancellationRequested(() => {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\tresolve();\n\t\t\t});\n\t\t});\n\t});\n}\n\nexport const enum PersistentConnectionEventType {\n\tConnectionLost,\n\tReconnectionWait,\n\tReconnectionRunning,\n\tReconnectionPermanentFailure,\n\tConnectionGain\n}\nexport class ConnectionLostEvent {\n\tpublic readonly type = PersistentConnectionEventType.ConnectionLost;\n\tconstructor(\n\t\tpublic readonly reconnectionToken: string,\n\t\tpublic readonly millisSinceLastIncomingData: number\n\t) { }\n}\nexport class ReconnectionWaitEvent {\n\tpublic readonly type = PersistentConnectionEventType.ReconnectionWait;\n\tconstructor(\n\t\tpublic readonly reconnectionToken: string,\n\t\tpublic readonly millisSinceLastIncomingData: number,\n\t\tpublic readonly durationSeconds: number,\n\t\tprivate readonly cancellableTimer: CancelablePromise\n\t) { }\n\n\tpublic skipWait(): void {\n\t\tthis.cancellableTimer.cancel();\n\t}\n}\nexport class ReconnectionRunningEvent {\n\tpublic readonly type = PersistentConnectionEventType.ReconnectionRunning;\n\tconstructor(\n\t\tpublic readonly reconnectionToken: string,\n\t\tpublic readonly millisSinceLastIncomingData: number,\n\t\tpublic readonly attempt: number\n\t) { }\n}\nexport class ConnectionGainEvent {\n\tpublic readonly type = PersistentConnectionEventType.ConnectionGain;\n\tconstructor(\n\t\tpublic readonly reconnectionToken: string,\n\t\tpublic readonly millisSinceLastIncomingData: number,\n\t\tpublic readonly attempt: number\n\t) { }\n}\nexport class ReconnectionPermanentFailureEvent {\n\tpublic readonly type = PersistentConnectionEventType.ReconnectionPermanentFailure;\n\tconstructor(\n\t\tpublic readonly reconnectionToken: string,\n\t\tpublic readonly millisSinceLastIncomingData: number,\n\t\tpublic readonly attempt: number,\n\t\tpublic readonly handled: boolean\n\t) { }\n}\nexport type PersistentConnectionEvent = ConnectionGainEvent | ConnectionLostEvent | ReconnectionWaitEvent | ReconnectionRunningEvent | ReconnectionPermanentFailureEvent;\n\nexport abstract class PersistentConnection extends Disposable {\n\n\tpublic static triggerPermanentFailure(millisSinceLastIncomingData: number, attempt: number, handled: boolean): void {\n\t\tthis._permanentFailure = true;\n\t\tthis._permanentFailureMillisSinceLastIncomingData = millisSinceLastIncomingData;\n\t\tthis._permanentFailureAttempt = attempt;\n\t\tthis._permanentFailureHandled = handled;\n\t\tthis._instances.forEach(instance => instance._gotoPermanentFailure(this._permanentFailureMillisSinceLastIncomingData, this._permanentFailureAttempt, this._permanentFailureHandled));\n\t}\n\n\tpublic static debugTriggerReconnection() {\n\t\tthis._instances.forEach(instance => instance._beginReconnecting());\n\t}\n\n\tpublic static debugPauseSocketWriting() {\n\t\tthis._instances.forEach(instance => instance._pauseSocketWriting());\n\t}\n\n\tprivate static _permanentFailure: boolean = false;\n\tprivate static _permanentFailureMillisSinceLastIncomingData: number = 0;\n\tprivate static _permanentFailureAttempt: number = 0;\n\tprivate static _permanentFailureHandled: boolean = false;\n\tprivate static _instances: PersistentConnection[] = [];\n\n\tprivate readonly _onDidStateChange = this._register(new Emitter());\n\tpublic readonly onDidStateChange = this._onDidStateChange.event;\n\n\tprivate _permanentFailure: boolean = false;\n\tprivate get _isPermanentFailure(): boolean {\n\t\treturn this._permanentFailure || PersistentConnection._permanentFailure;\n\t}\n\n\tprivate _isReconnecting: boolean = false;\n\tprivate _isDisposed: boolean = false;\n\n\tconstructor(\n\t\tprivate readonly _connectionType: ConnectionType,\n\t\tprotected readonly _options: IConnectionOptions,\n\t\tpublic readonly reconnectionToken: string,\n\t\tpublic readonly protocol: PersistentProtocol,\n\t\tprivate readonly _reconnectionFailureIsFatal: boolean\n\t) {\n\t\tsuper();\n\n\t\tthis._onDidStateChange.fire(new ConnectionGainEvent(this.reconnectionToken, 0, 0));\n\n\t\tthis._register(protocol.onSocketClose((e) => {\n\t\t\tconst logPrefix = commonLogPrefix(this._connectionType, this.reconnectionToken, true);\n\t\t\tif (!e) {\n\t\t\t\tthis._options.logService.info(`${logPrefix} received socket close event.`);\n\t\t\t} else if (e.type === SocketCloseEventType.NodeSocketCloseEvent) {\n\t\t\t\tthis._options.logService.info(`${logPrefix} received socket close event (hadError: ${e.hadError}).`);\n\t\t\t\tif (e.error) {\n\t\t\t\t\tthis._options.logService.error(e.error);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis._options.logService.info(`${logPrefix} received socket close event (wasClean: ${e.wasClean}, code: ${e.code}, reason: ${e.reason}).`);\n\t\t\t\tif (e.event) {\n\t\t\t\t\tthis._options.logService.error(e.event);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis._beginReconnecting();\n\t\t}));\n\t\tthis._register(protocol.onSocketTimeout((e) => {\n\t\t\tconst logPrefix = commonLogPrefix(this._connectionType, this.reconnectionToken, true);\n\t\t\tthis._options.logService.info(`${logPrefix} received socket timeout event (unacknowledgedMsgCount: ${e.unacknowledgedMsgCount}, timeSinceOldestUnacknowledgedMsg: ${e.timeSinceOldestUnacknowledgedMsg}, timeSinceLastReceivedSomeData: ${e.timeSinceLastReceivedSomeData}).`);\n\t\t\tthis._beginReconnecting();\n\t\t}));\n\n\t\tPersistentConnection._instances.push(this);\n\t\tthis._register(toDisposable(() => {\n\t\t\tconst myIndex = PersistentConnection._instances.indexOf(this);\n\t\t\tif (myIndex >= 0) {\n\t\t\t\tPersistentConnection._instances.splice(myIndex, 1);\n\t\t\t}\n\t\t}));\n\n\t\tif (this._isPermanentFailure) {\n\t\t\tthis._gotoPermanentFailure(PersistentConnection._permanentFailureMillisSinceLastIncomingData, PersistentConnection._permanentFailureAttempt, PersistentConnection._permanentFailureHandled);\n\t\t}\n\t}\n\n\tpublic override dispose(): void {\n\t\tsuper.dispose();\n\t\tthis._isDisposed = true;\n\t}\n\n\tprivate async _beginReconnecting(): Promise {\n\t\t// Only have one reconnection loop active at a time.\n\t\tif (this._isReconnecting) {\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\tthis._isReconnecting = true;\n\t\t\tawait this._runReconnectingLoop();\n\t\t} finally {\n\t\t\tthis._isReconnecting = false;\n\t\t}\n\t}\n\n\tprivate async _runReconnectingLoop(): Promise {\n\t\tif (this._isPermanentFailure || this._isDisposed) {\n\t\t\t// no more attempts!\n\t\t\treturn;\n\t\t}\n\t\tconst logPrefix = commonLogPrefix(this._connectionType, this.reconnectionToken, true);\n\t\tthis._options.logService.info(`${logPrefix} starting reconnecting loop. You can get more information with the trace log level.`);\n\t\tthis._onDidStateChange.fire(new ConnectionLostEvent(this.reconnectionToken, this.protocol.getMillisSinceLastIncomingData()));\n\t\tconst TIMES = [0, 5, 5, 10, 10, 10, 10, 10, 30];\n\t\tlet attempt = -1;\n\t\tdo {\n\t\t\tattempt++;\n\t\t\tconst waitTime = (attempt < TIMES.length ? TIMES[attempt] : TIMES[TIMES.length - 1]);\n\t\t\ttry {\n\t\t\t\tif (waitTime > 0) {\n\t\t\t\t\tconst sleepPromise = sleep(waitTime);\n\t\t\t\t\tthis._onDidStateChange.fire(new ReconnectionWaitEvent(this.reconnectionToken, this.protocol.getMillisSinceLastIncomingData(), waitTime, sleepPromise));\n\n\t\t\t\t\tthis._options.logService.info(`${logPrefix} waiting for ${waitTime} seconds before reconnecting...`);\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait sleepPromise;\n\t\t\t\t\t} catch { } // User canceled timer\n\t\t\t\t}\n\n\t\t\t\tif (this._isPermanentFailure) {\n\t\t\t\t\tthis._options.logService.error(`${logPrefix} permanent failure occurred while running the reconnecting loop.`);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\t// connection was lost, let's try to re-establish it\n\t\t\t\tthis._onDidStateChange.fire(new ReconnectionRunningEvent(this.reconnectionToken, this.protocol.getMillisSinceLastIncomingData(), attempt + 1));\n\t\t\t\tthis._options.logService.info(`${logPrefix} resolving connection...`);\n\t\t\t\tconst simpleOptions = await resolveConnectionOptions(this._options, this.reconnectionToken, this.protocol);\n\t\t\t\tthis._options.logService.info(`${logPrefix} connecting to ${simpleOptions.connectTo}...`);\n\t\t\t\tawait this._reconnect(simpleOptions, createTimeoutCancellation(RECONNECT_TIMEOUT));\n\t\t\t\tthis._options.logService.info(`${logPrefix} reconnected!`);\n\t\t\t\tthis._onDidStateChange.fire(new ConnectionGainEvent(this.reconnectionToken, this.protocol.getMillisSinceLastIncomingData(), attempt + 1));\n\n\t\t\t\tbreak;\n\t\t\t} catch (err) {\n\t\t\t\tif (err.code === 'VSCODE_CONNECTION_ERROR') {\n\t\t\t\t\tthis._options.logService.error(`${logPrefix} A permanent error occurred in the reconnecting loop! Will give up now! Error:`);\n\t\t\t\t\tthis._options.logService.error(err);\n\t\t\t\t\tthis._onReconnectionPermanentFailure(this.protocol.getMillisSinceLastIncomingData(), attempt + 1, false);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif (attempt > 360) {\n\t\t\t\t\t// ReconnectionGraceTime is 3hrs, with 30s between attempts that yields a maximum of 360 attempts\n\t\t\t\t\tthis._options.logService.error(`${logPrefix} An error occurred while reconnecting, but it will be treated as a permanent error because the reconnection grace time has expired! Will give up now! Error:`);\n\t\t\t\t\tthis._options.logService.error(err);\n\t\t\t\t\tthis._onReconnectionPermanentFailure(this.protocol.getMillisSinceLastIncomingData(), attempt + 1, false);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif (RemoteAuthorityResolverError.isTemporarilyNotAvailable(err)) {\n\t\t\t\t\tthis._options.logService.info(`${logPrefix} A temporarily not available error occurred while trying to reconnect, will try again...`);\n\t\t\t\t\tthis._options.logService.trace(err);\n\t\t\t\t\t// try again!\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif ((err.code === 'ETIMEDOUT' || err.code === 'ENETUNREACH' || err.code === 'ECONNREFUSED' || err.code === 'ECONNRESET') && err.syscall === 'connect') {\n\t\t\t\t\tthis._options.logService.info(`${logPrefix} A network error occurred while trying to reconnect, will try again...`);\n\t\t\t\t\tthis._options.logService.trace(err);\n\t\t\t\t\t// try again!\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (isCancellationError(err)) {\n\t\t\t\t\tthis._options.logService.info(`${logPrefix} A promise cancelation error occurred while trying to reconnect, will try again...`);\n\t\t\t\t\tthis._options.logService.trace(err);\n\t\t\t\t\t// try again!\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (err instanceof RemoteAuthorityResolverError) {\n\t\t\t\t\tthis._options.logService.error(`${logPrefix} A RemoteAuthorityResolverError occurred while trying to reconnect. Will give up now! Error:`);\n\t\t\t\t\tthis._options.logService.error(err);\n\t\t\t\t\tthis._onReconnectionPermanentFailure(this.protocol.getMillisSinceLastIncomingData(), attempt + 1, RemoteAuthorityResolverError.isHandled(err));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tthis._options.logService.error(`${logPrefix} An unknown error occurred while trying to reconnect, since this is an unknown case, it will be treated as a permanent error! Will give up now! Error:`);\n\t\t\t\tthis._options.logService.error(err);\n\t\t\t\tthis._onReconnectionPermanentFailure(this.protocol.getMillisSinceLastIncomingData(), attempt + 1, false);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t} while (!this._isPermanentFailure && !this._isDisposed);\n\t}\n\n\tprivate _onReconnectionPermanentFailure(millisSinceLastIncomingData: number, attempt: number, handled: boolean): void {\n\t\tif (this._reconnectionFailureIsFatal) {\n\t\t\tPersistentConnection.triggerPermanentFailure(millisSinceLastIncomingData, attempt, handled);\n\t\t} else {\n\t\t\tthis._gotoPermanentFailure(millisSinceLastIncomingData, attempt, handled);\n\t\t}\n\t}\n\n\tprivate _gotoPermanentFailure(millisSinceLastIncomingData: number, attempt: number, handled: boolean): void {\n\t\tthis._onDidStateChange.fire(new ReconnectionPermanentFailureEvent(this.reconnectionToken, millisSinceLastIncomingData, attempt, handled));\n\t\tsafeDisposeProtocolAndSocket(this.protocol);\n\t}\n\n\tprivate _pauseSocketWriting(): void {\n\t\tthis.protocol.pauseSocketWriting();\n\t}\n\n\tprotected abstract _reconnect(options: ISimpleConnectionOptions, timeoutCancellationToken: CancellationToken): Promise;\n}\n\nexport class ManagementPersistentConnection extends PersistentConnection {\n\n\tpublic readonly client: Client;\n\n\tconstructor(options: IConnectionOptions, remoteAuthority: string, clientId: string, reconnectionToken: string, protocol: PersistentProtocol) {\n\t\tsuper(ConnectionType.Management, options, reconnectionToken, protocol, /*reconnectionFailureIsFatal*/true);\n\t\tthis.client = this._register(new Client(protocol, {\n\t\t\tremoteAuthority: remoteAuthority,\n\t\t\tclientId: clientId\n\t\t}, options.ipcLogger));\n\t}\n\n\tprotected async _reconnect(options: ISimpleConnectionOptions, timeoutCancellationToken: CancellationToken): Promise {\n\t\tawait doConnectRemoteAgentManagement(options, timeoutCancellationToken);\n\t}\n}\n\nexport class ExtensionHostPersistentConnection extends PersistentConnection {\n\n\tprivate readonly _startArguments: IRemoteExtensionHostStartParams;\n\tpublic readonly debugPort: number | undefined;\n\n\tconstructor(options: IConnectionOptions, startArguments: IRemoteExtensionHostStartParams, reconnectionToken: string, protocol: PersistentProtocol, debugPort: number | undefined) {\n\t\tsuper(ConnectionType.ExtensionHost, options, reconnectionToken, protocol, /*reconnectionFailureIsFatal*/false);\n\t\tthis._startArguments = startArguments;\n\t\tthis.debugPort = debugPort;\n\t}\n\n\tprotected async _reconnect(options: ISimpleConnectionOptions, timeoutCancellationToken: CancellationToken): Promise {\n\t\tawait doConnectRemoteAgentExtensionHost(options, this._startArguments, timeoutCancellationToken);\n\t}\n}\n\nfunction safeDisposeProtocolAndSocket(protocol: PersistentProtocol): void {\n\ttry {\n\t\tprotocol.acceptDisconnect();\n\t\tconst socket = protocol.getSocket();\n\t\tprotocol.dispose();\n\t\tsocket.dispose();\n\t} catch (err) {\n\t\tonUnexpectedError(err);\n\t}\n}\n\nfunction getErrorFromMessage(msg: any): Error | null {\n\tif (msg && msg.type === 'error') {\n\t\tconst error = new Error(`Connection error: ${msg.reason}`);\n\t\t(error).code = 'VSCODE_CONNECTION_ERROR';\n\t\treturn error;\n\t}\n\treturn null;\n}\n\nfunction stringRightPad(str: string, len: number): string {\n\twhile (str.length < len) {\n\t\tstr += ' ';\n\t}\n\treturn str;\n}\n\nfunction _commonLogPrefix(connectionType: ConnectionType, reconnectionToken: string): string {\n\treturn `[remote-connection][${stringRightPad(connectionTypeToString(connectionType), 13)}][${reconnectionToken.substr(0, 5)}…]`;\n}\n\nfunction commonLogPrefix(connectionType: ConnectionType, reconnectionToken: string, isReconnect: boolean): string {\n\treturn `${_commonLogPrefix(connectionType, reconnectionToken)}[${isReconnect ? 'reconnect' : 'initial'}]`;\n}\n\nfunction connectLogPrefix(options: ISimpleConnectionOptions, connectionType: ConnectionType): string {\n\treturn `${commonLogPrefix(connectionType, options.reconnectionToken, !!options.reconnectionProtocol)}[${options.connectTo}]`;\n}\n\nfunction logElapsed(startTime: number): string {\n\treturn `${Date.now() - startTime} ms`;\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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, toDisposable } from 'vs/base/common/lifecycle';\nimport { ISocket } from 'vs/base/parts/ipc/common/ipc.net';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\nimport { RemoteConnectionOfType, RemoteConnectionType, RemoteConnection } from 'vs/platform/remote/common/remoteAuthorityResolver';\n\nexport const IRemoteSocketFactoryService = createDecorator('remoteSocketFactoryService');\n\nexport interface IRemoteSocketFactoryService {\n\treadonly _serviceBrand: undefined;\n\n\t/**\n\t * Register a socket factory for the given message passing type\n\t * @param type passing type to register for\n\t * @param factory function that returns the socket factory, or undefined if\n\t * it can't handle the data.\n\t */\n\tregister(type: T, factory: ISocketFactory): IDisposable;\n\n\tconnect(connectTo: RemoteConnection, path: string, query: string, debugLabel: string): Promise;\n}\n\nexport interface ISocketFactory {\n\tsupports(connectTo: RemoteConnectionOfType): boolean;\n\tconnect(connectTo: RemoteConnectionOfType, path: string, query: string, debugLabel: string): Promise;\n}\n\nexport class RemoteSocketFactoryService implements IRemoteSocketFactoryService {\n\tdeclare readonly _serviceBrand: undefined;\n\n\tprivate readonly factories: { [T in RemoteConnectionType]?: ISocketFactory[] } = {};\n\n\tpublic register(type: T, factory: ISocketFactory): IDisposable {\n\t\tthis.factories[type] ??= [];\n\t\tthis.factories[type]!.push(factory);\n\t\treturn toDisposable(() => {\n\t\t\tconst idx = this.factories[type]?.indexOf(factory);\n\t\t\tif (typeof idx === 'number' && idx >= 0) {\n\t\t\t\tthis.factories[type]?.splice(idx, 1);\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate getSocketFactory(messagePassing: RemoteConnectionOfType): ISocketFactory | undefined {\n\t\tconst factories = (this.factories[messagePassing.type] || []) as ISocketFactory[];\n\t\treturn factories.find(factory => factory.supports(messagePassing));\n\t}\n\n\tpublic connect(connectTo: RemoteConnection, path: string, query: string, debugLabel: string): Promise {\n\t\tconst socketFactory = this.getSocketFactory(connectTo);\n\t\tif (!socketFactory) {\n\t\t\tthrow new Error(`No socket factory found for ${connectTo}`);\n\t\t}\n\t\treturn socketFactory.connect(connectTo, path, query, debugLabel);\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { streamToBuffer } from 'vs/base/common/buffer';\nimport { CancellationToken } from 'vs/base/common/cancellation';\nimport { getErrorMessage } from 'vs/base/common/errors';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { IHeaders, IRequestContext, IRequestOptions } from 'vs/base/parts/request/common/request';\nimport { localize } from 'vs/nls';\nimport { ConfigurationScope, Extensions, IConfigurationNode, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\nimport { CONTEXT_LOG_LEVEL, ILogger, ILoggerService, LogLevel, LogLevelToString } from 'vs/platform/log/common/log';\nimport { Registry } from 'vs/platform/registry/common/platform';\n\nexport const IRequestService = createDecorator('requestService');\n\nexport interface IRequestService {\n\treadonly _serviceBrand: undefined;\n\n\trequest(options: IRequestOptions, token: CancellationToken): Promise;\n\n\tresolveProxy(url: string): Promise;\n\tloadCertificates(): Promise;\n}\n\nclass LoggableHeaders {\n\n\tprivate headers: IHeaders | undefined;\n\n\tconstructor(private readonly original: IHeaders) { }\n\n\ttoJSON(): any {\n\t\tif (!this.headers) {\n\t\t\tconst headers = Object.create(null);\n\t\t\tfor (const key in this.original) {\n\t\t\t\tif (key.toLowerCase() === 'authorization' || key.toLowerCase() === 'proxy-authorization') {\n\t\t\t\t\theaders[key] = '*****';\n\t\t\t\t} else {\n\t\t\t\t\theaders[key] = this.original[key];\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.headers = headers;\n\t\t}\n\t\treturn this.headers;\n\t}\n\n}\n\nexport abstract class AbstractRequestService extends Disposable implements IRequestService {\n\n\tdeclare readonly _serviceBrand: undefined;\n\n\tprotected readonly logger: ILogger;\n\tprivate counter = 0;\n\n\tconstructor(\n\t\tloggerService: ILoggerService\n\t) {\n\t\tsuper();\n\t\tthis.logger = loggerService.createLogger('network', {\n\t\t\tname: localize('request', \"Network Requests\"),\n\t\t\twhen: CONTEXT_LOG_LEVEL.isEqualTo(LogLevelToString(LogLevel.Trace)).serialize()\n\t\t});\n\t}\n\n\tprotected async logAndRequest(stack: string, options: IRequestOptions, request: () => Promise): Promise {\n\t\tconst prefix = `${stack} #${++this.counter}: ${options.url}`;\n\t\tthis.logger.trace(`${prefix} - begin`, options.type, new LoggableHeaders(options.headers ?? {}));\n\t\ttry {\n\t\t\tconst result = await request();\n\t\t\tthis.logger.trace(`${prefix} - end`, options.type, result.res.statusCode, result.res.headers);\n\t\t\treturn result;\n\t\t} catch (error) {\n\t\t\tthis.logger.error(`${prefix} - error`, options.type, getErrorMessage(error));\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tabstract request(options: IRequestOptions, token: CancellationToken): Promise;\n\tabstract resolveProxy(url: string): Promise;\n\tabstract loadCertificates(): Promise;\n}\n\nexport function isSuccess(context: IRequestContext): boolean {\n\treturn (context.res.statusCode && context.res.statusCode >= 200 && context.res.statusCode < 300) || context.res.statusCode === 1223;\n}\n\nexport function hasNoContent(context: IRequestContext): boolean {\n\treturn context.res.statusCode === 204;\n}\n\nexport async function asText(context: IRequestContext): Promise {\n\tif (hasNoContent(context)) {\n\t\treturn null;\n\t}\n\tconst buffer = await streamToBuffer(context.stream);\n\treturn buffer.toString();\n}\n\nexport async function asTextOrError(context: IRequestContext): Promise {\n\tif (!isSuccess(context)) {\n\t\tthrow new Error('Server returned ' + context.res.statusCode);\n\t}\n\treturn asText(context);\n}\n\nexport async function asJson(context: IRequestContext): Promise {\n\tif (!isSuccess(context)) {\n\t\tthrow new Error('Server returned ' + context.res.statusCode);\n\t}\n\tif (hasNoContent(context)) {\n\t\treturn null;\n\t}\n\tconst buffer = await streamToBuffer(context.stream);\n\tconst str = buffer.toString();\n\ttry {\n\t\treturn JSON.parse(str);\n\t} catch (err) {\n\t\terr.message += ':\\n' + str;\n\t\tthrow err;\n\t}\n}\n\nexport function updateProxyConfigurationsScope(scope: ConfigurationScope): void {\n\tregisterProxyConfigurations(scope);\n}\n\nlet proxyConfiguration: IConfigurationNode | undefined;\nfunction registerProxyConfigurations(scope: ConfigurationScope): void {\n\tconst configurationRegistry = Registry.as(Extensions.Configuration);\n\tconst oldProxyConfiguration = proxyConfiguration;\n\tproxyConfiguration = {\n\t\tid: 'http',\n\t\torder: 15,\n\t\ttitle: localize('httpConfigurationTitle', \"HTTP\"),\n\t\ttype: 'object',\n\t\tscope,\n\t\tproperties: {\n\t\t\t'http.proxy': {\n\t\t\t\ttype: 'string',\n\t\t\t\tpattern: '^(https?|socks|socks4a?|socks5h?)://([^:]*(:[^@]*)?@)?([^:]+|\\\\[[:0-9a-fA-F]+\\\\])(:\\\\d+)?/?$|^$',\n\t\t\t\tmarkdownDescription: localize('proxy', \"The proxy setting to use. If not set, will be inherited from the `http_proxy` and `https_proxy` environment variables.\"),\n\t\t\t\trestricted: true\n\t\t\t},\n\t\t\t'http.proxyStrictSSL': {\n\t\t\t\ttype: 'boolean',\n\t\t\t\tdefault: true,\n\t\t\t\tdescription: localize('strictSSL', \"Controls whether the proxy server certificate should be verified against the list of supplied CAs.\"),\n\t\t\t\trestricted: true\n\t\t\t},\n\t\t\t'http.proxyKerberosServicePrincipal': {\n\t\t\t\ttype: 'string',\n\t\t\t\tmarkdownDescription: localize('proxyKerberosServicePrincipal', \"Overrides the principal service name for Kerberos authentication with the HTTP proxy. A default based on the proxy hostname is used when this is not set.\"),\n\t\t\t\trestricted: true\n\t\t\t},\n\t\t\t'http.proxyAuthorization': {\n\t\t\t\ttype: ['null', 'string'],\n\t\t\t\tdefault: null,\n\t\t\t\tmarkdownDescription: localize('proxyAuthorization', \"The value to send as the `Proxy-Authorization` header for every network request.\"),\n\t\t\t\trestricted: true\n\t\t\t},\n\t\t\t'http.proxySupport': {\n\t\t\t\ttype: 'string',\n\t\t\t\tenum: ['off', 'on', 'fallback', 'override'],\n\t\t\t\tenumDescriptions: [\n\t\t\t\t\tlocalize('proxySupportOff', \"Disable proxy support for extensions.\"),\n\t\t\t\t\tlocalize('proxySupportOn', \"Enable proxy support for extensions.\"),\n\t\t\t\t\tlocalize('proxySupportFallback', \"Enable proxy support for extensions, fall back to request options, when no proxy found.\"),\n\t\t\t\t\tlocalize('proxySupportOverride', \"Enable proxy support for extensions, override request options.\"),\n\t\t\t\t],\n\t\t\t\tdefault: 'override',\n\t\t\t\tdescription: localize('proxySupport', \"Use the proxy support for extensions.\"),\n\t\t\t\trestricted: true\n\t\t\t},\n\t\t\t'http.systemCertificates': {\n\t\t\t\ttype: 'boolean',\n\t\t\t\tdefault: true,\n\t\t\t\tdescription: localize('systemCertificates', \"Controls whether CA certificates should be loaded from the OS. (On Windows and macOS, a reload of the window is required after turning this off.)\"),\n\t\t\t\trestricted: true\n\t\t\t},\n\t\t\t'http.experimental.systemCertificatesV2': {\n\t\t\t\ttype: 'boolean',\n\t\t\t\ttags: ['experimental'],\n\t\t\t\tdefault: false,\n\t\t\t\tdescription: localize('systemCertificatesV2', \"Controls whether experimental loading of CA certificates from the OS should be enabled. This uses a more general approach than the default implemenation.\"),\n\t\t\t\trestricted: true\n\t\t\t}\n\t\t}\n\t};\n\tconfigurationRegistry.updateConfigurations({ add: [proxyConfiguration], remove: oldProxyConfiguration ? [oldProxyConfiguration] : [] });\n}\n\nregisterProxyConfigurations(ConfigurationScope.APPLICATION);\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { Schemas } from 'vs/base/common/network';\nimport { URI } from 'vs/base/common/uri';\nimport { IDownloadService } from 'vs/platform/download/common/download';\nimport { IFileService } from 'vs/platform/files/common/files';\nimport { asTextOrError, IRequestService } from 'vs/platform/request/common/request';\n\nexport class DownloadService implements IDownloadService {\n\n\tdeclare readonly _serviceBrand: undefined;\n\n\tconstructor(\n\t\t@IRequestService private readonly requestService: IRequestService,\n\t\t@IFileService private readonly fileService: IFileService\n\t) { }\n\n\tasync download(resource: URI, target: URI, cancellationToken: CancellationToken = CancellationToken.None): Promise {\n\t\tif (resource.scheme === Schemas.file || resource.scheme === Schemas.vscodeRemote) {\n\t\t\t// Intentionally only support this for file|remote<->file|remote scenarios\n\t\t\tawait this.fileService.copy(resource, target);\n\t\t\treturn;\n\t\t}\n\t\tconst options = { type: 'GET', url: resource.toString(true) };\n\t\tconst context = await this.requestService.request(options, cancellationToken);\n\t\tif (context.res.statusCode === 200) {\n\t\t\tawait this.fileService.writeFile(target, context.stream);\n\t\t} else {\n\t\t\tconst message = await asTextOrError(context);\n\t\t\tthrow new Error(`Expected 200, got back ${context.res.statusCode} instead.\\n\\n${message}`);\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 { request } from 'vs/base/parts/request/browser/request';\nimport { IRequestContext, IRequestOptions } from 'vs/base/parts/request/common/request';\nimport { IConfigurationService } from 'vs/platform/configuration/common/configuration';\nimport { ILoggerService } from 'vs/platform/log/common/log';\nimport { AbstractRequestService, IRequestService } from 'vs/platform/request/common/request';\n\n/**\n * This service exposes the `request` API, while using the global\n * or configured proxy settings.\n */\nexport class RequestService extends AbstractRequestService implements IRequestService {\n\n\tdeclare readonly _serviceBrand: undefined;\n\n\tconstructor(\n\t\t@IConfigurationService private readonly configurationService: IConfigurationService,\n\t\t@ILoggerService loggerService: ILoggerService\n\t) {\n\t\tsuper(loggerService);\n\t}\n\n\tasync request(options: IRequestOptions, token: CancellationToken): Promise {\n\t\tif (!options.proxyAuthorization) {\n\t\t\toptions.proxyAuthorization = this.configurationService.getValue('http.proxyAuthorization');\n\t\t}\n\t\treturn this.logAndRequest('browser', options, () => request(options, token));\n\t}\n\n\tasync resolveProxy(url: string): Promise {\n\t\treturn undefined; // not implemented in the web\n\t}\n\n\tasync loadCertificates(): Promise {\n\t\treturn []; // not implemented in the web\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { bufferToStream, streamToBuffer, VSBuffer } from 'vs/base/common/buffer';\nimport { CancellationToken } from 'vs/base/common/cancellation';\nimport { Event } from 'vs/base/common/event';\nimport { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';\nimport { IHeaders, IRequestContext, IRequestOptions } from 'vs/base/parts/request/common/request';\nimport { IRequestService } from 'vs/platform/request/common/request';\n\ntype RequestResponse = [\n\t{\n\t\theaders: IHeaders;\n\t\tstatusCode?: number;\n\t},\n\tVSBuffer\n];\n\nexport class RequestChannel implements IServerChannel {\n\n\tconstructor(private readonly service: IRequestService) { }\n\n\tlisten(context: any, event: string): Event {\n\t\tthrow new Error('Invalid listen');\n\t}\n\n\tcall(context: any, command: string, args?: any, token: CancellationToken = CancellationToken.None): Promise {\n\t\tswitch (command) {\n\t\t\tcase 'request': return this.service.request(args[0], token)\n\t\t\t\t.then(async ({ res, stream }) => {\n\t\t\t\t\tconst buffer = await streamToBuffer(stream);\n\t\t\t\t\treturn [{ statusCode: res.statusCode, headers: res.headers }, buffer];\n\t\t\t\t});\n\t\t\tcase 'resolveProxy': return this.service.resolveProxy(args[0]);\n\t\t\tcase 'loadCertificates': return this.service.loadCertificates();\n\t\t}\n\t\tthrow new Error('Invalid call');\n\t}\n}\n\nexport class RequestChannelClient implements IRequestService {\n\n\tdeclare readonly _serviceBrand: undefined;\n\n\tconstructor(private readonly channel: IChannel) { }\n\n\tasync request(options: IRequestOptions, token: CancellationToken): Promise {\n\t\tconst [res, buffer] = await this.channel.call('request', [options], token);\n\t\treturn { res, stream: bufferToStream(buffer) };\n\t}\n\n\tasync resolveProxy(url: string): Promise {\n\t\treturn this.channel.call('resolveProxy', [url]);\n\t}\n\n\tasync loadCertificates(): Promise {\n\t\treturn this.channel.call('loadCertificates');\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { IMessage, ISignService } from 'vs/platform/sign/common/sign';\n\nexport interface IVsdaSigner {\n\tsign(arg: string): string;\n}\n\nexport interface IVsdaValidator {\n\tcreateNewMessage(arg: string): string;\n\tvalidate(arg: string): 'ok' | 'error';\n\tdispose?(): void;\n}\n\nexport abstract class AbstractSignService implements ISignService {\n\tdeclare readonly _serviceBrand: undefined;\n\n\tprivate static _nextId = 1;\n\tprivate readonly validators = new Map();\n\n\tprotected abstract getValidator(): Promise;\n\tprotected abstract signValue(arg: string): Promise;\n\n\tpublic async createNewMessage(value: string): Promise {\n\t\ttry {\n\t\t\tconst validator = await this.getValidator();\n\t\t\tif (validator) {\n\t\t\t\tconst id = String(AbstractSignService._nextId++);\n\t\t\t\tthis.validators.set(id, validator);\n\t\t\t\treturn {\n\t\t\t\t\tid: id,\n\t\t\t\t\tdata: validator.createNewMessage(value)\n\t\t\t\t};\n\t\t\t}\n\t\t} catch (e) {\n\t\t\t// ignore errors silently\n\t\t}\n\t\treturn { id: '', data: value };\n\t}\n\n\tasync validate(message: IMessage, value: string): Promise {\n\t\tif (!message.id) {\n\t\t\treturn true;\n\t\t}\n\n\t\tconst validator = this.validators.get(message.id);\n\t\tif (!validator) {\n\t\t\treturn false;\n\t\t}\n\t\tthis.validators.delete(message.id);\n\t\ttry {\n\t\t\treturn (validator.validate(value) === 'ok');\n\t\t} catch (e) {\n\t\t\t// ignore errors silently\n\t\t\treturn false;\n\t\t} finally {\n\t\t\tvalidator.dispose?.();\n\t\t}\n\t}\n\n\tasync sign(value: string): Promise {\n\t\ttry {\n\t\t\treturn await this.signValue(value);\n\t\t} catch (e) {\n\t\t\t// ignore errors silently\n\t\t}\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\nimport { WindowIntervalTimer } from 'vs/base/browser/dom';\nimport { mainWindow } from 'vs/base/browser/window';\nimport { memoize } from 'vs/base/common/decorators';\nimport { FileAccess } from 'vs/base/common/network';\nimport { IProductService } from 'vs/platform/product/common/productService';\nimport { AbstractSignService, IVsdaValidator } from 'vs/platform/sign/common/abstractSignService';\nimport { ISignService } from 'vs/platform/sign/common/sign';\n\ndeclare module vsdaWeb {\n\texport function sign(salted_message: string): string;\n\n\t// eslint-disable-next-line @typescript-eslint/naming-convention\n\texport class validator {\n\t\tfree(): void;\n\t\tconstructor();\n\t\tcreateNewMessage(original: string): string;\n\t\tvalidate(signed_message: string): 'ok' | 'error';\n\t}\n\n\texport type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;\n\texport function init(module_or_path?: InitInput | Promise): Promise;\n}\n\n// Initialized if/when vsda is loaded\ndeclare const vsda_web: {\n\tdefault: typeof vsdaWeb.init;\n\tsign: typeof vsdaWeb.sign;\n\tvalidator: typeof vsdaWeb.validator;\n};\n\nconst KEY_SIZE = 32;\nconst IV_SIZE = 16;\nconst STEP_SIZE = KEY_SIZE + IV_SIZE;\n\nexport class SignService extends AbstractSignService implements ISignService {\n\tconstructor(@IProductService private readonly productService: IProductService) {\n\t\tsuper();\n\t}\n\tprotected override getValidator(): Promise {\n\t\treturn this.vsda().then(vsda => {\n\t\t\tconst v = new vsda.validator();\n\t\t\treturn {\n\t\t\t\tcreateNewMessage: arg => v.createNewMessage(arg),\n\t\t\t\tvalidate: arg => v.validate(arg),\n\t\t\t\tdispose: () => v.free(),\n\t\t\t};\n\t\t});\n\t}\n\n\tprotected override signValue(arg: string): Promise {\n\t\treturn this.vsda().then(vsda => vsda.sign(arg));\n\t}\n\n\t@memoize\n\tprivate async vsda(): Promise {\n\t\tconst checkInterval = new WindowIntervalTimer();\n\t\tlet [wasm] = await Promise.all([\n\t\t\tthis.getWasmBytes(),\n\t\t\tnew Promise((resolve, reject) => {\n\t\t\t\trequire(['vsda'], resolve, reject);\n\n\t\t\t\t// todo@connor4312: there seems to be a bug(?) in vscode-loader with\n\t\t\t\t// require() not resolving in web once the script loads, so check manually\n\t\t\t\tcheckInterval.cancelAndSet(() => {\n\t\t\t\t\tif (typeof vsda_web !== 'undefined') {\n\t\t\t\t\t\tresolve();\n\t\t\t\t\t}\n\t\t\t\t}, 50, mainWindow);\n\t\t\t}).finally(() => checkInterval.dispose()),\n\t\t]);\n\n\n\t\tconst keyBytes = new TextEncoder().encode(this.productService.serverLicense?.join('\\n') || '');\n\t\tfor (let i = 0; i + STEP_SIZE < keyBytes.length; i += STEP_SIZE) {\n\t\t\tconst key = await crypto.subtle.importKey('raw', keyBytes.slice(i + IV_SIZE, i + IV_SIZE + KEY_SIZE), { name: 'AES-CBC' }, false, ['decrypt']);\n\t\t\twasm = await crypto.subtle.decrypt({ name: 'AES-CBC', iv: keyBytes.slice(i, i + IV_SIZE) }, key, wasm);\n\t\t}\n\n\t\tawait vsda_web.default(wasm);\n\n\t\treturn vsda_web;\n\t}\n\n\tprivate async getWasmBytes(): Promise {\n\t\tconst response = await fetch(FileAccess.asBrowserUri('vsda/../vsda_bg.wasm').toString(true));\n\t\tif (!response.ok) {\n\t\t\tthrow new Error('error loading vsda');\n\t\t}\n\n\t\treturn response.arrayBuffer();\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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';\n\nexport const SIGN_SERVICE_ID = 'signService';\nexport const ISignService = createDecorator(SIGN_SERVICE_ID);\n\nexport interface IMessage {\n\tid: string;\n\tdata: string;\n}\n\nexport interface ISignService {\n\treadonly _serviceBrand: undefined;\n\n\tcreateNewMessage(value: string): Promise;\n\tvalidate(message: IMessage, value: string): Promise;\n\tsign(value: string): 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 { Disposable } from 'vs/base/common/lifecycle';\nimport { UriDto } from 'vs/base/common/uri';\nimport { IChannel } from 'vs/base/parts/ipc/common/ipc';\nimport { IStorageDatabase, IStorageItemsChangeEvent, IUpdateRequest } from 'vs/base/parts/storage/common/storage';\nimport { IUserDataProfile } from 'vs/platform/userDataProfile/common/userDataProfile';\nimport { ISerializedSingleFolderWorkspaceIdentifier, ISerializedWorkspaceIdentifier, IEmptyWorkspaceIdentifier, IAnyWorkspaceIdentifier } from 'vs/platform/workspace/common/workspace';\n\nexport type Key = string;\nexport type Value = string;\nexport type Item = [Key, Value];\n\nexport interface IBaseSerializableStorageRequest {\n\n\t/**\n\t * Profile to correlate storage. Only used when no\n\t * workspace is provided. Can be undefined to denote\n\t * application scope.\n\t */\n\treadonly profile: UriDto | undefined;\n\n\t/**\n\t * Workspace to correlate storage. Can be undefined to\n\t * denote application or profile scope depending on profile.\n\t */\n\treadonly workspace: ISerializedWorkspaceIdentifier | ISerializedSingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier | undefined;\n\n\t/**\n\t * Additional payload for the request to perform.\n\t */\n\treadonly payload?: unknown;\n}\n\nexport interface ISerializableUpdateRequest extends IBaseSerializableStorageRequest {\n\tinsert?: Item[];\n\tdelete?: Key[];\n}\n\nexport interface ISerializableItemsChangeEvent {\n\treadonly changed?: Item[];\n\treadonly deleted?: Key[];\n}\n\nabstract class BaseStorageDatabaseClient extends Disposable implements IStorageDatabase {\n\n\tabstract readonly onDidChangeItemsExternal: Event;\n\n\tconstructor(\n\t\tprotected channel: IChannel,\n\t\tprotected profile: UriDto | undefined,\n\t\tprotected workspace: IAnyWorkspaceIdentifier | undefined\n\t) {\n\t\tsuper();\n\t}\n\n\tasync getItems(): Promise> {\n\t\tconst serializableRequest: IBaseSerializableStorageRequest = { profile: this.profile, workspace: this.workspace };\n\t\tconst items: Item[] = await this.channel.call('getItems', serializableRequest);\n\n\t\treturn new Map(items);\n\t}\n\n\tupdateItems(request: IUpdateRequest): Promise {\n\t\tconst serializableRequest: ISerializableUpdateRequest = { profile: this.profile, workspace: this.workspace };\n\n\t\tif (request.insert) {\n\t\t\tserializableRequest.insert = Array.from(request.insert.entries());\n\t\t}\n\n\t\tif (request.delete) {\n\t\t\tserializableRequest.delete = Array.from(request.delete.values());\n\t\t}\n\n\t\treturn this.channel.call('updateItems', serializableRequest);\n\t}\n\n\toptimize(): Promise {\n\t\tconst serializableRequest: IBaseSerializableStorageRequest = { profile: this.profile, workspace: this.workspace };\n\n\t\treturn this.channel.call('optimize', serializableRequest);\n\t}\n\n\tabstract close(): Promise;\n}\n\nabstract class BaseProfileAwareStorageDatabaseClient extends BaseStorageDatabaseClient {\n\n\tprivate readonly _onDidChangeItemsExternal = this._register(new Emitter());\n\treadonly onDidChangeItemsExternal = this._onDidChangeItemsExternal.event;\n\n\tconstructor(channel: IChannel, profile: UriDto | undefined) {\n\t\tsuper(channel, profile, undefined);\n\n\t\tthis.registerListeners();\n\t}\n\n\tprivate registerListeners(): void {\n\t\tthis._register(this.channel.listen('onDidChangeStorage', { profile: this.profile })((e: ISerializableItemsChangeEvent) => this.onDidChangeStorage(e)));\n\t}\n\n\tprivate onDidChangeStorage(e: ISerializableItemsChangeEvent): void {\n\t\tif (Array.isArray(e.changed) || Array.isArray(e.deleted)) {\n\t\t\tthis._onDidChangeItemsExternal.fire({\n\t\t\t\tchanged: e.changed ? new Map(e.changed) : undefined,\n\t\t\t\tdeleted: e.deleted ? new Set(e.deleted) : undefined\n\t\t\t});\n\t\t}\n\t}\n}\n\nexport class ApplicationStorageDatabaseClient extends BaseProfileAwareStorageDatabaseClient {\n\n\tconstructor(channel: IChannel) {\n\t\tsuper(channel, undefined);\n\t}\n\n\tasync close(): Promise {\n\n\t\t// The application storage database is shared across all instances so\n\t\t// we do not close it from the window. However we dispose the\n\t\t// listener for external changes because we no longer interested in it.\n\n\t\tthis.dispose();\n\t}\n}\n\nexport class ProfileStorageDatabaseClient extends BaseProfileAwareStorageDatabaseClient {\n\n\tconstructor(channel: IChannel, profile: UriDto) {\n\t\tsuper(channel, profile);\n\t}\n\n\tasync close(): Promise {\n\n\t\t// The profile storage database is shared across all instances of\n\t\t// the same profile so we do not close it from the window.\n\t\t// However we dispose the listener for external changes because\n\t\t// we no longer interested in it.\n\n\t\tthis.dispose();\n\t}\n}\n\nexport class WorkspaceStorageDatabaseClient extends BaseStorageDatabaseClient implements IStorageDatabase {\n\n\treadonly onDidChangeItemsExternal = Event.None; // unsupported for workspace storage because we only ever write from one window\n\n\tconstructor(channel: IChannel, workspace: IAnyWorkspaceIdentifier) {\n\t\tsuper(channel, undefined, workspace);\n\t}\n\n\tasync close(): Promise {\n\n\t\t// The workspace storage database is only used in this instance\n\t\t// but we do not need to close it from here, the main process\n\t\t// can take care of that.\n\n\t\tthis.dispose();\n\t}\n}\n\nexport class StorageClient {\n\n\tconstructor(private readonly channel: IChannel) { }\n\n\tisUsed(path: string): Promise {\n\t\tconst serializableRequest: ISerializableUpdateRequest = { payload: path, profile: undefined, workspace: undefined };\n\n\t\treturn this.channel.call('isUsed', serializableRequest);\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { isLinuxSnap, platform, Platform, PlatformToString } from 'vs/base/common/platform';\nimport { env, platform as nodePlatform } from 'vs/base/common/process';\nimport { generateUuid } from 'vs/base/common/uuid';\nimport { ICommonProperties } from 'vs/platform/telemetry/common/telemetry';\n\nfunction getPlatformDetail(hostname: string): string | undefined {\n\tif (platform === Platform.Linux && /^penguin(\\.|$)/i.test(hostname)) {\n\t\treturn 'chromebook';\n\t}\n\n\treturn undefined;\n}\n\nexport function resolveCommonProperties(\n\trelease: string,\n\thostname: string,\n\tarch: string,\n\tcommit: string | undefined,\n\tversion: string | undefined,\n\tmachineId: string | undefined,\n\tsqmId: string | undefined,\n\tisInternalTelemetry: boolean,\n\tproduct?: string\n): ICommonProperties {\n\tconst result: ICommonProperties = Object.create(null);\n\n\t// __GDPR__COMMON__ \"common.machineId\" : { \"endPoint\": \"MacAddressHash\", \"classification\": \"EndUserPseudonymizedInformation\", \"purpose\": \"FeatureInsight\" }\n\tresult['common.machineId'] = machineId;\n\t// __GDPR__COMMON__ \"common.sqmId\" : { \"endPoint\": \"SqmMachineId\", \"classification\": \"EndUserPseudonymizedInformation\", \"purpose\": \"BusinessInsight\" }\n\tresult['common.sqmId'] = sqmId;\n\t// __GDPR__COMMON__ \"sessionID\" : { \"classification\": \"SystemMetaData\", \"purpose\": \"FeatureInsight\" }\n\tresult['sessionID'] = generateUuid() + Date.now();\n\t// __GDPR__COMMON__ \"commitHash\" : { \"classification\": \"SystemMetaData\", \"purpose\": \"PerformanceAndHealth\" }\n\tresult['commitHash'] = commit;\n\t// __GDPR__COMMON__ \"version\" : { \"classification\": \"SystemMetaData\", \"purpose\": \"FeatureInsight\" }\n\tresult['version'] = version;\n\t// __GDPR__COMMON__ \"common.platformVersion\" : { \"classification\": \"SystemMetaData\", \"purpose\": \"FeatureInsight\" }\n\tresult['common.platformVersion'] = (release || '').replace(/^(\\d+)(\\.\\d+)?(\\.\\d+)?(.*)/, '$1$2$3');\n\t// __GDPR__COMMON__ \"common.platform\" : { \"classification\": \"SystemMetaData\", \"purpose\": \"FeatureInsight\" }\n\tresult['common.platform'] = PlatformToString(platform);\n\t// __GDPR__COMMON__ \"common.nodePlatform\" : { \"classification\": \"SystemMetaData\", \"purpose\": \"PerformanceAndHealth\" }\n\tresult['common.nodePlatform'] = nodePlatform;\n\t// __GDPR__COMMON__ \"common.nodeArch\" : { \"classification\": \"SystemMetaData\", \"purpose\": \"PerformanceAndHealth\" }\n\tresult['common.nodeArch'] = arch;\n\t// __GDPR__COMMON__ \"common.product\" : { \"classification\": \"SystemMetaData\", \"purpose\": \"PerformanceAndHealth\" }\n\tresult['common.product'] = product || 'desktop';\n\n\tif (isInternalTelemetry) {\n\t\t// __GDPR__COMMON__ \"common.msftInternal\" : { \"classification\": \"SystemMetaData\", \"purpose\": \"FeatureInsight\", \"isMeasurement\": true }\n\t\tresult['common.msftInternal'] = isInternalTelemetry;\n\t}\n\n\t// dynamic properties which value differs on each call\n\tlet seq = 0;\n\tconst startTime = Date.now();\n\tObject.defineProperties(result, {\n\t\t// __GDPR__COMMON__ \"timestamp\" : { \"classification\": \"SystemMetaData\", \"purpose\": \"FeatureInsight\" }\n\t\t'timestamp': {\n\t\t\tget: () => new Date(),\n\t\t\tenumerable: true\n\t\t},\n\t\t// __GDPR__COMMON__ \"common.timesincesessionstart\" : { \"classification\": \"SystemMetaData\", \"purpose\": \"FeatureInsight\", \"isMeasurement\": true }\n\t\t'common.timesincesessionstart': {\n\t\t\tget: () => Date.now() - startTime,\n\t\t\tenumerable: true\n\t\t},\n\t\t// __GDPR__COMMON__ \"common.sequence\" : { \"classification\": \"SystemMetaData\", \"purpose\": \"FeatureInsight\", \"isMeasurement\": true }\n\t\t'common.sequence': {\n\t\t\tget: () => seq++,\n\t\t\tenumerable: true\n\t\t}\n\t});\n\n\tif (isLinuxSnap) {\n\t\t// __GDPR__COMMON__ \"common.snap\" : { \"classification\": \"SystemMetaData\", \"purpose\": \"FeatureInsight\" }\n\t\tresult['common.snap'] = 'true';\n\t}\n\n\tconst platformDetail = getPlatformDetail(hostname);\n\n\tif (platformDetail) {\n\t\t// __GDPR__COMMON__ \"common.platformDetail\" : { \"classification\": \"SystemMetaData\", \"purpose\": \"FeatureInsight\" }\n\t\tresult['common.platformDetail'] = platformDetail;\n\t}\n\n\treturn result;\n}\n\nexport function verifyMicrosoftInternalDomain(domainList: readonly string[]): boolean {\n\tconst userDnsDomain = env['USERDNSDOMAIN'];\n\tif (!userDnsDomain) {\n\t\treturn false;\n\t}\n\n\tconst domain = userDnsDomain.toLowerCase();\n\treturn domainList.some(msftDomain => domain === msftDomain);\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { errorHandler, ErrorNoTelemetry } from 'vs/base/common/errors';\nimport { DisposableStore, toDisposable } from 'vs/base/common/lifecycle';\nimport { safeStringify } from 'vs/base/common/objects';\nimport { FileOperationError } from 'vs/platform/files/common/files';\nimport { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';\n\ntype ErrorEventFragment = {\n\towner: 'lramos15, sbatten';\n\tcomment: 'Whenever an error in VS Code is thrown.';\n\tcallstack: { classification: 'CallstackOrException'; purpose: 'PerformanceAndHealth'; comment: 'The callstack of the error.' };\n\tmsg?: { classification: 'CallstackOrException'; purpose: 'PerformanceAndHealth'; comment: 'The message of the error. Normally the first line int the callstack.' };\n\tfile?: { classification: 'CallstackOrException'; purpose: 'PerformanceAndHealth'; comment: 'The file the error originated from.' };\n\tline?: { classification: 'CallstackOrException'; purpose: 'PerformanceAndHealth'; isMeasurement: true; comment: 'The line the error originate on.' };\n\tcolumn?: { classification: 'CallstackOrException'; purpose: 'PerformanceAndHealth'; isMeasurement: true; comment: 'The column of the line which the error orginated on.' };\n\tuncaught_error_name?: { classification: 'CallstackOrException'; purpose: 'PerformanceAndHealth'; comment: 'If the error is uncaught what is the error type' };\n\tuncaught_error_msg?: { classification: 'CallstackOrException'; purpose: 'PerformanceAndHealth'; comment: 'If the error is uncaught this is just msg but for uncaught errors.' };\n\tcount?: { classification: 'CallstackOrException'; purpose: 'PerformanceAndHealth'; isMeasurement: true; comment: 'How many times this error has been thrown' };\n};\nexport interface ErrorEvent {\n\tcallstack: string;\n\tmsg?: string;\n\tfile?: string;\n\tline?: number;\n\tcolumn?: number;\n\tuncaught_error_name?: string;\n\tuncaught_error_msg?: string;\n\tcount?: number;\n}\n\nexport namespace ErrorEvent {\n\texport function compare(a: ErrorEvent, b: ErrorEvent) {\n\t\tif (a.callstack < b.callstack) {\n\t\t\treturn -1;\n\t\t} else if (a.callstack > b.callstack) {\n\t\t\treturn 1;\n\t\t}\n\t\treturn 0;\n\t}\n}\n\nexport default abstract class BaseErrorTelemetry {\n\n\tpublic static ERROR_FLUSH_TIMEOUT: number = 5 * 1000;\n\n\tprivate _telemetryService: ITelemetryService;\n\tprivate _flushDelay: number;\n\tprivate _flushHandle: any = -1;\n\tprivate _buffer: ErrorEvent[] = [];\n\tprotected readonly _disposables = new DisposableStore();\n\n\tconstructor(telemetryService: ITelemetryService, flushDelay = BaseErrorTelemetry.ERROR_FLUSH_TIMEOUT) {\n\t\tthis._telemetryService = telemetryService;\n\t\tthis._flushDelay = flushDelay;\n\n\t\t// (1) check for unexpected but handled errors\n\t\tconst unbind = errorHandler.addListener((err) => this._onErrorEvent(err));\n\t\tthis._disposables.add(toDisposable(unbind));\n\n\t\t// (2) install implementation-specific error listeners\n\t\tthis.installErrorListeners();\n\t}\n\n\tdispose() {\n\t\tclearTimeout(this._flushHandle);\n\t\tthis._flushBuffer();\n\t\tthis._disposables.dispose();\n\t}\n\n\tprotected installErrorListeners(): void {\n\t\t// to override\n\t}\n\n\tprivate _onErrorEvent(err: any): void {\n\n\t\tif (!err || err.code) {\n\t\t\treturn;\n\t\t}\n\n\t\t// unwrap nested errors from loader\n\t\tif (err.detail && err.detail.stack) {\n\t\t\terr = err.detail;\n\t\t}\n\n\t\t// If it's the no telemetry error it doesn't get logged\n\t\t// TOOD @lramos15 hacking in FileOperation error because it's too messy to adopt ErrorNoTelemetry. A better solution should be found\n\t\tif (ErrorNoTelemetry.isErrorNoTelemetry(err) || err instanceof FileOperationError || (typeof err?.message === 'string' && err.message.includes('Unable to read file'))) {\n\t\t\treturn;\n\t\t}\n\n\t\t// work around behavior in workerServer.ts that breaks up Error.stack\n\t\tconst callstack = Array.isArray(err.stack) ? err.stack.join('\\n') : err.stack;\n\t\tconst msg = err.message ? err.message : safeStringify(err);\n\n\t\t// errors without a stack are not useful telemetry\n\t\tif (!callstack) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._enqueue({ msg, callstack });\n\t}\n\n\tprotected _enqueue(e: ErrorEvent): void {\n\n\t\tconst idx = binarySearch(this._buffer, e, ErrorEvent.compare);\n\t\tif (idx < 0) {\n\t\t\te.count = 1;\n\t\t\tthis._buffer.splice(~idx, 0, e);\n\t\t} else {\n\t\t\tif (!this._buffer[idx].count) {\n\t\t\t\tthis._buffer[idx].count = 0;\n\t\t\t}\n\t\t\tthis._buffer[idx].count! += 1;\n\t\t}\n\n\t\tif (this._flushHandle === -1) {\n\t\t\tthis._flushHandle = setTimeout(() => {\n\t\t\t\tthis._flushBuffer();\n\t\t\t\tthis._flushHandle = -1;\n\t\t\t}, this._flushDelay);\n\t\t}\n\t}\n\n\tprivate _flushBuffer(): void {\n\t\tfor (const error of this._buffer) {\n\t\t\ttype UnhandledErrorClassification = {} & ErrorEventFragment;\n\t\t\tthis._telemetryService.publicLogError2('UnhandledError', error);\n\t\t}\n\t\tthis._buffer.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\nimport { mainWindow } from 'vs/base/browser/window';\nimport { ErrorNoTelemetry } from 'vs/base/common/errors';\nimport { toDisposable } from 'vs/base/common/lifecycle';\nimport BaseErrorTelemetry, { ErrorEvent } from 'vs/platform/telemetry/common/errorTelemetry';\n\nexport default class ErrorTelemetry extends BaseErrorTelemetry {\n\tprotected override installErrorListeners(): void {\n\t\tlet oldOnError: OnErrorEventHandler;\n\t\tconst that = this;\n\t\tif (typeof mainWindow.onerror === 'function') {\n\t\t\toldOnError = mainWindow.onerror;\n\t\t}\n\t\tmainWindow.onerror = function (message: Event | string, filename?: string, line?: number, column?: number, error?: Error) {\n\t\t\tthat._onUncaughtError(message as string, filename as string, line as number, column, error);\n\t\t\toldOnError?.apply(this, [message, filename, line, column, error]);\n\t\t};\n\t\tthis._disposables.add(toDisposable(() => {\n\t\t\tif (oldOnError) {\n\t\t\t\tmainWindow.onerror = oldOnError;\n\t\t\t}\n\t\t}));\n\t}\n\n\tprivate _onUncaughtError(msg: string, file: string, line: number, column?: number, err?: any): void {\n\t\tconst data: ErrorEvent = {\n\t\t\tcallstack: msg,\n\t\t\tmsg,\n\t\t\tfile,\n\t\t\tline,\n\t\t\tcolumn\n\t\t};\n\n\t\tif (err) {\n\t\t\t// If it's the no telemetry error it doesn't get logged\n\t\t\tif (ErrorNoTelemetry.isErrorNoTelemetry(err)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst { name, message, stack } = err;\n\t\t\tdata.uncaught_error_name = name;\n\t\t\tif (message) {\n\t\t\t\tdata.uncaught_error_msg = message;\n\t\t\t}\n\t\t\tif (stack) {\n\t\t\t\tdata.callstack = Array.isArray(err.stack)\n\t\t\t\t\t? err.stack = err.stack.join('\\n')\n\t\t\t\t\t: err.stack;\n\t\t\t}\n\t\t}\n\n\t\tthis._enqueue(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 { 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 ITelemetryData {\n\tfrom?: string;\n\ttarget?: string;\n\t[key: string]: any;\n}\n\nexport interface ITelemetryService {\n\n\treadonly _serviceBrand: undefined;\n\n\treadonly telemetryLevel: TelemetryLevel;\n\n\treadonly sessionId: string;\n\treadonly machineId: string;\n\treadonly sqmId: string;\n\treadonly firstSessionDate: string;\n\treadonly msftInternal?: boolean;\n\n\t/**\n\t * Whether error telemetry will get sent. If false, `publicLogError` will no-op.\n\t */\n\treadonly sendErrorTelemetry: boolean;\n\n\t/**\n\t * @deprecated Use publicLog2 and the typescript GDPR annotation where possible\n\t */\n\tpublicLog(eventName: string, data?: ITelemetryData): void;\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\t/**\n\t * @deprecated Use publicLogError2 and the typescript GDPR annotation where possible\n\t */\n\tpublicLogError(errorEventName: string, data?: ITelemetryData): void;\n\n\tpublicLogError2> = never, T extends IGDPRProperty = never>(eventName: string, data?: StrictPropertyCheck): void;\n\n\tsetExperimentProperty(name: string, value: string): void;\n}\n\nexport interface ITelemetryEndpoint {\n\tid: string;\n\taiKey: string;\n\tsendErrorTelemetry: boolean;\n}\n\nexport const ICustomEndpointTelemetryService = createDecorator('customEndpointTelemetryService');\n\nexport interface ICustomEndpointTelemetryService {\n\treadonly _serviceBrand: undefined;\n\n\tpublicLog(endpoint: ITelemetryEndpoint, eventName: string, data?: ITelemetryData): void;\n\tpublicLogError(endpoint: ITelemetryEndpoint, errorEventName: string, data?: ITelemetryData): void;\n}\n\n// Keys\nexport const currentSessionDateStorageKey = 'telemetry.currentSessionDate';\nexport const firstSessionDateStorageKey = 'telemetry.firstSessionDate';\nexport const lastSessionDateStorageKey = 'telemetry.lastSessionDate';\nexport const machineIdKey = 'telemetry.machineId';\nexport const sqmIdKey = 'telemetry.sqmId';\n\n// Configuration Keys\nexport const TELEMETRY_SECTION_ID = 'telemetry';\nexport const TELEMETRY_SETTING_ID = 'telemetry.telemetryLevel';\nexport const TELEMETRY_CRASH_REPORTER_SETTING_ID = 'telemetry.enableCrashReporter';\nexport const TELEMETRY_OLD_SETTING_ID = 'telemetry.enableTelemetry';\n\nexport const enum TelemetryLevel {\n\tNONE = 0,\n\tCRASH = 1,\n\tERROR = 2,\n\tUSAGE = 3\n}\n\nexport const enum TelemetryConfiguration {\n\tOFF = 'off',\n\tCRASH = 'crash',\n\tERROR = 'error',\n\tON = 'all'\n}\n\nexport interface ICommonProperties {\n\t[name: string]: string | boolean | 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 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\tid: string;\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\tmenuId?: MenuId;\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\n/**\n * Registers a diff editor contribution. Diff editor contributions have a lifecycle which\n * is bound to a specific diff editor instance.\n */\nexport function registerDiffEditorContribution(id: string, ctor: { new(editor: IDiffEditor, ...services: Services): IEditorContribution }): void {\n\tEditorContributionRegistry.INSTANCE.registerDiffEditorContribution(id, ctor);\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 registerDiffEditorContribution(id: string, ctor: { new(editor: IDiffEditor, ...services: Services): IEditorContribution }): void {\n\t\tthis.diffEditorContributions.push({ id, ctor: ctor as DiffEditorContributionCtor });\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.revealPrimaryCursor(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.revealPrimaryCursor(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.revealPrimaryCursor(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.revealPrimaryCursor(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.revealPrimaryCursor(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.revealPrimaryCursor(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.revealPrimaryCursor(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.revealPrimaryCursor(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.revealPrimaryCursor(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.revealPrimaryCursor(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.revealPrimaryCursor(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.revealPrimaryCursor(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.revealPrimaryCursor(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\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'; isMeasurement: true; comment: 'To understand if the new diff algorithm is slower/faster than the old one' };\n\t\t\ttimedOut: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'To understand how often the new diff algorithm times out' };\n\t\t\tdetectedMoves: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; 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\tpublic setHoveredMovedText(movedText: MovedText | undefined): void {\n\t\tthis._hoveredMovedText.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\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 { Disposable } from 'vs/base/common/lifecycle';\nimport { observableFromEvent, observableValue, transaction } from 'vs/base/common/observable';\nimport { mapObservableArrayCached } from 'vs/base/common/observableInternal/utils';\nimport { DiffEditorOptions } from 'vs/editor/browser/widget/diffEditor/diffEditorOptions';\nimport { DiffEditorViewModel } from 'vs/editor/browser/widget/diffEditor/diffEditorViewModel';\nimport { IDocumentDiffItem, IMultiDiffEditorModel, LazyPromise } from 'vs/editor/browser/widget/multiDiffEditorWidget/model';\nimport { IDiffEditorOptions } from 'vs/editor/common/config/editorOptions';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { IDiffEditorViewModel } from 'vs/editor/common/editorCommon';\nimport { IModelService } from 'vs/editor/common/services/model';\nimport { ContextKeyValue } from 'vs/platform/contextkey/common/contextkey';\nimport { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\nimport { URI } from 'vs/base/common/uri';\n\nexport class MultiDiffEditorViewModel extends Disposable {\n\tprivate readonly _documents = observableFromEvent(this.model.onDidChange, /** @description MultiDiffEditorViewModel.documents */() => this.model.documents);\n\n\tpublic readonly items = mapObservableArrayCached(this, this._documents, (d, store) => store.add(this._instantiationService.createInstance(DocumentDiffItemViewModel, d)))\n\t\t.recomputeInitiallyAndOnChange(this._store);\n\n\tpublic readonly activeDiffItem = observableValue(this, undefined);\n\n\tpublic async waitForDiffs(): Promise {\n\t\tfor (const d of this.items.get()) {\n\t\t\tawait d.diffEditorViewModel.waitForDiff();\n\t\t}\n\t}\n\n\tpublic collapseAll(): void {\n\t\ttransaction(tx => {\n\t\t\tfor (const d of this.items.get()) {\n\t\t\t\td.collapsed.set(true, tx);\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic expandAll(): void {\n\t\ttransaction(tx => {\n\t\t\tfor (const d of this.items.get()) {\n\t\t\t\td.collapsed.set(false, tx);\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic get contextKeys(): Record | undefined {\n\t\treturn this.model.contextKeys;\n\t}\n\n\tconstructor(\n\t\tpublic readonly model: IMultiDiffEditorModel,\n\t\tprivate readonly _instantiationService: IInstantiationService,\n\t) {\n\t\tsuper();\n\t}\n}\n\nexport class DocumentDiffItemViewModel extends Disposable {\n\tpublic readonly diffEditorViewModel: IDiffEditorViewModel;\n\tpublic readonly collapsed = observableValue(this, false);\n\n\tpublic readonly lastTemplateData = observableValue<{ contentHeight: number; selections: Selection[] | undefined }>(\n\t\tthis,\n\t\t{ contentHeight: 500, selections: undefined, }\n\t);\n\n\tpublic get originalUri(): URI | undefined { return this.entry.value!.original?.uri; }\n\tpublic get modifiedUri(): URI | undefined { return this.entry.value!.modified?.uri; }\n\n\tconstructor(\n\t\tpublic readonly entry: LazyPromise,\n\t\t@IInstantiationService private readonly _instantiationService: IInstantiationService,\n\t\t@IModelService private readonly _modelService: IModelService,\n\t) {\n\t\tsuper();\n\n\t\tfunction updateOptions(options: IDiffEditorOptions): IDiffEditorOptions {\n\t\t\treturn {\n\t\t\t\t...options,\n\t\t\t\thideUnchangedRegions: {\n\t\t\t\t\tenabled: true,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\tconst options = new DiffEditorOptions(updateOptions(this.entry.value!.options || {}));\n\t\tif (this.entry.value!.onOptionsDidChange) {\n\t\t\tthis._register(this.entry.value!.onOptionsDidChange(() => {\n\t\t\t\toptions.updateOptions(updateOptions(this.entry.value!.options || {}));\n\t\t\t}));\n\t\t}\n\n\t\tconst originalTextModel = this.entry.value!.original ?? this._register(this._modelService.createModel('', null));\n\t\tconst modifiedTextModel = this.entry.value!.modified ?? this._register(this._modelService.createModel('', null));\n\n\t\tthis.diffEditorViewModel = this._register(this._instantiationService.createInstance(DiffEditorViewModel, {\n\t\t\toriginal: originalTextModel,\n\t\t\tmodified: modifiedTextModel,\n\t\t}, options));\n\t}\n\n\tpublic getKey(): string {\n\t\treturn JSON.stringify([\n\t\t\tthis.originalUri?.toString(),\n\t\t\tthis.modifiedUri?.toString()\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 { 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.tabSize,\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';\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 refactorPreviewCommandId = 'editor.action.refactor.preview';\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 CodeActionKind(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 CodeActionKind(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?: CodeActionKind\n): languages.Command | undefined {\n\tif (!provider.documentation) {\n\t\treturn undefined;\n\t}\n\n\tconst documentation = provider.documentation.map(entry => ({ kind: new CodeActionKind(entry.kind), command: entry.command }));\n\n\tif (only) {\n\t\tlet currentBest: { readonly kind: CodeActionKind; 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 CodeActionKind(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: 'mjbvz';\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 CodeActionKind(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 { 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: CodeActionKind;\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: CodeActionKind.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 CodeActionKind(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 { 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 { IConfigurationService } from 'vs/platform/configuration/common/configuration';\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 CodeActionKind(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\tthis.setState(new CodeActionsState.Triggered(trigger.trigger, startPosition, actions));\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 type { 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\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\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 { coalesce } from 'vs/base/common/arrays';\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 { 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\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());\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);\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);\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\nasync function executeProvider(provider: HoverProvider, ordinal: number, model: ITextModel, position: Position, token: CancellationToken): Promise {\n\ttry {\n\t\tconst result = await Promise.resolve(provider.provideHover(model, position, token));\n\t\tif (result && isValid(result)) {\n\t\t\treturn new HoverProviderResult(provider, result, ordinal);\n\t\t}\n\t} catch (err) {\n\t\tonUnexpectedExternalError(err);\n\t}\n\treturn undefined;\n}\n\nexport function getHover(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 getHoverPromise(registry: LanguageFeatureRegistry, model: ITextModel, position: Position, token: CancellationToken): Promise {\n\treturn getHover(registry, model, position, token).map(item => item.hover).toPromise();\n}\n\nregisterModelAndPositionCommand('_executeHoverProvider', (accessor, model, position) => {\n\tconst languageFeaturesService = accessor.get(ILanguageFeaturesService);\n\treturn getHoverPromise(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 * as dom from 'vs/base/browser/dom';\nimport { asArray } from 'vs/base/common/arrays';\nimport { AsyncIterableObject } from 'vs/base/common/async';\nimport { CancellationToken } from 'vs/base/common/cancellation';\nimport { IMarkdownString, isEmptyMarkdownString, MarkdownString } from 'vs/base/common/htmlContent';\nimport { DisposableStore, IDisposable } from 'vs/base/common/lifecycle';\nimport { MarkdownRenderer } from 'vs/editor/browser/widget/markdownRenderer/browser/markdownRenderer';\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 } from 'vs/editor/common/model';\nimport { ILanguageService } from 'vs/editor/common/languages/language';\nimport { getHover } from 'vs/editor/contrib/hover/browser/getHover';\nimport { HoverAnchor, HoverAnchorType, 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';\n\nconst $ = dom.$;\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) { }\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\nexport class MarkdownHoverParticipant implements IEditorHoverParticipant {\n\n\tpublic readonly hoverOrdinal: number = 3;\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) { }\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\tif (!this._languageFeaturesService.hoverProvider.has(model)) {\n\t\t\treturn AsyncIterableObject.EMPTY;\n\t\t}\n\n\t\tconst position = new Position(anchor.range.startLineNumber, anchor.range.startColumn);\n\t\treturn getHover(this._languageFeaturesService.hoverProvider, model, position, token)\n\t\t\t.filter(item => !isEmptyMarkdownString(item.hover.contents))\n\t\t\t.map(item => {\n\t\t\t\tconst rng = item.hover.range ? Range.lift(item.hover.range) : anchor.range;\n\t\t\t\treturn new MarkdownHover(this, rng, item.hover.contents, false, item.ordinal);\n\t\t\t});\n\t}\n\n\tpublic renderHoverParts(context: IEditorHoverRenderContext, hoverParts: MarkdownHover[]): IDisposable {\n\t\treturn renderMarkdownHovers(context, hoverParts, this._editor, this._languageService, this._openerService);\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((a, b) => a.ordinal - b.ordinal);\n\n\tconst disposables = new DisposableStore();\n\tfor (const hoverPart of hoverParts) {\n\t\tfor (const contents of hoverPart.contents) {\n\t\t\tif (isEmptyMarkdownString(contents)) {\n\t\t\t\tcontinue;\n\t\t\t}\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 renderer = disposables.add(new MarkdownRenderer({ editor }, languageService, openerService));\n\t\t\tdisposables.add(renderer.onDidRenderAsync(() => {\n\t\t\t\thoverContentsElement.className = 'hover-contents code-hover-contents';\n\t\t\t\tcontext.onContentsChanged();\n\t\t\t}));\n\t\t\tconst renderedContents = disposables.add(renderer.render(contents));\n\t\t\thoverContentsElement.appendChild(renderedContents.element);\n\t\t\tcontext.fragment.appendChild(markdownHoverElement);\n\t\t}\n\t}\n\treturn disposables;\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { EditOperation, 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/browser/indentUtils';\nimport * as nls from 'vs/nls';\nimport { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';\nimport { normalizeIndentation } from 'vs/editor/common/core/indentation';\nimport { getGoodIndentForLine, getIndentMetadata } from 'vs/editor/common/languages/autoIndent';\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\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});\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});\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});\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});\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});\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});\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});\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});\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.revealPrimaryCursor(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';\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\tconst selections = editor.getSelections() || [];\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\n\t\tfor (const selection of editor.getSelections()) {\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, endCursorState);\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 command = new TrimTrailingWhitespaceCommand(selection, cursors);\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\tselectionStartColumn: 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 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 (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\tpublic static get(editor: ICodeEditor): LongLinesHelper | null {\n\t\treturn editor.getContribution(LongLinesHelper.ID);\n\t}\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\tisVisible() {\n\t\treturn this._visible.get();\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));\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, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position {\n\t\treturn super._move(getMapForWordSeparators(EditorOptions.wordSeparators.defaultValue), 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, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position {\n\t\treturn super._move(getMapForWordSeparators(EditorOptions.wordSeparators.defaultValue), 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, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position {\n\t\treturn super._move(getMapForWordSeparators(EditorOptions.wordSeparators.defaultValue), 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, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position {\n\t\treturn super._move(getMapForWordSeparators(EditorOptions.wordSeparators.defaultValue), 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));\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));\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 { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle';\nimport { FileAccess } from 'vs/base/common/network';\nimport { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';\nimport { IConfigurationService } from 'vs/platform/configuration/common/configuration';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\nimport { Event } from 'vs/base/common/event';\nimport { localize } from 'vs/nls';\nimport { observableFromEvent, derived } from 'vs/base/common/observable';\nimport { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';\n\nexport const IAccessibilitySignalService = createDecorator('accessibilitySignalService');\n\nexport interface IAccessibilitySignalService {\n\treadonly _serviceBrand: undefined;\n\tplaySignal(cue: AccessibilitySignal, options?: IAccessbilitySignalOptions): Promise;\n\tplayAccessibilitySignals(cues: (AccessibilitySignal | { cue: AccessibilitySignal; source: string })[]): Promise;\n\tisSoundEnabled(cue: AccessibilitySignal): boolean;\n\tisAnnouncementEnabled(cue: AccessibilitySignal): boolean;\n\tonSoundEnabledChanged(cue: AccessibilitySignal): Event;\n\tonAnnouncementEnabledChanged(cue: AccessibilitySignal): Event;\n\n\tplaySound(cue: Sound, allowManyInParallel?: boolean): Promise;\n\tplaySignalLoop(cue: AccessibilitySignal, milliseconds: number): IDisposable;\n}\n\nexport interface IAccessbilitySignalOptions {\n\tallowManyInParallel?: boolean;\n\tsource?: string;\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\nexport class AccessibilitySignalService extends Disposable implements IAccessibilitySignalService {\n\treadonly _serviceBrand: undefined;\n\tprivate readonly sounds: Map = new Map();\n\tprivate readonly screenReaderAttached = observableFromEvent(\n\t\tthis.accessibilityService.onDidChangeScreenReaderOptimized,\n\t\t() => /** @description accessibilityService.onDidChangeScreenReaderOptimized */ this.accessibilityService.isScreenReaderOptimized()\n\t);\n\tprivate readonly sentTelemetry = new Set();\n\n\tconstructor(\n\t\t@IConfigurationService private readonly configurationService: IConfigurationService,\n\t\t@IAccessibilityService private readonly accessibilityService: IAccessibilityService,\n\t\t@ITelemetryService private readonly telemetryService: ITelemetryService,\n\t) {\n\t\tsuper();\n\t}\n\n\tpublic async playSignal(signal: AccessibilitySignal, options: IAccessbilitySignalOptions = {}): Promise {\n\t\tconst alertMessage = signal.announcementMessage;\n\t\tif (this.isAnnouncementEnabled(signal, options.userGesture) && alertMessage) {\n\t\t\tthis.accessibilityService.status(alertMessage);\n\t\t}\n\n\t\tif (this.isSoundEnabled(signal, options.userGesture)) {\n\t\t\tthis.sendSignalTelemetry(signal, options.source);\n\t\t\tawait this.playSound(signal.sound.getSound(), options.allowManyInParallel);\n\t\t}\n\t}\n\n\tpublic async playAccessibilitySignals(cues: (AccessibilitySignal | { cue: AccessibilitySignal; source: string })[]): Promise {\n\t\tfor (const cue of cues) {\n\t\t\tthis.sendSignalTelemetry('cue' in cue ? cue.cue : cue, 'source' in cue ? cue.source : undefined);\n\t\t}\n\t\tconst cueArray = cues.map(c => 'cue' in c ? c.cue : c);\n\t\tconst alerts = cueArray.filter(cue => this.isAnnouncementEnabled(cue)).map(c => c.announcementMessage);\n\t\tif (alerts.length) {\n\t\t\tthis.accessibilityService.status(alerts.join(', '));\n\t\t}\n\n\t\t// Some sounds are reused. Don't play the same sound twice.\n\t\tconst sounds = new Set(cueArray.filter(cue => this.isSoundEnabled(cue)).map(cue => cue.sound.getSound()));\n\t\tawait Promise.all(Array.from(sounds).map(sound => this.playSound(sound, true)));\n\n\t}\n\n\n\tprivate sendSignalTelemetry(cue: AccessibilitySignal, source: string | undefined): void {\n\t\tconst isScreenReaderOptimized = this.accessibilityService.isScreenReaderOptimized();\n\t\tconst key = cue.name + (source ? `::${source}` : '') + (isScreenReaderOptimized ? '{screenReaderOptimized}' : '');\n\t\t// Only send once per user session\n\t\tif (this.sentTelemetry.has(key) || this.getVolumeInPercent() === 0) {\n\t\t\treturn;\n\t\t}\n\t\tthis.sentTelemetry.add(key);\n\n\t\tthis.telemetryService.publicLog2<{\n\t\t\tsignal: string;\n\t\t\tsource: string;\n\t\t\tisScreenReaderOptimized: boolean;\n\t\t}, {\n\t\t\towner: 'hediet';\n\n\t\t\tsignal: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The signal that was played.' };\n\t\t\tsource: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The source that triggered the signal (e.g. \"diffEditorNavigation\").' };\n\t\t\tisScreenReaderOptimized: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether the user is using a screen reader' };\n\n\t\t\tcomment: 'This data is collected to understand how signals are used and if more signals should be added.';\n\t\t}>('signal.played', {\n\t\t\tsignal: cue.name,\n\t\t\tsource: source ?? '',\n\t\t\tisScreenReaderOptimized,\n\t\t});\n\t}\n\n\tprivate getVolumeInPercent(): number {\n\t\tconst volume = this.configurationService.getValue('accessibilitySignals.volume');\n\t\tif (typeof volume !== 'number') {\n\t\t\treturn 50;\n\t\t}\n\n\t\treturn Math.max(Math.min(volume, 100), 0);\n\t}\n\n\tprivate readonly playingSounds = new Set();\n\n\tpublic async playSound(sound: Sound, allowManyInParallel = false): Promise {\n\t\tif (!allowManyInParallel && this.playingSounds.has(sound)) {\n\t\t\treturn;\n\t\t}\n\t\tthis.playingSounds.add(sound);\n\t\tconst url = FileAccess.asBrowserUri(`vs/platform/accessibilitySignal/browser/media/${sound.fileName}`).toString(true);\n\n\t\ttry {\n\t\t\tconst sound = this.sounds.get(url);\n\t\t\tif (sound) {\n\t\t\t\tsound.volume = this.getVolumeInPercent() / 100;\n\t\t\t\tsound.currentTime = 0;\n\t\t\t\tawait sound.play();\n\t\t\t} else {\n\t\t\t\tconst playedSound = await playAudio(url, this.getVolumeInPercent() / 100);\n\t\t\t\tthis.sounds.set(url, playedSound);\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tif (!e.message.includes('play() can only be initiated by a user gesture')) {\n\t\t\t\t// tracking this issue in #178642, no need to spam the console\n\t\t\t\tconsole.error('Error while playing sound', e);\n\t\t\t}\n\t\t} finally {\n\t\t\tthis.playingSounds.delete(sound);\n\t\t}\n\t}\n\n\tpublic playSignalLoop(signal: AccessibilitySignal, milliseconds: number): IDisposable {\n\t\tlet playing = true;\n\t\tconst playSound = () => {\n\t\t\tif (playing) {\n\t\t\t\tthis.playSignal(signal, { allowManyInParallel: true }).finally(() => {\n\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\tif (playing) {\n\t\t\t\t\t\t\tplaySound();\n\t\t\t\t\t\t}\n\t\t\t\t\t}, milliseconds);\n\t\t\t\t});\n\t\t\t}\n\t\t};\n\t\tplaySound();\n\t\treturn toDisposable(() => playing = false);\n\t}\n\n\tprivate readonly obsoleteAccessibilitySignalsEnabled = observableFromEvent(\n\t\tEvent.filter(this.configurationService.onDidChangeConfiguration, (e) =>\n\t\t\te.affectsConfiguration('accessibilitySignals.enabled')\n\t\t),\n\t\t() => /** @description config: accessibilitySignals.enabled */ this.configurationService.getValue<'on' | 'off' | 'auto' | 'userGesture' | 'always' | 'never'>('accessibilitySignals.enabled')\n\t);\n\n\tprivate readonly isSoundEnabledCache = new Cache((event: { readonly signal: AccessibilitySignal; readonly userGesture?: boolean }) => {\n\t\tconst settingObservable = observableFromEvent(\n\t\t\tEvent.filter(this.configurationService.onDidChangeConfiguration, (e) =>\n\t\t\t\te.affectsConfiguration(event.signal.legacySoundSettingsKey) || e.affectsConfiguration(event.signal.settingsKey)\n\t\t\t),\n\t\t\t() => this.configurationService.getValue<'on' | 'off' | 'auto' | 'userGesture' | 'always' | 'never'>(event.signal.settingsKey + '.sound')\n\t\t);\n\t\treturn derived(reader => {\n\t\t\t/** @description sound enabled */\n\t\t\tconst setting = settingObservable.read(reader);\n\t\t\tif (\n\t\t\t\tsetting === 'on' ||\n\t\t\t\t(setting === 'auto' && this.screenReaderAttached.read(reader))\n\t\t\t) {\n\t\t\t\treturn true;\n\t\t\t} else if (setting === 'always' || setting === 'userGesture' && event.userGesture) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tconst obsoleteSetting = this.obsoleteAccessibilitySignalsEnabled.read(reader);\n\t\t\tif (\n\t\t\t\tobsoleteSetting === 'on' ||\n\t\t\t\t(obsoleteSetting === 'auto' && this.screenReaderAttached.read(reader))\n\t\t\t) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t});\n\t}, JSON.stringify);\n\n\tprivate readonly isAnnouncementEnabledCache = new Cache((event: { readonly signal: AccessibilitySignal; readonly userGesture?: boolean }) => {\n\t\tconst settingObservable = observableFromEvent(\n\t\t\tEvent.filter(this.configurationService.onDidChangeConfiguration, (e) =>\n\t\t\t\te.affectsConfiguration(event.signal.legacyAnnouncementSettingsKey!) || e.affectsConfiguration(event.signal.settingsKey)\n\t\t\t),\n\t\t\t() => event.signal.announcementMessage ? this.configurationService.getValue<'auto' | 'off' | 'userGesture' | 'always' | 'never'>(event.signal.settingsKey + '.announcement') : false\n\t\t);\n\t\treturn derived(reader => {\n\t\t\t/** @description alert enabled */\n\t\t\tconst setting = settingObservable.read(reader);\n\t\t\tif (\n\t\t\t\t!this.screenReaderAttached.read(reader)\n\t\t\t) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn setting === 'auto' || setting === 'always' || setting === 'userGesture' && event.userGesture;\n\t\t});\n\t}, JSON.stringify);\n\n\tpublic isAnnouncementEnabled(signal: AccessibilitySignal, userGesture?: boolean): boolean {\n\t\tif (!signal.announcementMessage) {\n\t\t\treturn false;\n\t\t}\n\t\treturn this.isAnnouncementEnabledCache.get({ signal, userGesture }).get() ?? false;\n\t}\n\n\tpublic isSoundEnabled(signal: AccessibilitySignal, userGesture?: boolean): boolean {\n\t\treturn this.isSoundEnabledCache.get({ signal, userGesture }).get() ?? false;\n\t}\n\n\tpublic onSoundEnabledChanged(signal: AccessibilitySignal): Event {\n\t\treturn Event.fromObservableLight(this.isSoundEnabledCache.get({ signal }));\n\t}\n\n\tpublic onAnnouncementEnabledChanged(cue: AccessibilitySignal): Event {\n\t\treturn Event.fromObservableLight(this.isAnnouncementEnabledCache.get({ signal: cue }));\n\t}\n}\n\n\n/**\n * Play the given audio url.\n * @volume value between 0 and 1\n */\nfunction playAudio(url: string, volume: number): Promise {\n\treturn new Promise((resolve, reject) => {\n\t\tconst audio = new Audio(url);\n\t\taudio.volume = volume;\n\t\taudio.addEventListener('ended', () => {\n\t\t\tresolve(audio);\n\t\t});\n\t\taudio.addEventListener('error', (e) => {\n\t\t\t// When the error event fires, ended might not be called\n\t\t\treject(e.error);\n\t\t});\n\t\taudio.play().catch(e => {\n\t\t\t// When play fails, the error event is not fired.\n\t\t\treject(e);\n\t\t});\n\t});\n}\n\nclass Cache {\n\tprivate readonly map = new Map();\n\tconstructor(private readonly getValue: (value: TArg) => TValue, private readonly getKey: (value: TArg) => unknown) {\n\t}\n\n\tpublic get(arg: TArg): TValue {\n\t\tif (this.map.has(arg)) {\n\t\t\treturn this.map.get(arg)!;\n\t\t}\n\n\t\tconst value = this.getValue(arg);\n\t\tconst key = this.getKey(arg);\n\t\tthis.map.set(key, value);\n\t\treturn value;\n\t}\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 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 chatResponsePending = Sound.register({ fileName: 'chatResponsePending.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\n\tprivate constructor(public readonly fileName: string) { }\n}\n\nexport class SoundSource {\n\tconstructor(\n\t\tpublic readonly randomOneOf: Sound[]\n\t) { }\n\n\tpublic getSound(deterministic = false): Sound {\n\t\tif (deterministic || this.randomOneOf.length === 1) {\n\t\t\treturn this.randomOneOf[0];\n\t\t} else {\n\t\t\tconst index = Math.floor(Math.random() * this.randomOneOf.length);\n\t\t\treturn this.randomOneOf[index];\n\t\t}\n\t}\n}\n\nexport const enum AccessibilityAlertSettingId {\n\tSave = 'accessibility.alert.save',\n\tFormat = 'accessibility.alert.format',\n\tClear = 'accessibility.alert.clear',\n\tBreakpoint = 'accessibility.alert.breakpoint',\n\tError = 'accessibility.alert.error',\n\tWarning = 'accessibility.alert.warning',\n\tFoldedArea = 'accessibility.alert.foldedArea',\n\tTerminalQuickFix = 'accessibility.alert.terminalQuickFix',\n\tTerminalBell = 'accessibility.alert.terminalBell',\n\tTerminalCommandFailed = 'accessibility.alert.terminalCommandFailed',\n\tTaskCompleted = 'accessibility.alert.taskCompleted',\n\tTaskFailed = 'accessibility.alert.taskFailed',\n\tChatRequestSent = 'accessibility.alert.chatRequestSent',\n\tNotebookCellCompleted = 'accessibility.alert.notebookCellCompleted',\n\tNotebookCellFailed = 'accessibility.alert.notebookCellFailed',\n\tOnDebugBreak = 'accessibility.alert.onDebugBreak',\n\tNoInlayHints = 'accessibility.alert.noInlayHints',\n\tLineHasBreakpoint = 'accessibility.alert.lineHasBreakpoint',\n\tChatResponsePending = 'accessibility.alert.chatResponsePending'\n}\n\n\nexport class AccessibilitySignal {\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?: AccessibilityAlertSettingId;\n\t\tannouncementMessage?: 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(soundSource, options.name, options.legacySoundSettingsKey, options.settingsKey, options.legacyAnnouncementSettingsKey, options.announcementMessage);\n\t\tAccessibilitySignal._signals.add(signal);\n\t\treturn signal;\n\t}\n\n\tpublic static get allAccessibilitySignals() {\n\t\treturn [...this._signals];\n\t}\n\n\tpublic static readonly error = 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: AccessibilityAlertSettingId.Error,\n\t\tannouncementMessage: localize('accessibility.signals.lineHasError', 'Error'),\n\t\tsettingsKey: 'accessibility.signals.lineHasError'\n\t});\n\tpublic static readonly warning = 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: AccessibilityAlertSettingId.Warning,\n\t\tannouncementMessage: localize('accessibility.signals.lineHasWarning', 'Warning'),\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: AccessibilityAlertSettingId.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: AccessibilityAlertSettingId.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: AccessibilityAlertSettingId.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: AccessibilityAlertSettingId.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: AccessibilityAlertSettingId.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: AccessibilityAlertSettingId.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: AccessibilityAlertSettingId.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: AccessibilityAlertSettingId.TerminalCommandFailed,\n\t\tannouncementMessage: localize('accessibility.signals.terminalCommandFailed', 'Command Failed'),\n\t\tsettingsKey: 'accessibility.signals.terminalCommandFailed'\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: AccessibilityAlertSettingId.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: AccessibilityAlertSettingId.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: AccessibilityAlertSettingId.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: AccessibilityAlertSettingId.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 chatResponsePending = AccessibilitySignal.register({\n\t\tname: localize('accessibilitySignals.chatResponsePending', 'Chat Response Pending'),\n\t\tsound: Sound.chatResponsePending,\n\t\tlegacySoundSettingsKey: 'audioCues.chatResponsePending',\n\t\tlegacyAnnouncementSettingsKey: AccessibilityAlertSettingId.ChatResponsePending,\n\t\tannouncementMessage: localize('accessibility.signals.chatResponsePending', 'Chat Response Pending'),\n\t\tsettingsKey: 'accessibility.signals.chatResponsePending'\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: AccessibilityAlertSettingId.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: AccessibilityAlertSettingId.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: AccessibilityAlertSettingId.Format,\n\t\tannouncementMessage: localize('accessibility.signals.format', 'Format'),\n\t\tsettingsKey: 'accessibility.signals.format'\n\t});\n\n\tprivate constructor(\n\t\tpublic readonly sound: SoundSource,\n\t\tpublic readonly name: string,\n\t\tpublic readonly legacySoundSettingsKey: string,\n\t\tpublic readonly settingsKey: string,\n\t\tpublic readonly legacyAnnouncementSettingsKey?: string,\n\t\tpublic readonly announcementMessage?: 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 { 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 { ButtonBar, IButton } from 'vs/base/browser/ui/button/button';\nimport { ActionRunner, IAction, IActionRunner, SubmenuAction, WorkbenchActionExecutedClassification, WorkbenchActionExecutedEvent } from 'vs/base/common/actions';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { DisposableStore } from 'vs/base/common/lifecycle';\nimport { ThemeIcon } from 'vs/base/common/themables';\nimport { localize } from 'vs/nls';\nimport { MenuId, IMenuService, MenuItemAction } from 'vs/platform/actions/common/actions';\nimport { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';\nimport { IContextMenuService } from 'vs/platform/contextview/browser/contextView';\nimport { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';\nimport { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';\n\nexport type IButtonConfigProvider = (action: IAction) => {\n\tshowIcon?: boolean;\n\tshowLabel?: boolean;\n\tisSecondary?: boolean;\n} | undefined;\n\nexport interface IWorkbenchButtonBarOptions {\n\ttelemetrySource?: string;\n\tbuttonConfigProvider?: IButtonConfigProvider;\n}\n\nexport class WorkbenchButtonBar extends ButtonBar {\n\n\tprotected readonly _store = new DisposableStore();\n\n\tprivate readonly _actionRunner: IActionRunner;\n\tprivate readonly _onDidChange = new Emitter();\n\treadonly onDidChange: Event = this._onDidChange.event;\n\n\n\tconstructor(\n\t\tcontainer: HTMLElement,\n\t\tprivate readonly _options: IWorkbenchButtonBarOptions | undefined,\n\t\t@IContextMenuService private readonly _contextMenuService: IContextMenuService,\n\t\t@IKeybindingService private readonly _keybindingService: IKeybindingService,\n\t\t@ITelemetryService telemetryService: ITelemetryService,\n\t) {\n\t\tsuper(container);\n\n\t\tthis._actionRunner = this._store.add(new ActionRunner());\n\t\tif (_options?.telemetrySource) {\n\t\t\tthis._actionRunner.onDidRun(e => {\n\t\t\t\ttelemetryService.publicLog2(\n\t\t\t\t\t'workbenchActionExecuted',\n\t\t\t\t\t{ id: e.action.id, from: _options.telemetrySource! }\n\t\t\t\t);\n\t\t\t}, undefined, this._store);\n\t\t}\n\t}\n\n\toverride dispose() {\n\t\tthis._onDidChange.dispose();\n\t\tthis._store.dispose();\n\t\tsuper.dispose();\n\t}\n\n\tupdate(actions: IAction[]): void {\n\n\t\tconst conifgProvider: IButtonConfigProvider = this._options?.buttonConfigProvider ?? (() => ({ showLabel: true }));\n\n\t\tthis.clear();\n\n\t\tfor (let i = 0; i < actions.length; i++) {\n\n\t\t\tconst secondary = i > 0;\n\t\t\tconst actionOrSubmenu = actions[i];\n\t\t\tlet action: IAction;\n\t\t\tlet btn: IButton;\n\n\t\t\tif (actionOrSubmenu instanceof SubmenuAction && actionOrSubmenu.actions.length > 0) {\n\t\t\t\tconst [first, ...rest] = actionOrSubmenu.actions;\n\t\t\t\taction = first;\n\t\t\t\tbtn = this.addButtonWithDropdown({\n\t\t\t\t\tsecondary: conifgProvider(action)?.isSecondary ?? secondary,\n\t\t\t\t\tactionRunner: this._actionRunner,\n\t\t\t\t\tactions: rest,\n\t\t\t\t\tcontextMenuProvider: this._contextMenuService,\n\t\t\t\t\tariaLabel: action.label\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\taction = actionOrSubmenu;\n\t\t\t\tbtn = this.addButton({\n\t\t\t\t\tsecondary: conifgProvider(action)?.isSecondary ?? secondary,\n\t\t\t\t\tariaLabel: action.label\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tbtn.enabled = action.enabled;\n\t\t\tbtn.element.classList.add('default-colors');\n\t\t\tif (conifgProvider(action)?.showLabel ?? true) {\n\t\t\t\tbtn.label = action.label;\n\t\t\t} else {\n\t\t\t\tbtn.element.classList.add('monaco-text-button');\n\t\t\t}\n\t\t\tif (conifgProvider(action)?.showIcon) {\n\t\t\t\tif (action instanceof MenuItemAction && ThemeIcon.isThemeIcon(action.item.icon)) {\n\t\t\t\t\tbtn.icon = action.item.icon;\n\t\t\t\t} else if (action.class) {\n\t\t\t\t\tbtn.element.classList.add(...action.class.split(' '));\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst kb = this._keybindingService.lookupKeybinding(action.id);\n\t\t\tif (kb) {\n\t\t\t\tbtn.element.title = localize('labelWithKeybinding', \"{0} ({1})\", action.label, kb.getLabel());\n\t\t\t} else {\n\t\t\t\tbtn.element.title = action.label;\n\n\t\t\t}\n\t\t\tbtn.onDidClick(async () => {\n\t\t\t\tthis._actionRunner.run(action);\n\t\t\t});\n\t\t}\n\t\tthis._onDidChange.fire(this);\n\t}\n}\n\nexport class MenuWorkbenchButtonBar extends WorkbenchButtonBar {\n\n\tconstructor(\n\t\tcontainer: HTMLElement,\n\t\tmenuId: MenuId,\n\t\toptions: IWorkbenchButtonBarOptions | undefined,\n\t\t@IMenuService menuService: IMenuService,\n\t\t@IContextKeyService contextKeyService: IContextKeyService,\n\t\t@IContextMenuService contextMenuService: IContextMenuService,\n\t\t@IKeybindingService keybindingService: IKeybindingService,\n\t\t@ITelemetryService telemetryService: ITelemetryService,\n\t) {\n\t\tsuper(container, options, contextMenuService, keybindingService, telemetryService);\n\n\t\tconst menu = menuService.createMenu(menuId, contextKeyService);\n\t\tthis._store.add(menu);\n\n\t\tconst update = () => {\n\n\t\t\tthis.clear();\n\n\t\t\tconst actions = menu\n\t\t\t\t.getActions({ renderShortTitle: true })\n\t\t\t\t.flatMap(entry => entry[1]);\n\n\t\t\tsuper.update(actions);\n\n\t\t};\n\t\tthis._store.add(menu.onDidChange(update));\n\t\tupdate();\n\t}\n\n\toverride dispose() {\n\t\tsuper.dispose();\n\t}\n\n\toverride update(_actions: IAction[]): void {\n\t\tthrow new Error('Use Menu or WorkbenchButtonBar');\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { cloneAndChange, safeStringify } from 'vs/base/common/objects';\nimport { isObject } from 'vs/base/common/types';\nimport { URI } from 'vs/base/common/uri';\nimport { IConfigurationService } from 'vs/platform/configuration/common/configuration';\nimport { IEnvironmentService } from 'vs/platform/environment/common/environment';\nimport { IProductService } from 'vs/platform/product/common/productService';\nimport { getRemoteName } from 'vs/platform/remote/common/remoteHosts';\nimport { verifyMicrosoftInternalDomain } from 'vs/platform/telemetry/common/commonProperties';\nimport { ICustomEndpointTelemetryService, ITelemetryData, ITelemetryEndpoint, ITelemetryService, TelemetryConfiguration, TelemetryLevel, TELEMETRY_CRASH_REPORTER_SETTING_ID, TELEMETRY_OLD_SETTING_ID, TELEMETRY_SETTING_ID } from 'vs/platform/telemetry/common/telemetry';\n\n/**\n * A special class used to denoting a telemetry value which should not be clean.\n * This is because that value is \"Trusted\" not to contain identifiable information such as paths.\n * NOTE: This is used as an API type as well, and should not be changed.\n */\nexport class TelemetryTrustedValue {\n\t// This is merely used as an identifier as the instance will be lost during serialization over the exthost\n\tpublic readonly isTrustedTelemetryValue = true;\n\tconstructor(public readonly value: T) { }\n}\n\nexport class NullTelemetryServiceShape implements ITelemetryService {\n\tdeclare readonly _serviceBrand: undefined;\n\treadonly telemetryLevel = TelemetryLevel.NONE;\n\treadonly sessionId = 'someValue.sessionId';\n\treadonly machineId = 'someValue.machineId';\n\treadonly sqmId = 'someValue.sqmId';\n\treadonly firstSessionDate = 'someValue.firstSessionDate';\n\treadonly sendErrorTelemetry = false;\n\tpublicLog() { }\n\tpublicLog2() { }\n\tpublicLogError() { }\n\tpublicLogError2() { }\n\tsetExperimentProperty() { }\n}\n\nexport const NullTelemetryService = new NullTelemetryServiceShape();\n\nexport class NullEndpointTelemetryService implements ICustomEndpointTelemetryService {\n\t_serviceBrand: undefined;\n\n\tasync publicLog(_endpoint: ITelemetryEndpoint, _eventName: string, _data?: ITelemetryData): Promise {\n\t\t// noop\n\t}\n\n\tasync publicLogError(_endpoint: ITelemetryEndpoint, _errorEventName: string, _data?: ITelemetryData): Promise {\n\t\t// noop\n\t}\n}\n\nexport const telemetryLogId = 'telemetry';\nexport const extensionTelemetryLogChannelId = 'extensionTelemetryLog';\n\nexport interface ITelemetryAppender {\n\tlog(eventName: string, data: any): void;\n\tflush(): Promise;\n}\n\nexport const NullAppender: ITelemetryAppender = { log: () => null, flush: () => Promise.resolve(null) };\n\n\n/* __GDPR__FRAGMENT__\n\t\"URIDescriptor\" : {\n\t\t\"mimeType\" : { \"classification\": \"SystemMetaData\", \"purpose\": \"FeatureInsight\" },\n\t\t\"scheme\": { \"classification\": \"SystemMetaData\", \"purpose\": \"FeatureInsight\" },\n\t\t\"ext\": { \"classification\": \"SystemMetaData\", \"purpose\": \"FeatureInsight\" },\n\t\t\"path\": { \"classification\": \"SystemMetaData\", \"purpose\": \"FeatureInsight\" }\n\t}\n*/\nexport interface URIDescriptor {\n\tmimeType?: string;\n\tscheme?: string;\n\text?: string;\n\tpath?: string;\n}\n\n/**\n * Determines whether or not we support logging telemetry.\n * This checks if the product is capable of collecting telemetry but not whether or not it can send it\n * For checking the user setting and what telemetry you can send please check `getTelemetryLevel`.\n * This returns true if `--disable-telemetry` wasn't used, the product.json allows for telemetry, and we're not testing an extension\n * If false telemetry is disabled throughout the product\n * @param productService\n * @param environmentService\n * @returns false - telemetry is completely disabled, true - telemetry is logged locally, but may not be sent\n */\nexport function supportsTelemetry(productService: IProductService, environmentService: IEnvironmentService): boolean {\n\t// If it's OSS and telemetry isn't disabled via the CLI we will allow it for logging only purposes\n\tif (!environmentService.isBuilt && !environmentService.disableTelemetry) {\n\t\treturn true;\n\t}\n\treturn !(environmentService.disableTelemetry || !productService.enableTelemetry);\n}\n\n/**\n * Checks to see if we're in logging only mode to debug telemetry.\n * This is if telemetry is enabled and we're in OSS, but no telemetry key is provided so it's not being sent just logged.\n * @param productService\n * @param environmentService\n * @returns True if telemetry is actually disabled and we're only logging for debug purposes\n */\nexport function isLoggingOnly(productService: IProductService, environmentService: IEnvironmentService): boolean {\n\t// If we're testing an extension, log telemetry for debug purposes\n\tif (environmentService.extensionTestsLocationURI) {\n\t\treturn true;\n\t}\n\t// Logging only mode is only for OSS\n\tif (environmentService.isBuilt) {\n\t\treturn false;\n\t}\n\n\tif (environmentService.disableTelemetry) {\n\t\treturn false;\n\t}\n\n\tif (productService.enableTelemetry && productService.aiConfig?.ariaKey) {\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\n/**\n * Determines how telemetry is handled based on the user's configuration.\n *\n * @param configurationService\n * @returns OFF, ERROR, ON\n */\nexport function getTelemetryLevel(configurationService: IConfigurationService): TelemetryLevel {\n\tconst newConfig = configurationService.getValue(TELEMETRY_SETTING_ID);\n\tconst crashReporterConfig = configurationService.getValue(TELEMETRY_CRASH_REPORTER_SETTING_ID);\n\tconst oldConfig = configurationService.getValue(TELEMETRY_OLD_SETTING_ID);\n\n\t// If `telemetry.enableCrashReporter` is false or `telemetry.enableTelemetry' is false, disable telemetry\n\tif (oldConfig === false || crashReporterConfig === false) {\n\t\treturn TelemetryLevel.NONE;\n\t}\n\n\t// Maps new telemetry setting to a telemetry level\n\tswitch (newConfig ?? TelemetryConfiguration.ON) {\n\t\tcase TelemetryConfiguration.ON:\n\t\t\treturn TelemetryLevel.USAGE;\n\t\tcase TelemetryConfiguration.ERROR:\n\t\t\treturn TelemetryLevel.ERROR;\n\t\tcase TelemetryConfiguration.CRASH:\n\t\t\treturn TelemetryLevel.CRASH;\n\t\tcase TelemetryConfiguration.OFF:\n\t\t\treturn TelemetryLevel.NONE;\n\t}\n}\n\nexport interface Properties {\n\t[key: string]: string;\n}\n\nexport interface Measurements {\n\t[key: string]: number;\n}\n\nexport function validateTelemetryData(data?: any): { properties: Properties; measurements: Measurements } {\n\n\tconst properties: Properties = {};\n\tconst measurements: Measurements = {};\n\n\tconst flat: Record = {};\n\tflatten(data, flat);\n\n\tfor (let prop in flat) {\n\t\t// enforce property names less than 150 char, take the last 150 char\n\t\tprop = prop.length > 150 ? prop.substr(prop.length - 149) : prop;\n\t\tconst value = flat[prop];\n\n\t\tif (typeof value === 'number') {\n\t\t\tmeasurements[prop] = value;\n\n\t\t} else if (typeof value === 'boolean') {\n\t\t\tmeasurements[prop] = value ? 1 : 0;\n\n\t\t} else if (typeof value === 'string') {\n\t\t\tif (value.length > 8192) {\n\t\t\t\tconsole.warn(`Telemetry property: ${prop} has been trimmed to 8192, the original length is ${value.length}`);\n\t\t\t}\n\t\t\t//enforce property value to be less than 8192 char, take the first 8192 char\n\t\t\t// https://docs.microsoft.com/en-us/azure/azure-monitor/app/api-custom-events-metrics#limits\n\t\t\tproperties[prop] = value.substring(0, 8191);\n\n\t\t} else if (typeof value !== 'undefined' && value !== null) {\n\t\t\tproperties[prop] = value;\n\t\t}\n\t}\n\n\treturn {\n\t\tproperties,\n\t\tmeasurements\n\t};\n}\n\nconst telemetryAllowedAuthorities = new Set(['ssh-remote', 'dev-container', 'attached-container', 'wsl', 'tunnel', 'codespaces', 'amlext']);\n\nexport function cleanRemoteAuthority(remoteAuthority?: string): string {\n\tif (!remoteAuthority) {\n\t\treturn 'none';\n\t}\n\tconst remoteName = getRemoteName(remoteAuthority);\n\treturn telemetryAllowedAuthorities.has(remoteName) ? remoteName : 'other';\n}\n\nfunction flatten(obj: any, result: { [key: string]: any }, order: number = 0, prefix?: string): void {\n\tif (!obj) {\n\t\treturn;\n\t}\n\n\tfor (const item of Object.getOwnPropertyNames(obj)) {\n\t\tconst value = obj[item];\n\t\tconst index = prefix ? prefix + item : item;\n\n\t\tif (Array.isArray(value)) {\n\t\t\tresult[index] = safeStringify(value);\n\n\t\t} else if (value instanceof Date) {\n\t\t\t// TODO unsure why this is here and not in _getData\n\t\t\tresult[index] = value.toISOString();\n\n\t\t} else if (isObject(value)) {\n\t\t\tif (order < 2) {\n\t\t\t\tflatten(value, result, order + 1, index + '.');\n\t\t\t} else {\n\t\t\t\tresult[index] = safeStringify(value);\n\t\t\t}\n\t\t} else {\n\t\t\tresult[index] = value;\n\t\t}\n\t}\n}\n\n/**\n * Whether or not this is an internal user\n * @param productService The product service\n * @param configService The config servivce\n * @returns true if internal, false otherwise\n */\nexport function isInternalTelemetry(productService: IProductService, configService: IConfigurationService) {\n\tconst msftInternalDomains = productService.msftInternalDomains || [];\n\tconst internalTesting = configService.getValue('telemetry.internalTesting');\n\treturn verifyMicrosoftInternalDomain(msftInternalDomains) || internalTesting;\n}\n\ninterface IPathEnvironment {\n\tappRoot: string;\n\textensionsPath: string;\n\tuserDataPath: string;\n\tuserHome: URI;\n\ttmpDir: URI;\n}\n\nexport function getPiiPathsFromEnvironment(paths: IPathEnvironment): string[] {\n\treturn [paths.appRoot, paths.extensionsPath, paths.userHome.fsPath, paths.tmpDir.fsPath, paths.userDataPath];\n}\n\n//#region Telemetry Cleaning\n\n/**\n * Cleans a given stack of possible paths\n * @param stack The stack to sanitize\n * @param cleanupPatterns Cleanup patterns to remove from the stack\n * @returns The cleaned stack\n */\nfunction anonymizeFilePaths(stack: string, cleanupPatterns: RegExp[]): string {\n\n\t// Fast check to see if it is a file path to avoid doing unnecessary heavy regex work\n\tif (!stack || (!stack.includes('/') && !stack.includes('\\\\'))) {\n\t\treturn stack;\n\t}\n\n\tlet updatedStack = stack;\n\n\tconst cleanUpIndexes: [number, number][] = [];\n\tfor (const regexp of cleanupPatterns) {\n\t\twhile (true) {\n\t\t\tconst result = regexp.exec(stack);\n\t\t\tif (!result) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcleanUpIndexes.push([result.index, regexp.lastIndex]);\n\t\t}\n\t}\n\n\tconst nodeModulesRegex = /^[\\\\\\/]?(node_modules|node_modules\\.asar)[\\\\\\/]/;\n\tconst fileRegex = /(file:\\/\\/)?([a-zA-Z]:(\\\\\\\\|\\\\|\\/)|(\\\\\\\\|\\\\|\\/))?([\\w-\\._]+(\\\\\\\\|\\\\|\\/))+[\\w-\\._]*/g;\n\tlet lastIndex = 0;\n\tupdatedStack = '';\n\n\twhile (true) {\n\t\tconst result = fileRegex.exec(stack);\n\t\tif (!result) {\n\t\t\tbreak;\n\t\t}\n\n\t\t// Check to see if the any cleanupIndexes partially overlap with this match\n\t\tconst overlappingRange = cleanUpIndexes.some(([start, end]) => result.index < end && start < fileRegex.lastIndex);\n\n\t\t// anoynimize user file paths that do not need to be retained or cleaned up.\n\t\tif (!nodeModulesRegex.test(result[0]) && !overlappingRange) {\n\t\t\tupdatedStack += stack.substring(lastIndex, result.index) + '';\n\t\t\tlastIndex = fileRegex.lastIndex;\n\t\t}\n\t}\n\tif (lastIndex < stack.length) {\n\t\tupdatedStack += stack.substr(lastIndex);\n\t}\n\n\treturn updatedStack;\n}\n\n/**\n * Attempts to remove commonly leaked PII\n * @param property The property which will be removed if it contains user data\n * @returns The new value for the property\n */\nfunction removePropertiesWithPossibleUserInfo(property: string): string {\n\t// If for some reason it is undefined we skip it (this shouldn't be possible);\n\tif (!property) {\n\t\treturn property;\n\t}\n\n\tconst userDataRegexes = [\n\t\t{ label: 'Google API Key', regex: /AIza[A-Za-z0-9_\\\\\\-]{35}/ },\n\t\t{ label: 'Slack Token', regex: /xox[pbar]\\-[A-Za-z0-9]/ },\n\t\t{ label: 'GitHub Token', regex: /(gh[psuro]_[a-zA-Z0-9]{36}|github_pat_[a-zA-Z0-9]{22}_[a-zA-Z0-9]{59})/ },\n\t\t{ label: 'Generic Secret', regex: /(key|token|sig|secret|signature|password|passwd|pwd|android:value)[^a-zA-Z0-9]/i },\n\t\t{ label: 'Email', regex: /@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-]+/ } // Regex which matches @*.site\n\t];\n\n\t// Check for common user data in the telemetry events\n\tfor (const secretRegex of userDataRegexes) {\n\t\tif (secretRegex.regex.test(property)) {\n\t\t\treturn ``;\n\t\t}\n\t}\n\n\treturn property;\n}\n\n\n/**\n * Does a best possible effort to clean a data object from any possible PII.\n * @param data The data object to clean\n * @param paths Any additional patterns that should be removed from the data set\n * @returns A new object with the PII removed\n */\nexport function cleanData(data: Record, cleanUpPatterns: RegExp[]): Record {\n\treturn cloneAndChange(data, value => {\n\n\t\t// If it's a trusted value it means it's okay to skip cleaning so we don't clean it\n\t\tif (value instanceof TelemetryTrustedValue || Object.hasOwnProperty.call(value, 'isTrustedTelemetryValue')) {\n\t\t\treturn value.value;\n\t\t}\n\n\t\t// We only know how to clean strings\n\t\tif (typeof value === 'string') {\n\t\t\tlet updatedProperty = value.replaceAll('%20', ' ');\n\n\t\t\t// First we anonymize any possible file paths\n\t\t\tupdatedProperty = anonymizeFilePaths(updatedProperty, cleanUpPatterns);\n\n\t\t\t// Then we do a simple regex replace with the defined patterns\n\t\t\tfor (const regexp of cleanUpPatterns) {\n\t\t\t\tupdatedProperty = updatedProperty.replace(regexp, '');\n\t\t\t}\n\n\t\t\t// Lastly, remove commonly leaked PII\n\t\t\tupdatedProperty = removePropertiesWithPossibleUserInfo(updatedProperty);\n\n\t\t\treturn updatedProperty;\n\t\t}\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 type { IExperimentationTelemetry, ExperimentationService as TASClient, IKeyValueStorage } from 'tas-client-umd';\nimport { TelemetryLevel } from 'vs/platform/telemetry/common/telemetry';\nimport { IConfigurationService } from 'vs/platform/configuration/common/configuration';\nimport { IProductService } from 'vs/platform/product/common/productService';\nimport { getTelemetryLevel } from 'vs/platform/telemetry/common/telemetryUtils';\nimport { AssignmentFilterProvider, ASSIGNMENT_REFETCH_INTERVAL, ASSIGNMENT_STORAGE_KEY, IAssignmentService, TargetPopulation } from 'vs/platform/assignment/common/assignment';\nimport { importAMDNodeModule } from 'vs/amdX';\nimport { IEnvironmentService } from 'vs/platform/environment/common/environment';\n\nexport abstract class BaseAssignmentService implements IAssignmentService {\n\t_serviceBrand: undefined;\n\tprotected tasClient: Promise | undefined;\n\tprivate networkInitialized = false;\n\tprivate overrideInitDelay: Promise;\n\n\tprotected get experimentsEnabled(): boolean {\n\t\treturn true;\n\t}\n\n\tconstructor(\n\t\tprivate readonly machineId: string,\n\t\tprotected readonly configurationService: IConfigurationService,\n\t\tprotected readonly productService: IProductService,\n\t\tprotected readonly environmentService: IEnvironmentService,\n\t\tprotected telemetry: IExperimentationTelemetry,\n\t\tprivate keyValueStorage?: IKeyValueStorage\n\t) {\n\t\tconst isTesting = environmentService.extensionTestsLocationURI !== undefined;\n\t\tif (!isTesting && productService.tasConfig && this.experimentsEnabled && getTelemetryLevel(this.configurationService) === TelemetryLevel.USAGE) {\n\t\t\tthis.tasClient = this.setupTASClient();\n\t\t}\n\n\t\t// For development purposes, configure the delay until tas local tas treatment ovverrides are available\n\t\tconst overrideDelaySetting = this.configurationService.getValue('experiments.overrideDelay');\n\t\tconst overrideDelay = typeof overrideDelaySetting === 'number' ? overrideDelaySetting : 0;\n\t\tthis.overrideInitDelay = new Promise(resolve => setTimeout(resolve, overrideDelay));\n\t}\n\n\tasync getTreatment(name: string): Promise {\n\t\t// For development purposes, allow overriding tas assignments to test variants locally.\n\t\tawait this.overrideInitDelay;\n\t\tconst override = this.configurationService.getValue('experiments.override.' + name);\n\t\tif (override !== undefined) {\n\t\t\treturn override;\n\t\t}\n\n\t\tif (!this.tasClient) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (!this.experimentsEnabled) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tlet result: T | undefined;\n\t\tconst client = await this.tasClient;\n\n\t\t// The TAS client is initialized but we need to check if the initial fetch has completed yet\n\t\t// If it is complete, return a cached value for the treatment\n\t\t// If not, use the async call with `checkCache: true`. This will allow the module to return a cached value if it is present.\n\t\t// Otherwise it will await the initial fetch to return the most up to date value.\n\t\tif (this.networkInitialized) {\n\t\t\tresult = client.getTreatmentVariable('vscode', name);\n\t\t} else {\n\t\t\tresult = await client.getTreatmentVariableAsync('vscode', name, true);\n\t\t}\n\n\t\tresult = client.getTreatmentVariable('vscode', name);\n\t\treturn result;\n\t}\n\n\tprivate async setupTASClient(): Promise {\n\n\t\tconst targetPopulation = this.productService.quality === 'stable' ?\n\t\t\tTargetPopulation.Public : (this.productService.quality === 'exploration' ?\n\t\t\t\tTargetPopulation.Exploration : TargetPopulation.Insiders);\n\n\t\tconst filterProvider = new AssignmentFilterProvider(\n\t\t\tthis.productService.version,\n\t\t\tthis.productService.nameLong,\n\t\t\tthis.machineId,\n\t\t\ttargetPopulation\n\t\t);\n\n\t\tconst tasConfig = this.productService.tasConfig!;\n\t\tconst tasClient = new (await importAMDNodeModule('tas-client-umd', 'lib/tas-client-umd.js')).ExperimentationService({\n\t\t\tfilterProviders: [filterProvider],\n\t\t\ttelemetry: this.telemetry,\n\t\t\tstorageKey: ASSIGNMENT_STORAGE_KEY,\n\t\t\tkeyValueStorage: this.keyValueStorage,\n\t\t\tassignmentContextTelemetryPropertyName: tasConfig.assignmentContextTelemetryPropertyName,\n\t\t\ttelemetryEventName: tasConfig.telemetryEventName,\n\t\t\tendpoint: tasConfig.endpoint,\n\t\t\trefetchInterval: ASSIGNMENT_REFETCH_INTERVAL,\n\t\t});\n\n\t\tawait tasClient.initializePromise;\n\t\ttasClient.initialFetch.then(() => this.networkInitialized = true);\n\n\t\treturn tasClient;\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { compareIgnoreCase } from 'vs/base/common/strings';\nimport { IExtensionIdentifier, IGalleryExtension, ILocalExtension, getTargetPlatform } from 'vs/platform/extensionManagement/common/extensionManagement';\nimport { ExtensionIdentifier, IExtension, TargetPlatform, UNDEFINED_PUBLISHER } from 'vs/platform/extensions/common/extensions';\nimport { IFileService } from 'vs/platform/files/common/files';\nimport { isLinux, platform } from 'vs/base/common/platform';\nimport { URI } from 'vs/base/common/uri';\nimport { getErrorMessage } from 'vs/base/common/errors';\nimport { ILogService } from 'vs/platform/log/common/log';\nimport { arch } from 'vs/base/common/process';\nimport { TelemetryTrustedValue } from 'vs/platform/telemetry/common/telemetryUtils';\n\nexport function areSameExtensions(a: IExtensionIdentifier, b: IExtensionIdentifier): boolean {\n\tif (a.uuid && b.uuid) {\n\t\treturn a.uuid === b.uuid;\n\t}\n\tif (a.id === b.id) {\n\t\treturn true;\n\t}\n\treturn compareIgnoreCase(a.id, b.id) === 0;\n}\n\nconst ExtensionKeyRegex = /^([^.]+\\..+)-(\\d+\\.\\d+\\.\\d+)(-(.+))?$/;\n\nexport class ExtensionKey {\n\n\tstatic create(extension: IExtension | IGalleryExtension): ExtensionKey {\n\t\tconst version = (extension as IExtension).manifest ? (extension as IExtension).manifest.version : (extension as IGalleryExtension).version;\n\t\tconst targetPlatform = (extension as IExtension).manifest ? (extension as IExtension).targetPlatform : (extension as IGalleryExtension).properties.targetPlatform;\n\t\treturn new ExtensionKey(extension.identifier, version, targetPlatform);\n\t}\n\n\tstatic parse(key: string): ExtensionKey | null {\n\t\tconst matches = ExtensionKeyRegex.exec(key);\n\t\treturn matches && matches[1] && matches[2] ? new ExtensionKey({ id: matches[1] }, matches[2], matches[4] as TargetPlatform || undefined) : null;\n\t}\n\n\treadonly id: string;\n\n\tconstructor(\n\t\tidentifier: IExtensionIdentifier,\n\t\treadonly version: string,\n\t\treadonly targetPlatform: TargetPlatform = TargetPlatform.UNDEFINED,\n\t) {\n\t\tthis.id = identifier.id;\n\t}\n\n\ttoString(): string {\n\t\treturn `${this.id}-${this.version}${this.targetPlatform !== TargetPlatform.UNDEFINED ? `-${this.targetPlatform}` : ''}`;\n\t}\n\n\tequals(o: any): boolean {\n\t\tif (!(o instanceof ExtensionKey)) {\n\t\t\treturn false;\n\t\t}\n\t\treturn areSameExtensions(this, o) && this.version === o.version && this.targetPlatform === o.targetPlatform;\n\t}\n}\n\nconst EXTENSION_IDENTIFIER_WITH_VERSION_REGEX = /^([^.]+\\..+)@((prerelease)|(\\d+\\.\\d+\\.\\d+(-.*)?))$/;\nexport function getIdAndVersion(id: string): [string, string | undefined] {\n\tconst matches = EXTENSION_IDENTIFIER_WITH_VERSION_REGEX.exec(id);\n\tif (matches && matches[1]) {\n\t\treturn [adoptToGalleryExtensionId(matches[1]), matches[2]];\n\t}\n\treturn [adoptToGalleryExtensionId(id), undefined];\n}\n\nexport function getExtensionId(publisher: string, name: string): string {\n\treturn `${publisher}.${name}`;\n}\n\nexport function adoptToGalleryExtensionId(id: string): string {\n\treturn id.toLowerCase();\n}\n\nexport function getGalleryExtensionId(publisher: string | undefined, name: string): string {\n\treturn adoptToGalleryExtensionId(getExtensionId(publisher ?? UNDEFINED_PUBLISHER, name));\n}\n\nexport function groupByExtension(extensions: T[], getExtensionIdentifier: (t: T) => IExtensionIdentifier): T[][] {\n\tconst byExtension: T[][] = [];\n\tconst findGroup = (extension: T) => {\n\t\tfor (const group of byExtension) {\n\t\t\tif (group.some(e => areSameExtensions(getExtensionIdentifier(e), getExtensionIdentifier(extension)))) {\n\t\t\t\treturn group;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t};\n\tfor (const extension of extensions) {\n\t\tconst group = findGroup(extension);\n\t\tif (group) {\n\t\t\tgroup.push(extension);\n\t\t} else {\n\t\t\tbyExtension.push([extension]);\n\t\t}\n\t}\n\treturn byExtension;\n}\n\nexport function getLocalExtensionTelemetryData(extension: ILocalExtension): any {\n\treturn {\n\t\tid: extension.identifier.id,\n\t\tname: extension.manifest.name,\n\t\tgalleryId: null,\n\t\tpublisherId: extension.publisherId,\n\t\tpublisherName: extension.manifest.publisher,\n\t\tpublisherDisplayName: extension.publisherDisplayName,\n\t\tdependencies: extension.manifest.extensionDependencies && extension.manifest.extensionDependencies.length > 0\n\t};\n}\n\n\n/* __GDPR__FRAGMENT__\n\t\"GalleryExtensionTelemetryData\" : {\n\t\t\"id\" : { \"classification\": \"SystemMetaData\", \"purpose\": \"FeatureInsight\" },\n\t\t\"name\": { \"classification\": \"SystemMetaData\", \"purpose\": \"FeatureInsight\" },\n\t\t\"galleryId\": { \"classification\": \"SystemMetaData\", \"purpose\": \"FeatureInsight\" },\n\t\t\"publisherId\": { \"classification\": \"SystemMetaData\", \"purpose\": \"FeatureInsight\" },\n\t\t\"publisherName\": { \"classification\": \"SystemMetaData\", \"purpose\": \"FeatureInsight\" },\n\t\t\"publisherDisplayName\": { \"classification\": \"SystemMetaData\", \"purpose\": \"FeatureInsight\" },\n\t\t\"isPreReleaseVersion\": { \"classification\": \"SystemMetaData\", \"purpose\": \"FeatureInsight\" },\n\t\t\"dependencies\": { \"classification\": \"SystemMetaData\", \"purpose\": \"FeatureInsight\", \"isMeasurement\": true },\n\t\t\"isSigned\": { \"classification\": \"SystemMetaData\", \"purpose\": \"FeatureInsight\" },\n\t\t\"${include}\": [\n\t\t\t\"${GalleryExtensionTelemetryData2}\"\n\t\t]\n\t}\n*/\nexport function getGalleryExtensionTelemetryData(extension: IGalleryExtension): any {\n\treturn {\n\t\tid: new TelemetryTrustedValue(extension.identifier.id),\n\t\tname: new TelemetryTrustedValue(extension.name),\n\t\tgalleryId: extension.identifier.uuid,\n\t\tpublisherId: extension.publisherId,\n\t\tpublisherName: extension.publisher,\n\t\tpublisherDisplayName: extension.publisherDisplayName,\n\t\tisPreReleaseVersion: extension.properties.isPreReleaseVersion,\n\t\tdependencies: !!(extension.properties.dependencies && extension.properties.dependencies.length > 0),\n\t\tisSigned: extension.isSigned,\n\t\t...extension.telemetryData\n\t};\n}\n\nexport const BetterMergeId = new ExtensionIdentifier('pprice.better-merge');\n\nexport function getExtensionDependencies(installedExtensions: ReadonlyArray, extension: IExtension): IExtension[] {\n\tconst dependencies: IExtension[] = [];\n\tconst extensions = extension.manifest.extensionDependencies?.slice(0) ?? [];\n\n\twhile (extensions.length) {\n\t\tconst id = extensions.shift();\n\n\t\tif (id && dependencies.every(e => !areSameExtensions(e.identifier, { id }))) {\n\t\t\tconst ext = installedExtensions.filter(e => areSameExtensions(e.identifier, { id }));\n\t\t\tif (ext.length === 1) {\n\t\t\t\tdependencies.push(ext[0]);\n\t\t\t\textensions.push(...ext[0].manifest.extensionDependencies?.slice(0) ?? []);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn dependencies;\n}\n\nasync function isAlpineLinux(fileService: IFileService, logService: ILogService): Promise {\n\tif (!isLinux) {\n\t\treturn false;\n\t}\n\tlet content: string | undefined;\n\ttry {\n\t\tconst fileContent = await fileService.readFile(URI.file('/etc/os-release'));\n\t\tcontent = fileContent.value.toString();\n\t} catch (error) {\n\t\ttry {\n\t\t\tconst fileContent = await fileService.readFile(URI.file('/usr/lib/os-release'));\n\t\t\tcontent = fileContent.value.toString();\n\t\t} catch (error) {\n\t\t\t/* Ignore */\n\t\t\tlogService.debug(`Error while getting the os-release file.`, getErrorMessage(error));\n\t\t}\n\t}\n\treturn !!content && (content.match(/^ID=([^\\u001b\\r\\n]*)/m) || [])[1] === 'alpine';\n}\n\nexport async function computeTargetPlatform(fileService: IFileService, logService: ILogService): Promise {\n\tconst alpineLinux = await isAlpineLinux(fileService, logService);\n\tconst targetPlatform = getTargetPlatform(alpineLinux ? 'alpine' : platform, arch);\n\tlogService.debug('ComputeTargetPlatform:', targetPlatform);\n\treturn targetPlatform;\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { getErrorMessage, isCancellationError } from 'vs/base/common/errors';\nimport { Schemas } from 'vs/base/common/network';\nimport { basename } from 'vs/base/common/resources';\nimport { gt } from 'vs/base/common/semver/semver';\nimport { URI } from 'vs/base/common/uri';\nimport { localize } from 'vs/nls';\nimport { EXTENSION_IDENTIFIER_REGEX, IExtensionGalleryService, IExtensionInfo, IExtensionManagementService, IGalleryExtension, ILocalExtension, InstallOptions, InstallExtensionInfo, InstallOperation } from 'vs/platform/extensionManagement/common/extensionManagement';\nimport { areSameExtensions, getExtensionId, getGalleryExtensionId, getIdAndVersion } from 'vs/platform/extensionManagement/common/extensionManagementUtil';\nimport { ExtensionType, EXTENSION_CATEGORIES, IExtensionManifest } from 'vs/platform/extensions/common/extensions';\nimport { ILogger } from 'vs/platform/log/common/log';\n\n\nconst notFound = (id: string) => localize('notFound', \"Extension '{0}' not found.\", id);\nconst useId = localize('useId', \"Make sure you use the full extension ID, including the publisher, e.g.: {0}\", 'ms-dotnettools.csharp');\n\ntype InstallVSIXInfo = { vsix: URI; installOptions: InstallOptions };\ntype InstallGalleryExtensionInfo = { id: string; version?: string; installOptions: InstallOptions };\n\nexport class ExtensionManagementCLI {\n\n\tconstructor(\n\t\tprotected readonly logger: ILogger,\n\t\t@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService,\n\t\t@IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService,\n\t) { }\n\n\tprotected get location(): string | undefined {\n\t\treturn undefined;\n\t}\n\n\tpublic async listExtensions(showVersions: boolean, category?: string, profileLocation?: URI): Promise {\n\t\tlet extensions = await this.extensionManagementService.getInstalled(ExtensionType.User, profileLocation);\n\t\tconst categories = EXTENSION_CATEGORIES.map(c => c.toLowerCase());\n\t\tif (category && category !== '') {\n\t\t\tif (categories.indexOf(category.toLowerCase()) < 0) {\n\t\t\t\tthis.logger.info('Invalid category please enter a valid category. To list valid categories run --category without a category specified');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\textensions = extensions.filter(e => {\n\t\t\t\tif (e.manifest.categories) {\n\t\t\t\t\tconst lowerCaseCategories: string[] = e.manifest.categories.map(c => c.toLowerCase());\n\t\t\t\t\treturn lowerCaseCategories.indexOf(category.toLowerCase()) > -1;\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t});\n\t\t} else if (category === '') {\n\t\t\tthis.logger.info('Possible Categories: ');\n\t\t\tcategories.forEach(category => {\n\t\t\t\tthis.logger.info(category);\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tif (this.location) {\n\t\t\tthis.logger.info(localize('listFromLocation', \"Extensions installed on {0}:\", this.location));\n\t\t}\n\n\t\textensions = extensions.sort((e1, e2) => e1.identifier.id.localeCompare(e2.identifier.id));\n\t\tlet lastId: string | undefined = undefined;\n\t\tfor (const extension of extensions) {\n\t\t\tif (lastId !== extension.identifier.id) {\n\t\t\t\tlastId = extension.identifier.id;\n\t\t\t\tthis.logger.info(showVersions ? `${lastId}@${extension.manifest.version}` : lastId);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic async installExtensions(extensions: (string | URI)[], builtinExtensions: (string | URI)[], installOptions: InstallOptions, force: boolean): Promise {\n\t\tconst failed: string[] = [];\n\n\t\ttry {\n\t\t\tif (extensions.length) {\n\t\t\t\tthis.logger.info(this.location ? localize('installingExtensionsOnLocation', \"Installing extensions on {0}...\", this.location) : localize('installingExtensions', \"Installing extensions...\"));\n\t\t\t}\n\n\t\t\tconst installVSIXInfos: InstallVSIXInfo[] = [];\n\t\t\tconst installExtensionInfos: InstallGalleryExtensionInfo[] = [];\n\t\t\tconst addInstallExtensionInfo = (id: string, version: string | undefined, isBuiltin: boolean) => {\n\t\t\t\tinstallExtensionInfos.push({ id, version: version !== 'prerelease' ? version : undefined, installOptions: { ...installOptions, isBuiltin, installPreReleaseVersion: version === 'prerelease' || installOptions.installPreReleaseVersion } });\n\t\t\t};\n\t\t\tfor (const extension of extensions) {\n\t\t\t\tif (extension instanceof URI) {\n\t\t\t\t\tinstallVSIXInfos.push({ vsix: extension, installOptions });\n\t\t\t\t} else {\n\t\t\t\t\tconst [id, version] = getIdAndVersion(extension);\n\t\t\t\t\taddInstallExtensionInfo(id, version, false);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const extension of builtinExtensions) {\n\t\t\t\tif (extension instanceof URI) {\n\t\t\t\t\tinstallVSIXInfos.push({ vsix: extension, installOptions: { ...installOptions, isBuiltin: true, donotIncludePackAndDependencies: true } });\n\t\t\t\t} else {\n\t\t\t\t\tconst [id, version] = getIdAndVersion(extension);\n\t\t\t\t\taddInstallExtensionInfo(id, version, true);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst installed = await this.extensionManagementService.getInstalled(ExtensionType.User, installOptions.profileLocation);\n\n\t\t\tif (installVSIXInfos.length) {\n\t\t\t\tawait Promise.all(installVSIXInfos.map(async ({ vsix, installOptions }) => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait this.installVSIX(vsix, installOptions, force, installed);\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tthis.logger.error(err);\n\t\t\t\t\t\tfailed.push(vsix.toString());\n\t\t\t\t\t}\n\t\t\t\t}));\n\t\t\t}\n\n\t\t\tif (installExtensionInfos.length) {\n\t\t\t\tconst failedGalleryExtensions = await this.installGalleryExtensions(installExtensionInfos, installed, force);\n\t\t\t\tfailed.push(...failedGalleryExtensions);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tthis.logger.error(localize('error while installing extensions', \"Error while installing extensions: {0}\", getErrorMessage(error)));\n\t\t\tthrow error;\n\t\t}\n\n\t\tif (failed.length) {\n\t\t\tthrow new Error(localize('installation failed', \"Failed Installing Extensions: {0}\", failed.join(', ')));\n\t\t}\n\t}\n\n\tpublic async updateExtensions(profileLocation?: URI): Promise {\n\t\tconst installedExtensions = await this.extensionManagementService.getInstalled(ExtensionType.User, profileLocation);\n\n\t\tconst installedExtensionsQuery: IExtensionInfo[] = [];\n\t\tfor (const extension of installedExtensions) {\n\t\t\tif (!!extension.identifier.uuid) { // No need to check new version for an unpublished extension\n\t\t\t\tinstalledExtensionsQuery.push({ ...extension.identifier, preRelease: extension.preRelease });\n\t\t\t}\n\t\t}\n\n\t\tthis.logger.trace(localize({ key: 'updateExtensionsQuery', comment: ['Placeholder is for the count of extensions'] }, \"Fetching latest versions for {0} extensions\", installedExtensionsQuery.length));\n\t\tconst availableVersions = await this.extensionGalleryService.getExtensions(installedExtensionsQuery, { compatible: true }, CancellationToken.None);\n\n\t\tconst extensionsToUpdate: InstallExtensionInfo[] = [];\n\t\tfor (const newVersion of availableVersions) {\n\t\t\tfor (const oldVersion of installedExtensions) {\n\t\t\t\tif (areSameExtensions(oldVersion.identifier, newVersion.identifier) && gt(newVersion.version, oldVersion.manifest.version)) {\n\t\t\t\t\textensionsToUpdate.push({\n\t\t\t\t\t\textension: newVersion,\n\t\t\t\t\t\toptions: { operation: InstallOperation.Update, installPreReleaseVersion: oldVersion.isPreReleaseVersion }\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (!extensionsToUpdate.length) {\n\t\t\tthis.logger.info(localize('updateExtensionsNoExtensions', \"No extension to update\"));\n\t\t\treturn;\n\t\t}\n\n\t\tthis.logger.info(localize('updateExtensionsNewVersionsAvailable', \"Updating extensions: {0}\", extensionsToUpdate.map(ext => ext.extension.identifier.id).join(', ')));\n\t\tconst installationResult = await this.extensionManagementService.installGalleryExtensions(extensionsToUpdate);\n\n\t\tfor (const extensionResult of installationResult) {\n\t\t\tif (extensionResult.error) {\n\t\t\t\tthis.logger.error(localize('errorUpdatingExtension', \"Error while updating extension {0}: {1}\", extensionResult.identifier.id, getErrorMessage(extensionResult.error)));\n\t\t\t} else {\n\t\t\t\tthis.logger.info(localize('successUpdate', \"Extension '{0}' v{1} was successfully updated.\", extensionResult.identifier.id, extensionResult.local?.manifest.version));\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async installGalleryExtensions(installExtensionInfos: InstallGalleryExtensionInfo[], installed: ILocalExtension[], force: boolean): Promise {\n\t\tinstallExtensionInfos = installExtensionInfos.filter(({ id, version }) => {\n\t\t\tconst installedExtension = installed.find(i => areSameExtensions(i.identifier, { id }));\n\t\t\tif (installedExtension) {\n\t\t\t\tif (!force && (!version || (version === 'prerelease' && installedExtension.preRelease))) {\n\t\t\t\t\tthis.logger.info(localize('alreadyInstalled-checkAndUpdate', \"Extension '{0}' v{1} is already installed. Use '--force' option to update to latest version or provide '@' to install a specific version, for example: '{2}@1.2.3'.\", id, installedExtension.manifest.version, id));\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tif (version && installedExtension.manifest.version === version) {\n\t\t\t\t\tthis.logger.info(localize('alreadyInstalled', \"Extension '{0}' is already installed.\", `${id}@${version}`));\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\tif (!installExtensionInfos.length) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst failed: string[] = [];\n\t\tconst extensionsToInstall: InstallExtensionInfo[] = [];\n\t\tconst galleryExtensions = await this.getGalleryExtensions(installExtensionInfos);\n\t\tawait Promise.all(installExtensionInfos.map(async ({ id, version, installOptions }) => {\n\t\t\tconst gallery = galleryExtensions.get(id.toLowerCase());\n\t\t\tif (!gallery) {\n\t\t\t\tthis.logger.error(`${notFound(version ? `${id}@${version}` : id)}\\n${useId}`);\n\t\t\t\tfailed.push(id);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst manifest = await this.extensionGalleryService.getManifest(gallery, CancellationToken.None);\n\t\t\t\tif (manifest && !this.validateExtensionKind(manifest)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tthis.logger.error(err.message || err.stack || err);\n\t\t\t\tfailed.push(id);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst installedExtension = installed.find(e => areSameExtensions(e.identifier, gallery.identifier));\n\t\t\tif (installedExtension) {\n\t\t\t\tif (gallery.version === installedExtension.manifest.version) {\n\t\t\t\t\tthis.logger.info(localize('alreadyInstalled', \"Extension '{0}' is already installed.\", version ? `${id}@${version}` : id));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis.logger.info(localize('updateMessage', \"Updating the extension '{0}' to the version {1}\", id, gallery.version));\n\t\t\t}\n\t\t\tif (installOptions.isBuiltin) {\n\t\t\t\tthis.logger.info(version ? localize('installing builtin with version', \"Installing builtin extension '{0}' v{1}...\", id, version) : localize('installing builtin ', \"Installing builtin extension '{0}'...\", id));\n\t\t\t} else {\n\t\t\t\tthis.logger.info(version ? localize('installing with version', \"Installing extension '{0}' v{1}...\", id, version) : localize('installing', \"Installing extension '{0}'...\", id));\n\t\t\t}\n\t\t\textensionsToInstall.push({\n\t\t\t\textension: gallery,\n\t\t\t\toptions: { ...installOptions, installGivenVersion: !!version },\n\t\t\t});\n\t\t}));\n\n\t\tif (extensionsToInstall.length) {\n\t\t\tconst installationResult = await this.extensionManagementService.installGalleryExtensions(extensionsToInstall);\n\t\t\tfor (const extensionResult of installationResult) {\n\t\t\t\tif (extensionResult.error) {\n\t\t\t\t\tthis.logger.error(localize('errorInstallingExtension', \"Error while installing extension {0}: {1}\", extensionResult.identifier.id, getErrorMessage(extensionResult.error)));\n\t\t\t\t\tfailed.push(extensionResult.identifier.id);\n\t\t\t\t} else {\n\t\t\t\t\tthis.logger.info(localize('successInstall', \"Extension '{0}' v{1} was successfully installed.\", extensionResult.identifier.id, extensionResult.local?.manifest.version));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn failed;\n\t}\n\n\tprivate async installVSIX(vsix: URI, installOptions: InstallOptions, force: boolean, installedExtensions: ILocalExtension[]): Promise {\n\n\t\tconst manifest = await this.extensionManagementService.getManifest(vsix);\n\t\tif (!manifest) {\n\t\t\tthrow new Error('Invalid vsix');\n\t\t}\n\n\t\tconst valid = await this.validateVSIX(manifest, force, installOptions.profileLocation, installedExtensions);\n\t\tif (valid) {\n\t\t\ttry {\n\t\t\t\tawait this.extensionManagementService.install(vsix, installOptions);\n\t\t\t\tthis.logger.info(localize('successVsixInstall', \"Extension '{0}' was successfully installed.\", basename(vsix)));\n\t\t\t} catch (error) {\n\t\t\t\tif (isCancellationError(error)) {\n\t\t\t\t\tthis.logger.info(localize('cancelVsixInstall', \"Cancelled installing extension '{0}'.\", basename(vsix)));\n\t\t\t\t} else {\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async getGalleryExtensions(extensions: InstallGalleryExtensionInfo[]): Promise> {\n\t\tconst galleryExtensions = new Map();\n\t\tconst preRelease = extensions.some(e => e.installOptions.installPreReleaseVersion);\n\t\tconst targetPlatform = await this.extensionManagementService.getTargetPlatform();\n\t\tconst extensionInfos: IExtensionInfo[] = [];\n\t\tfor (const extension of extensions) {\n\t\t\tif (EXTENSION_IDENTIFIER_REGEX.test(extension.id)) {\n\t\t\t\textensionInfos.push({ ...extension, preRelease });\n\t\t\t}\n\t\t}\n\t\tif (extensionInfos.length) {\n\t\t\tconst result = await this.extensionGalleryService.getExtensions(extensionInfos, { targetPlatform }, CancellationToken.None);\n\t\t\tfor (const extension of result) {\n\t\t\t\tgalleryExtensions.set(extension.identifier.id.toLowerCase(), extension);\n\t\t\t}\n\t\t}\n\t\treturn galleryExtensions;\n\t}\n\n\tprotected validateExtensionKind(_manifest: IExtensionManifest): boolean {\n\t\treturn true;\n\t}\n\n\tprivate async validateVSIX(manifest: IExtensionManifest, force: boolean, profileLocation: URI | undefined, installedExtensions: ILocalExtension[]): Promise {\n\t\tif (!force) {\n\t\t\tconst extensionIdentifier = { id: getGalleryExtensionId(manifest.publisher, manifest.name) };\n\t\t\tconst newer = installedExtensions.find(local => areSameExtensions(extensionIdentifier, local.identifier) && gt(local.manifest.version, manifest.version));\n\t\t\tif (newer) {\n\t\t\t\tthis.logger.info(localize('forceDowngrade', \"A newer version of extension '{0}' v{1} is already installed. Use '--force' option to downgrade to older version.\", newer.identifier.id, newer.manifest.version, manifest.version));\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn this.validateExtensionKind(manifest);\n\t}\n\n\tpublic async uninstallExtensions(extensions: (string | URI)[], force: boolean, profileLocation?: URI): Promise {\n\t\tconst getId = async (extensionDescription: string | URI): Promise => {\n\t\t\tif (extensionDescription instanceof URI) {\n\t\t\t\tconst manifest = await this.extensionManagementService.getManifest(extensionDescription);\n\t\t\t\treturn getExtensionId(manifest.publisher, manifest.name);\n\t\t\t}\n\t\t\treturn extensionDescription;\n\t\t};\n\n\t\tconst uninstalledExtensions: ILocalExtension[] = [];\n\t\tfor (const extension of extensions) {\n\t\t\tconst id = await getId(extension);\n\t\t\tconst installed = await this.extensionManagementService.getInstalled(undefined, profileLocation);\n\t\t\tconst extensionsToUninstall = installed.filter(e => areSameExtensions(e.identifier, { id }));\n\t\t\tif (!extensionsToUninstall.length) {\n\t\t\t\tthrow new Error(`${this.notInstalled(id)}\\n${useId}`);\n\t\t\t}\n\t\t\tif (extensionsToUninstall.some(e => e.type === ExtensionType.System)) {\n\t\t\t\tthis.logger.info(localize('builtin', \"Extension '{0}' is a Built-in extension and cannot be uninstalled\", id));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (!force && extensionsToUninstall.some(e => e.isBuiltin)) {\n\t\t\t\tthis.logger.info(localize('forceUninstall', \"Extension '{0}' is marked as a Built-in extension by user. Please use '--force' option to uninstall it.\", id));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.logger.info(localize('uninstalling', \"Uninstalling {0}...\", id));\n\t\t\tfor (const extensionToUninstall of extensionsToUninstall) {\n\t\t\t\tawait this.extensionManagementService.uninstall(extensionToUninstall, { profileLocation });\n\t\t\t\tuninstalledExtensions.push(extensionToUninstall);\n\t\t\t}\n\n\t\t\tif (this.location) {\n\t\t\t\tthis.logger.info(localize('successUninstallFromLocation', \"Extension '{0}' was successfully uninstalled from {1}!\", id, this.location));\n\t\t\t} else {\n\t\t\t\tthis.logger.info(localize('successUninstall', \"Extension '{0}' was successfully uninstalled!\", id));\n\t\t\t}\n\n\t\t}\n\t}\n\n\tpublic async locateExtension(extensions: string[]): Promise {\n\t\tconst installed = await this.extensionManagementService.getInstalled();\n\t\textensions.forEach(e => {\n\t\t\tinstalled.forEach(i => {\n\t\t\t\tif (i.identifier.id === e) {\n\t\t\t\t\tif (i.location.scheme === Schemas.file) {\n\t\t\t\t\t\tthis.logger.info(i.location.fsPath);\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\tprivate notInstalled(id: string) {\n\t\treturn this.location ? localize('notInstalleddOnLocation', \"Extension '{0}' is not installed on {1}.\", id, this.location) : localize('notInstalled', \"Extension '{0}' is not installed.\", 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 { isNonEmptyArray } from 'vs/base/common/arrays';\nimport { Disposable, MutableDisposable } from 'vs/base/common/lifecycle';\nimport { IConfigBasedExtensionTip as IRawConfigBasedExtensionTip } from 'vs/base/common/product';\nimport { joinPath } from 'vs/base/common/resources';\nimport { URI } from 'vs/base/common/uri';\nimport { IConfigBasedExtensionTip, IExecutableBasedExtensionTip, IExtensionManagementService, IExtensionTipsService, ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement';\nimport { IFileService } from 'vs/platform/files/common/files';\nimport { IProductService } from 'vs/platform/product/common/productService';\nimport { disposableTimeout } from 'vs/base/common/async';\nimport { IStringDictionary } from 'vs/base/common/collections';\nimport { Event } from 'vs/base/common/event';\nimport { join } from 'vs/base/common/path';\nimport { isWindows } from 'vs/base/common/platform';\nimport { env } from 'vs/base/common/process';\nimport { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';\nimport { IExtensionRecommendationNotificationService, RecommendationsNotificationResult, RecommendationSource } from 'vs/platform/extensionRecommendations/common/extensionRecommendations';\nimport { ExtensionType } from 'vs/platform/extensions/common/extensions';\nimport { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';\nimport { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';\n\n//#region Base Extension Tips Service\n\nexport class ExtensionTipsService extends Disposable implements IExtensionTipsService {\n\n\t_serviceBrand: any;\n\n\tprivate readonly allConfigBasedTips: Map = new Map();\n\n\tconstructor(\n\t\t@IFileService protected readonly fileService: IFileService,\n\t\t@IProductService private readonly productService: IProductService,\n\t) {\n\t\tsuper();\n\t\tif (this.productService.configBasedExtensionTips) {\n\t\t\tObject.entries(this.productService.configBasedExtensionTips).forEach(([, value]) => this.allConfigBasedTips.set(value.configPath, value));\n\t\t}\n\t}\n\n\tgetConfigBasedTips(folder: URI): Promise {\n\t\treturn this.getValidConfigBasedTips(folder);\n\t}\n\n\tasync getImportantExecutableBasedTips(): Promise {\n\t\treturn [];\n\t}\n\n\tasync getOtherExecutableBasedTips(): Promise {\n\t\treturn [];\n\t}\n\n\tprivate async getValidConfigBasedTips(folder: URI): Promise {\n\t\tconst result: IConfigBasedExtensionTip[] = [];\n\t\tfor (const [configPath, tip] of this.allConfigBasedTips) {\n\t\t\tif (tip.configScheme && tip.configScheme !== folder.scheme) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst content = (await this.fileService.readFile(joinPath(folder, configPath))).value.toString();\n\t\t\t\tfor (const [key, value] of Object.entries(tip.recommendations)) {\n\t\t\t\t\tif (!value.contentPattern || new RegExp(value.contentPattern, 'mig').test(content)) {\n\t\t\t\t\t\tresult.push({\n\t\t\t\t\t\t\textensionId: key,\n\t\t\t\t\t\t\textensionName: value.name,\n\t\t\t\t\t\t\tconfigName: tip.configName,\n\t\t\t\t\t\t\timportant: !!value.important,\n\t\t\t\t\t\t\tisExtensionPack: !!value.isExtensionPack,\n\t\t\t\t\t\t\twhenNotInstalled: value.whenNotInstalled\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error) { /* Ignore */ }\n\t\t}\n\t\treturn result;\n\t}\n}\n\n//#endregion\n\n//#region Native Extension Tips Service (enables unit testing having it here in \"common\")\n\ntype ExeExtensionRecommendationsClassification = {\n\towner: 'sandy081';\n\tcomment: 'Information about executable based extension recommendation';\n\textensionId: { classification: 'PublicNonPersonalData'; purpose: 'FeatureInsight'; comment: 'id of the recommended extension' };\n\texeName: { classification: 'PublicNonPersonalData'; purpose: 'FeatureInsight'; comment: 'name of the executable for which extension is being recommended' };\n};\n\ntype IExeBasedExtensionTips = {\n\treadonly exeFriendlyName: string;\n\treadonly windowsPath?: string;\n\treadonly recommendations: { extensionId: string; extensionName: string; isExtensionPack: boolean; whenNotInstalled?: string[] }[];\n};\n\nconst promptedExecutableTipsStorageKey = 'extensionTips/promptedExecutableTips';\nconst lastPromptedMediumImpExeTimeStorageKey = 'extensionTips/lastPromptedMediumImpExeTime';\n\nexport abstract class AbstractNativeExtensionTipsService extends ExtensionTipsService {\n\n\tprivate readonly highImportanceExecutableTips: Map = new Map();\n\tprivate readonly mediumImportanceExecutableTips: Map = new Map();\n\tprivate readonly allOtherExecutableTips: Map = new Map();\n\n\tprivate highImportanceTipsByExe = new Map();\n\tprivate mediumImportanceTipsByExe = new Map();\n\n\tconstructor(\n\t\tprivate readonly userHome: URI,\n\t\tprivate readonly windowEvents: {\n\t\t\treadonly onDidOpenMainWindow: Event;\n\t\t\treadonly onDidFocusMainWindow: Event;\n\t\t},\n\t\tprivate readonly telemetryService: ITelemetryService,\n\t\tprivate readonly extensionManagementService: IExtensionManagementService,\n\t\tprivate readonly storageService: IStorageService,\n\t\tprivate readonly extensionRecommendationNotificationService: IExtensionRecommendationNotificationService,\n\t\tfileService: IFileService,\n\t\tproductService: IProductService\n\t) {\n\t\tsuper(fileService, productService);\n\t\tif (productService.exeBasedExtensionTips) {\n\t\t\tObject.entries(productService.exeBasedExtensionTips).forEach(([key, exeBasedExtensionTip]) => {\n\t\t\t\tconst highImportanceRecommendations: { extensionId: string; extensionName: string; isExtensionPack: boolean }[] = [];\n\t\t\t\tconst mediumImportanceRecommendations: { extensionId: string; extensionName: string; isExtensionPack: boolean }[] = [];\n\t\t\t\tconst otherRecommendations: { extensionId: string; extensionName: string; isExtensionPack: boolean }[] = [];\n\t\t\t\tObject.entries(exeBasedExtensionTip.recommendations).forEach(([extensionId, value]) => {\n\t\t\t\t\tif (value.important) {\n\t\t\t\t\t\tif (exeBasedExtensionTip.important) {\n\t\t\t\t\t\t\thighImportanceRecommendations.push({ extensionId, extensionName: value.name, isExtensionPack: !!value.isExtensionPack });\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tmediumImportanceRecommendations.push({ extensionId, extensionName: value.name, isExtensionPack: !!value.isExtensionPack });\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\totherRecommendations.push({ extensionId, extensionName: value.name, isExtensionPack: !!value.isExtensionPack });\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tif (highImportanceRecommendations.length) {\n\t\t\t\t\tthis.highImportanceExecutableTips.set(key, { exeFriendlyName: exeBasedExtensionTip.friendlyName, windowsPath: exeBasedExtensionTip.windowsPath, recommendations: highImportanceRecommendations });\n\t\t\t\t}\n\t\t\t\tif (mediumImportanceRecommendations.length) {\n\t\t\t\t\tthis.mediumImportanceExecutableTips.set(key, { exeFriendlyName: exeBasedExtensionTip.friendlyName, windowsPath: exeBasedExtensionTip.windowsPath, recommendations: mediumImportanceRecommendations });\n\t\t\t\t}\n\t\t\t\tif (otherRecommendations.length) {\n\t\t\t\t\tthis.allOtherExecutableTips.set(key, { exeFriendlyName: exeBasedExtensionTip.friendlyName, windowsPath: exeBasedExtensionTip.windowsPath, recommendations: otherRecommendations });\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t/*\n\t\t\t3s has come out to be the good number to fetch and prompt important exe based recommendations\n\t\t\tAlso fetch important exe based recommendations for reporting telemetry\n\t\t*/\n\t\tdisposableTimeout(async () => {\n\t\t\tawait this.collectTips();\n\t\t\tthis.promptHighImportanceExeBasedTip();\n\t\t\tthis.promptMediumImportanceExeBasedTip();\n\t\t}, 3000, this._store);\n\t}\n\n\toverride async getImportantExecutableBasedTips(): Promise {\n\t\tconst highImportanceExeTips = await this.getValidExecutableBasedExtensionTips(this.highImportanceExecutableTips);\n\t\tconst mediumImportanceExeTips = await this.getValidExecutableBasedExtensionTips(this.mediumImportanceExecutableTips);\n\t\treturn [...highImportanceExeTips, ...mediumImportanceExeTips];\n\t}\n\n\toverride getOtherExecutableBasedTips(): Promise {\n\t\treturn this.getValidExecutableBasedExtensionTips(this.allOtherExecutableTips);\n\t}\n\n\tprivate async collectTips(): Promise {\n\t\tconst highImportanceExeTips = await this.getValidExecutableBasedExtensionTips(this.highImportanceExecutableTips);\n\t\tconst mediumImportanceExeTips = await this.getValidExecutableBasedExtensionTips(this.mediumImportanceExecutableTips);\n\t\tconst local = await this.extensionManagementService.getInstalled();\n\n\t\tthis.highImportanceTipsByExe = this.groupImportantTipsByExe(highImportanceExeTips, local);\n\t\tthis.mediumImportanceTipsByExe = this.groupImportantTipsByExe(mediumImportanceExeTips, local);\n\t}\n\n\tprivate groupImportantTipsByExe(importantExeBasedTips: IExecutableBasedExtensionTip[], local: ILocalExtension[]): Map {\n\t\tconst importantExeBasedRecommendations = new Map();\n\t\timportantExeBasedTips.forEach(tip => importantExeBasedRecommendations.set(tip.extensionId.toLowerCase(), tip));\n\n\t\tconst { installed, uninstalled: recommendations } = this.groupByInstalled([...importantExeBasedRecommendations.keys()], local);\n\n\t\t/* Log installed and uninstalled exe based recommendations */\n\t\tfor (const extensionId of installed) {\n\t\t\tconst tip = importantExeBasedRecommendations.get(extensionId);\n\t\t\tif (tip) {\n\t\t\t\tthis.telemetryService.publicLog2<{ exeName: string; extensionId: string }, ExeExtensionRecommendationsClassification>('exeExtensionRecommendations:alreadyInstalled', { extensionId, exeName: tip.exeName });\n\t\t\t}\n\t\t}\n\t\tfor (const extensionId of recommendations) {\n\t\t\tconst tip = importantExeBasedRecommendations.get(extensionId);\n\t\t\tif (tip) {\n\t\t\t\tthis.telemetryService.publicLog2<{ exeName: string; extensionId: string }, ExeExtensionRecommendationsClassification>('exeExtensionRecommendations:notInstalled', { extensionId, exeName: tip.exeName });\n\t\t\t}\n\t\t}\n\n\t\tconst promptedExecutableTips = this.getPromptedExecutableTips();\n\t\tconst tipsByExe = new Map();\n\t\tfor (const extensionId of recommendations) {\n\t\t\tconst tip = importantExeBasedRecommendations.get(extensionId);\n\t\t\tif (tip && (!promptedExecutableTips[tip.exeName] || !promptedExecutableTips[tip.exeName].includes(tip.extensionId))) {\n\t\t\t\tlet tips = tipsByExe.get(tip.exeName);\n\t\t\t\tif (!tips) {\n\t\t\t\t\ttips = [];\n\t\t\t\t\ttipsByExe.set(tip.exeName, tips);\n\t\t\t\t}\n\t\t\t\ttips.push(tip);\n\t\t\t}\n\t\t}\n\n\t\treturn tipsByExe;\n\t}\n\n\t/**\n\t * High importance tips are prompted once per restart session\n\t */\n\tprivate promptHighImportanceExeBasedTip(): void {\n\t\tif (this.highImportanceTipsByExe.size === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst [exeName, tips] = [...this.highImportanceTipsByExe.entries()][0];\n\t\tthis.promptExeRecommendations(tips)\n\t\t\t.then(result => {\n\t\t\t\tswitch (result) {\n\t\t\t\t\tcase RecommendationsNotificationResult.Accepted:\n\t\t\t\t\t\tthis.addToRecommendedExecutables(tips[0].exeName, tips);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase RecommendationsNotificationResult.Ignored:\n\t\t\t\t\t\tthis.highImportanceTipsByExe.delete(exeName);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase RecommendationsNotificationResult.IncompatibleWindow: {\n\t\t\t\t\t\t// Recommended in incompatible window. Schedule the prompt after active window change\n\t\t\t\t\t\tconst onActiveWindowChange = Event.once(Event.latch(Event.any(this.windowEvents.onDidOpenMainWindow, this.windowEvents.onDidFocusMainWindow)));\n\t\t\t\t\t\tthis._register(onActiveWindowChange(() => this.promptHighImportanceExeBasedTip()));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase RecommendationsNotificationResult.TooMany: {\n\t\t\t\t\t\t// Too many notifications. Schedule the prompt after one hour\n\t\t\t\t\t\tconst disposable = this._register(new MutableDisposable());\n\t\t\t\t\t\tdisposable.value = disposableTimeout(() => { disposable.dispose(); this.promptHighImportanceExeBasedTip(); }, 60 * 60 * 1000 /* 1 hour */);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t}\n\n\t/**\n\t * Medium importance tips are prompted once per 7 days\n\t */\n\tprivate promptMediumImportanceExeBasedTip(): void {\n\t\tif (this.mediumImportanceTipsByExe.size === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst lastPromptedMediumExeTime = this.getLastPromptedMediumExeTime();\n\t\tconst timeSinceLastPrompt = Date.now() - lastPromptedMediumExeTime;\n\t\tconst promptInterval = 7 * 24 * 60 * 60 * 1000; // 7 Days\n\t\tif (timeSinceLastPrompt < promptInterval) {\n\t\t\t// Wait until interval and prompt\n\t\t\tconst disposable = this._register(new MutableDisposable());\n\t\t\tdisposable.value = disposableTimeout(() => { disposable.dispose(); this.promptMediumImportanceExeBasedTip(); }, promptInterval - timeSinceLastPrompt);\n\t\t\treturn;\n\t\t}\n\n\t\tconst [exeName, tips] = [...this.mediumImportanceTipsByExe.entries()][0];\n\t\tthis.promptExeRecommendations(tips)\n\t\t\t.then(result => {\n\t\t\t\tswitch (result) {\n\t\t\t\t\tcase RecommendationsNotificationResult.Accepted: {\n\t\t\t\t\t\t// Accepted: Update the last prompted time and caches.\n\t\t\t\t\t\tthis.updateLastPromptedMediumExeTime(Date.now());\n\t\t\t\t\t\tthis.mediumImportanceTipsByExe.delete(exeName);\n\t\t\t\t\t\tthis.addToRecommendedExecutables(tips[0].exeName, tips);\n\n\t\t\t\t\t\t// Schedule the next recommendation for next internval\n\t\t\t\t\t\tconst disposable1 = this._register(new MutableDisposable());\n\t\t\t\t\t\tdisposable1.value = disposableTimeout(() => { disposable1.dispose(); this.promptMediumImportanceExeBasedTip(); }, promptInterval);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase RecommendationsNotificationResult.Ignored:\n\t\t\t\t\t\t// Ignored: Remove from the cache and prompt next recommendation\n\t\t\t\t\t\tthis.mediumImportanceTipsByExe.delete(exeName);\n\t\t\t\t\t\tthis.promptMediumImportanceExeBasedTip();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase RecommendationsNotificationResult.IncompatibleWindow: {\n\t\t\t\t\t\t// Recommended in incompatible window. Schedule the prompt after active window change\n\t\t\t\t\t\tconst onActiveWindowChange = Event.once(Event.latch(Event.any(this.windowEvents.onDidOpenMainWindow, this.windowEvents.onDidFocusMainWindow)));\n\t\t\t\t\t\tthis._register(onActiveWindowChange(() => this.promptMediumImportanceExeBasedTip()));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase RecommendationsNotificationResult.TooMany: {\n\t\t\t\t\t\t// Too many notifications. Schedule the prompt after one hour\n\t\t\t\t\t\tconst disposable2 = this._register(new MutableDisposable());\n\t\t\t\t\t\tdisposable2.value = disposableTimeout(() => { disposable2.dispose(); this.promptMediumImportanceExeBasedTip(); }, 60 * 60 * 1000 /* 1 hour */);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t}\n\n\tprivate async promptExeRecommendations(tips: IExecutableBasedExtensionTip[]): Promise {\n\t\tconst installed = await this.extensionManagementService.getInstalled(ExtensionType.User);\n\t\tconst extensions = tips\n\t\t\t.filter(tip => !tip.whenNotInstalled || tip.whenNotInstalled.every(id => installed.every(local => !areSameExtensions(local.identifier, { id }))))\n\t\t\t.map(({ extensionId }) => extensionId.toLowerCase());\n\t\treturn this.extensionRecommendationNotificationService.promptImportantExtensionsInstallNotification({ extensions, source: RecommendationSource.EXE, name: tips[0].exeFriendlyName, searchValue: `@exe:\"${tips[0].exeName}\"` });\n\t}\n\n\tprivate getLastPromptedMediumExeTime(): number {\n\t\tlet value = this.storageService.getNumber(lastPromptedMediumImpExeTimeStorageKey, StorageScope.APPLICATION);\n\t\tif (!value) {\n\t\t\tvalue = Date.now();\n\t\t\tthis.updateLastPromptedMediumExeTime(value);\n\t\t}\n\t\treturn value;\n\t}\n\n\tprivate updateLastPromptedMediumExeTime(value: number): void {\n\t\tthis.storageService.store(lastPromptedMediumImpExeTimeStorageKey, value, StorageScope.APPLICATION, StorageTarget.MACHINE);\n\t}\n\n\tprivate getPromptedExecutableTips(): IStringDictionary {\n\t\treturn JSON.parse(this.storageService.get(promptedExecutableTipsStorageKey, StorageScope.APPLICATION, '{}'));\n\t}\n\n\tprivate addToRecommendedExecutables(exeName: string, tips: IExecutableBasedExtensionTip[]) {\n\t\tconst promptedExecutableTips = this.getPromptedExecutableTips();\n\t\tpromptedExecutableTips[exeName] = tips.map(({ extensionId }) => extensionId.toLowerCase());\n\t\tthis.storageService.store(promptedExecutableTipsStorageKey, JSON.stringify(promptedExecutableTips), StorageScope.APPLICATION, StorageTarget.USER);\n\t}\n\n\tprivate groupByInstalled(recommendationsToSuggest: string[], local: ILocalExtension[]): { installed: string[]; uninstalled: string[] } {\n\t\tconst installed: string[] = [], uninstalled: string[] = [];\n\t\tconst installedExtensionsIds = local.reduce((result, i) => { result.add(i.identifier.id.toLowerCase()); return result; }, new Set());\n\t\trecommendationsToSuggest.forEach(id => {\n\t\t\tif (installedExtensionsIds.has(id.toLowerCase())) {\n\t\t\t\tinstalled.push(id);\n\t\t\t} else {\n\t\t\t\tuninstalled.push(id);\n\t\t\t}\n\t\t});\n\t\treturn { installed, uninstalled };\n\t}\n\n\tprivate async getValidExecutableBasedExtensionTips(executableTips: Map): Promise {\n\t\tconst result: IExecutableBasedExtensionTip[] = [];\n\n\t\tconst checkedExecutables: Map = new Map();\n\t\tfor (const exeName of executableTips.keys()) {\n\t\t\tconst extensionTip = executableTips.get(exeName);\n\t\t\tif (!extensionTip || !isNonEmptyArray(extensionTip.recommendations)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst exePaths: string[] = [];\n\t\t\tif (isWindows) {\n\t\t\t\tif (extensionTip.windowsPath) {\n\t\t\t\t\texePaths.push(extensionTip.windowsPath.replace('%USERPROFILE%', () => env['USERPROFILE']!)\n\t\t\t\t\t\t.replace('%ProgramFiles(x86)%', () => env['ProgramFiles(x86)']!)\n\t\t\t\t\t\t.replace('%ProgramFiles%', () => env['ProgramFiles']!)\n\t\t\t\t\t\t.replace('%APPDATA%', () => env['APPDATA']!)\n\t\t\t\t\t\t.replace('%WINDIR%', () => env['WINDIR']!));\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\texePaths.push(join('/usr/local/bin', exeName));\n\t\t\t\texePaths.push(join('/usr/bin', exeName));\n\t\t\t\texePaths.push(join(this.userHome.fsPath, exeName));\n\t\t\t}\n\n\t\t\tfor (const exePath of exePaths) {\n\t\t\t\tlet exists = checkedExecutables.get(exePath);\n\t\t\t\tif (exists === undefined) {\n\t\t\t\t\texists = await this.fileService.exists(URI.file(exePath));\n\t\t\t\t\tcheckedExecutables.set(exePath, exists);\n\t\t\t\t}\n\t\t\t\tif (exists) {\n\t\t\t\t\tfor (const { extensionId, extensionName, isExtensionPack, whenNotInstalled } of extensionTip.recommendations) {\n\t\t\t\t\t\tresult.push({\n\t\t\t\t\t\t\textensionId,\n\t\t\t\t\t\t\textensionName,\n\t\t\t\t\t\t\tisExtensionPack,\n\t\t\t\t\t\t\texeName,\n\t\t\t\t\t\t\texeFriendlyName: extensionTip.exeFriendlyName,\n\t\t\t\t\t\t\twindowsPath: extensionTip.windowsPath,\n\t\t\t\t\t\t\twhenNotInstalled: whenNotInstalled\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 result;\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 { CancellationToken } from 'vs/base/common/cancellation';\nimport { IExtensionGalleryService, IExtensionManagementService, IGlobalExtensionEnablementService, InstallOperation } from 'vs/platform/extensionManagement/common/extensionManagement';\nimport { areSameExtensions, getExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';\nimport { IExtensionStorageService } from 'vs/platform/extensionManagement/common/extensionStorage';\nimport { ExtensionType } from 'vs/platform/extensions/common/extensions';\nimport { ILogService } from 'vs/platform/log/common/log';\n\n/**\n * Migrates the installed unsupported nightly extension to a supported pre-release extension. It includes following:\n * \t- Uninstall the Unsupported extension\n * \t- Install (with optional storage migration) the Pre-release extension only if\n * \t\t- the extension is not installed\n * \t\t- or it is a release version and the unsupported extension is enabled.\n */\nexport async function migrateUnsupportedExtensions(extensionManagementService: IExtensionManagementService, galleryService: IExtensionGalleryService, extensionStorageService: IExtensionStorageService, extensionEnablementService: IGlobalExtensionEnablementService, logService: ILogService): Promise {\n\ttry {\n\t\tconst extensionsControlManifest = await extensionManagementService.getExtensionsControlManifest();\n\t\tif (!extensionsControlManifest.deprecated) {\n\t\t\treturn;\n\t\t}\n\t\tconst installed = await extensionManagementService.getInstalled(ExtensionType.User);\n\t\tfor (const [unsupportedExtensionId, deprecated] of Object.entries(extensionsControlManifest.deprecated)) {\n\t\t\tif (!deprecated?.extension) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst { id: preReleaseExtensionId, autoMigrate, preRelease } = deprecated.extension;\n\t\t\tif (!autoMigrate) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst unsupportedExtension = installed.find(i => areSameExtensions(i.identifier, { id: unsupportedExtensionId }));\n\t\t\t// Unsupported Extension is not installed\n\t\t\tif (!unsupportedExtension) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst gallery = (await galleryService.getExtensions([{ id: preReleaseExtensionId, preRelease }], { targetPlatform: await extensionManagementService.getTargetPlatform(), compatible: true }, CancellationToken.None))[0];\n\t\t\tif (!gallery) {\n\t\t\t\tlogService.info(`Skipping migrating '${unsupportedExtension.identifier.id}' extension because, the comaptible target '${preReleaseExtensionId}' extension is not found`);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tlogService.info(`Migrating '${unsupportedExtension.identifier.id}' extension to '${preReleaseExtensionId}' extension...`);\n\n\t\t\t\tconst isUnsupportedExtensionEnabled = !extensionEnablementService.getDisabledExtensions().some(e => areSameExtensions(e, unsupportedExtension.identifier));\n\t\t\t\tawait extensionManagementService.uninstall(unsupportedExtension);\n\t\t\t\tlogService.info(`Uninstalled the unsupported extension '${unsupportedExtension.identifier.id}'`);\n\n\t\t\t\tlet preReleaseExtension = installed.find(i => areSameExtensions(i.identifier, { id: preReleaseExtensionId }));\n\t\t\t\tif (!preReleaseExtension || (!preReleaseExtension.isPreReleaseVersion && isUnsupportedExtensionEnabled)) {\n\t\t\t\t\tpreReleaseExtension = await extensionManagementService.installFromGallery(gallery, { installPreReleaseVersion: true, isMachineScoped: unsupportedExtension.isMachineScoped, operation: InstallOperation.Migrate });\n\t\t\t\t\tlogService.info(`Installed the pre-release extension '${preReleaseExtension.identifier.id}'`);\n\t\t\t\t\tif (!isUnsupportedExtensionEnabled) {\n\t\t\t\t\t\tawait extensionEnablementService.disableExtension(preReleaseExtension.identifier);\n\t\t\t\t\t\tlogService.info(`Disabled the pre-release extension '${preReleaseExtension.identifier.id}' because the unsupported extension '${unsupportedExtension.identifier.id}' is disabled`);\n\t\t\t\t\t}\n\t\t\t\t\tif (autoMigrate.storage) {\n\t\t\t\t\t\textensionStorageService.addToMigrationList(getExtensionId(unsupportedExtension.manifest.publisher, unsupportedExtension.manifest.name), getExtensionId(preReleaseExtension.manifest.publisher, preReleaseExtension.manifest.name));\n\t\t\t\t\t\tlogService.info(`Added pre-release extension to the storage migration list`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tlogService.info(`Migrated '${unsupportedExtension.identifier.id}' extension to '${preReleaseExtensionId}' extension.`);\n\t\t\t} catch (error) {\n\t\t\t\tlogService.error(error);\n\t\t\t}\n\t\t}\n\t} catch (error) {\n\t\tlogService.error(error);\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { isWeb } from 'vs/base/common/platform';\nimport { format2 } from 'vs/base/common/strings';\nimport { URI } from 'vs/base/common/uri';\nimport { IHeaders } from 'vs/base/parts/request/common/request';\nimport { IConfigurationService } from 'vs/platform/configuration/common/configuration';\nimport { IEnvironmentService } from 'vs/platform/environment/common/environment';\nimport { IFileService } from 'vs/platform/files/common/files';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\nimport { IProductService } from 'vs/platform/product/common/productService';\nimport { getServiceMachineId } from 'vs/platform/externalServices/common/serviceMachineId';\nimport { IStorageService } from 'vs/platform/storage/common/storage';\nimport { TelemetryLevel } from 'vs/platform/telemetry/common/telemetry';\nimport { getTelemetryLevel, supportsTelemetry } from 'vs/platform/telemetry/common/telemetryUtils';\nimport { RemoteAuthorities } from 'vs/base/common/network';\nimport { getRemoteServerRootPath } from 'vs/platform/remote/common/remoteHosts';\nimport { TargetPlatform } from 'vs/platform/extensions/common/extensions';\n\nconst WEB_EXTENSION_RESOURCE_END_POINT = 'web-extension-resource';\n\nexport const IExtensionResourceLoaderService = createDecorator('extensionResourceLoaderService');\n\n/**\n * A service useful for reading resources from within extensions.\n */\nexport interface IExtensionResourceLoaderService {\n\treadonly _serviceBrand: undefined;\n\n\t/**\n\t * Read a certain resource within an extension.\n\t */\n\treadExtensionResource(uri: URI): Promise;\n\n\t/**\n\t * Returns whether the gallery provides extension resources.\n\t */\n\treadonly supportsExtensionGalleryResources: boolean;\n\n\t/**\n\t * Return true if the given URI is a extension gallery resource.\n\t */\n\tisExtensionGalleryResource(uri: URI): boolean;\n\n\t/**\n\t * Computes the URL of a extension gallery resource. Returns `undefined` if gallery does not provide extension resources.\n\t */\n\tgetExtensionGalleryResourceURL(galleryExtension: { publisher: string; name: string; version: string; targetPlatform?: TargetPlatform }, path?: string): URI | undefined;\n}\n\nexport function migratePlatformSpecificExtensionGalleryResourceURL(resource: URI, targetPlatform: TargetPlatform): URI | undefined {\n\tif (resource.query !== `target=${targetPlatform}`) {\n\t\treturn undefined;\n\t}\n\tconst paths = resource.path.split('/');\n\tif (!paths[3]) {\n\t\treturn undefined;\n\t}\n\tpaths[3] = `${paths[3]}+${targetPlatform}`;\n\treturn resource.with({ query: null, path: paths.join('/') });\n}\n\nexport abstract class AbstractExtensionResourceLoaderService implements IExtensionResourceLoaderService {\n\n\treadonly _serviceBrand: undefined;\n\n\tprivate readonly _webExtensionResourceEndPoint: string;\n\tprivate readonly _extensionGalleryResourceUrlTemplate: string | undefined;\n\tprivate readonly _extensionGalleryAuthority: string | undefined;\n\n\tconstructor(\n\t\tprotected readonly _fileService: IFileService,\n\t\tprivate readonly _storageService: IStorageService,\n\t\tprivate readonly _productService: IProductService,\n\t\tprivate readonly _environmentService: IEnvironmentService,\n\t\tprivate readonly _configurationService: IConfigurationService,\n\t) {\n\t\tthis._webExtensionResourceEndPoint = `${getRemoteServerRootPath(_productService)}/${WEB_EXTENSION_RESOURCE_END_POINT}/`;\n\t\tif (_productService.extensionsGallery) {\n\t\t\tthis._extensionGalleryResourceUrlTemplate = _productService.extensionsGallery.resourceUrlTemplate;\n\t\t\tthis._extensionGalleryAuthority = this._extensionGalleryResourceUrlTemplate ? this._getExtensionGalleryAuthority(URI.parse(this._extensionGalleryResourceUrlTemplate)) : undefined;\n\t\t}\n\t}\n\n\tpublic get supportsExtensionGalleryResources(): boolean {\n\t\treturn this._extensionGalleryResourceUrlTemplate !== undefined;\n\t}\n\n\tpublic getExtensionGalleryResourceURL({ publisher, name, version, targetPlatform }: { publisher: string; name: string; version: string; targetPlatform?: TargetPlatform }, path?: string): URI | undefined {\n\t\tif (this._extensionGalleryResourceUrlTemplate) {\n\t\t\tconst uri = URI.parse(format2(this._extensionGalleryResourceUrlTemplate, {\n\t\t\t\tpublisher,\n\t\t\t\tname,\n\t\t\t\tversion: targetPlatform !== undefined\n\t\t\t\t\t&& targetPlatform !== TargetPlatform.UNDEFINED\n\t\t\t\t\t&& targetPlatform !== TargetPlatform.UNKNOWN\n\t\t\t\t\t&& targetPlatform !== TargetPlatform.UNIVERSAL\n\t\t\t\t\t? `${version}+${targetPlatform}`\n\t\t\t\t\t: version,\n\t\t\t\tpath: 'extension'\n\t\t\t}));\n\t\t\treturn this._isWebExtensionResourceEndPoint(uri) ? uri.with({ scheme: RemoteAuthorities.getPreferredWebSchema() }) : uri;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tpublic abstract readExtensionResource(uri: URI): Promise;\n\n\tisExtensionGalleryResource(uri: URI): boolean {\n\t\treturn !!this._extensionGalleryAuthority && this._extensionGalleryAuthority === this._getExtensionGalleryAuthority(uri);\n\t}\n\n\tprotected async getExtensionGalleryRequestHeaders(): Promise {\n\t\tconst headers: IHeaders = {\n\t\t\t'X-Client-Name': `${this._productService.applicationName}${isWeb ? '-web' : ''}`,\n\t\t\t'X-Client-Version': this._productService.version\n\t\t};\n\t\tif (supportsTelemetry(this._productService, this._environmentService) && getTelemetryLevel(this._configurationService) === TelemetryLevel.USAGE) {\n\t\t\theaders['X-Machine-Id'] = await this._getServiceMachineId();\n\t\t}\n\t\tif (this._productService.commit) {\n\t\t\theaders['X-Client-Commit'] = this._productService.commit;\n\t\t}\n\t\treturn headers;\n\t}\n\n\tprivate _serviceMachineIdPromise: Promise | undefined;\n\tprivate _getServiceMachineId(): Promise {\n\t\tif (!this._serviceMachineIdPromise) {\n\t\t\tthis._serviceMachineIdPromise = getServiceMachineId(this._environmentService, this._fileService, this._storageService);\n\t\t}\n\t\treturn this._serviceMachineIdPromise;\n\t}\n\n\tprivate _getExtensionGalleryAuthority(uri: URI): string | undefined {\n\t\tif (this._isWebExtensionResourceEndPoint(uri)) {\n\t\t\treturn uri.authority;\n\t\t}\n\t\tconst index = uri.authority.indexOf('.');\n\t\treturn index !== -1 ? uri.authority.substring(index + 1) : undefined;\n\t}\n\n\tprotected _isWebExtensionResourceEndPoint(uri: URI): boolean {\n\t\treturn uri.path.startsWith(this._webExtensionResourceEndPoint);\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 { IHeaders } from 'vs/base/parts/request/common/request';\nimport { IConfigurationService } from 'vs/platform/configuration/common/configuration';\nimport { IEnvironmentService } from 'vs/platform/environment/common/environment';\nimport { getServiceMachineId } from 'vs/platform/externalServices/common/serviceMachineId';\nimport { IFileService } from 'vs/platform/files/common/files';\nimport { IProductService } from 'vs/platform/product/common/productService';\nimport { IStorageService } from 'vs/platform/storage/common/storage';\nimport { ITelemetryService, TelemetryLevel } from 'vs/platform/telemetry/common/telemetry';\nimport { getTelemetryLevel, supportsTelemetry } from 'vs/platform/telemetry/common/telemetryUtils';\n\nexport async function resolveMarketplaceHeaders(version: string,\n\tproductService: IProductService,\n\tenvironmentService: IEnvironmentService,\n\tconfigurationService: IConfigurationService,\n\tfileService: IFileService,\n\tstorageService: IStorageService | undefined,\n\ttelemetryService: ITelemetryService): Promise {\n\n\tconst headers: IHeaders = {\n\t\t'X-Market-Client-Id': `VSCode ${version}`,\n\t\t'User-Agent': `VSCode ${version} (${productService.nameShort})`\n\t};\n\n\tif (supportsTelemetry(productService, environmentService) && getTelemetryLevel(configurationService) === TelemetryLevel.USAGE) {\n\t\tconst serviceMachineId = await getServiceMachineId(environmentService, fileService, storageService);\n\t\theaders['X-Market-User-Id'] = serviceMachineId;\n\t\t// Send machineId as VSCode-SessionId so we can correlate telemetry events across different services\n\t\t// machineId can be undefined sometimes (eg: when launching from CLI), so send serviceMachineId instead otherwise\n\t\t// Marketplace will reject the request if there is no VSCode-SessionId header\n\t\theaders['VSCode-SessionId'] = telemetryService.machineId || serviceMachineId;\n\t}\n\n\treturn headers;\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { URI } from 'vs/base/common/uri';\nimport { IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement';\nimport { IExtensionResourceLoaderService } from 'vs/platform/extensionResourceLoader/common/extensionResourceLoader';\nimport { ILanguagePackItem, LanguagePackBaseService } from 'vs/platform/languagePacks/common/languagePacks';\nimport { ILogService } from 'vs/platform/log/common/log';\n\nexport class WebLanguagePacksService extends LanguagePackBaseService {\n\tconstructor(\n\t\t@IExtensionResourceLoaderService private readonly extensionResourceLoaderService: IExtensionResourceLoaderService,\n\t\t@IExtensionGalleryService extensionGalleryService: IExtensionGalleryService,\n\t\t@ILogService private readonly logService: ILogService\n\t) {\n\t\tsuper(extensionGalleryService);\n\t}\n\n\tasync getBuiltInExtensionTranslationsUri(id: string, language: string): Promise {\n\n\t\tconst queryTimeout = new CancellationTokenSource();\n\t\tsetTimeout(() => queryTimeout.cancel(), 1000);\n\n\t\t// First get the extensions that supports the language (there should only be one but just in case let's include more results)\n\t\tlet result;\n\t\ttry {\n\t\t\tresult = await this.extensionGalleryService.query({\n\t\t\t\ttext: `tag:\"lp-${language}\"`,\n\t\t\t\tpageSize: 5\n\t\t\t}, queryTimeout.token);\n\t\t} catch (err) {\n\t\t\tthis.logService.error(err);\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst languagePackExtensions = result.firstPage.find(e => e.properties.localizedLanguages?.length);\n\t\tif (!languagePackExtensions) {\n\t\t\tthis.logService.trace(`No language pack found for language ${language}`);\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// Then get the manifest for that extension\n\t\tconst manifestTimeout = new CancellationTokenSource();\n\t\tsetTimeout(() => queryTimeout.cancel(), 1000);\n\t\tconst manifest = await this.extensionGalleryService.getManifest(languagePackExtensions, manifestTimeout.token);\n\n\t\t// Find the translation from the language pack\n\t\tconst localization = manifest?.contributes?.localizations?.find(l => l.languageId === language);\n\t\tconst translation = localization?.translations.find(t => t.id === id);\n\t\tif (!translation) {\n\t\t\tthis.logService.trace(`No translation found for id '${id}, in ${manifest?.name}`);\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// get the resource uri and return it\n\t\tconst uri = this.extensionResourceLoaderService.getExtensionGalleryResourceURL({\n\t\t\t// If translation is defined then manifest should have been defined.\n\t\t\tname: manifest!.name,\n\t\t\tpublisher: manifest!.publisher,\n\t\t\tversion: manifest!.version\n\t\t});\n\t\tif (!uri) {\n\t\t\tthis.logService.trace('Gallery does not provide extension resources.');\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn URI.joinPath(uri, translation.path);\n\t}\n\n\t// Web doesn't have a concept of language packs, so we just return an empty array\n\tgetInstalledLanguages(): Promise {\n\t\treturn Promise.resolve([]);\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport type { IExtendedConfiguration, IExtendedTelemetryItem, ITelemetryItem, ITelemetryUnloadState } from '@microsoft/1ds-core-js';\nimport type { IChannelConfiguration, IXHROverride, PostChannel } from '@microsoft/1ds-post-js';\nimport { importAMDNodeModule } from 'vs/amdX';\nimport { onUnexpectedError } from 'vs/base/common/errors';\nimport { mixin } from 'vs/base/common/objects';\nimport { ITelemetryAppender, validateTelemetryData } from 'vs/platform/telemetry/common/telemetryUtils';\n\n// Interface type which is a subset of @microsoft/1ds-core-js AppInsightsCore.\n// Allows us to more easily build mock objects for testing as the interface is quite large and we only need a few properties.\nexport interface IAppInsightsCore {\n\tpluginVersionString: string;\n\ttrack(item: ITelemetryItem | IExtendedTelemetryItem): void;\n\tunload(isAsync: boolean, unloadComplete: (unloadState: ITelemetryUnloadState) => void): void;\n}\n\nconst endpointUrl = 'https://mobile.events.data.microsoft.com/OneCollector/1.0';\nconst endpointHealthUrl = 'https://mobile.events.data.microsoft.com/ping';\n\nasync function getClient(instrumentationKey: string, addInternalFlag?: boolean, xhrOverride?: IXHROverride): Promise {\n\tconst oneDs = await importAMDNodeModule('@microsoft/1ds-core-js', 'dist/ms.core.js');\n\tconst postPlugin = await importAMDNodeModule('@microsoft/1ds-post-js', 'dist/ms.post.js');\n\tconst appInsightsCore = new oneDs.AppInsightsCore();\n\tconst collectorChannelPlugin: PostChannel = new postPlugin.PostChannel();\n\t// Configure the app insights core to send to collector++ and disable logging of debug info\n\tconst coreConfig: IExtendedConfiguration = {\n\t\tinstrumentationKey,\n\t\tendpointUrl,\n\t\tloggingLevelTelemetry: 0,\n\t\tloggingLevelConsole: 0,\n\t\tdisableCookiesUsage: true,\n\t\tdisableDbgExt: true,\n\t\tdisableInstrumentationKeyValidation: true,\n\t\tchannels: [[\n\t\t\tcollectorChannelPlugin\n\t\t]]\n\t};\n\n\tif (xhrOverride) {\n\t\tcoreConfig.extensionConfig = {};\n\t\t// Configure the channel to use a XHR Request override since it's not available in node\n\t\tconst channelConfig: IChannelConfiguration = {\n\t\t\talwaysUseXhrOverride: true,\n\t\t\tignoreMc1Ms0CookieProcessing: true,\n\t\t\thttpXHROverride: xhrOverride\n\t\t};\n\t\tcoreConfig.extensionConfig[collectorChannelPlugin.identifier] = channelConfig;\n\t}\n\n\tappInsightsCore.initialize(coreConfig, []);\n\n\tappInsightsCore.addTelemetryInitializer((envelope) => {\n\t\t// Opt the user out of 1DS data sharing\n\t\tenvelope['ext'] = envelope['ext'] ?? {};\n\t\tenvelope['ext']['web'] = envelope['ext']['web'] ?? {};\n\t\tenvelope['ext']['web']['consentDetails'] = '{\"GPC_DataSharingOptIn\":false}';\n\n\t\tif (addInternalFlag) {\n\t\t\tenvelope['ext']['utc'] = envelope['ext']['utc'] ?? {};\n\t\t\t// Sets it to be internal only based on Windows UTC flagging\n\t\t\tenvelope['ext']['utc']['flags'] = 0x0000811ECD;\n\t\t}\n\t});\n\n\treturn appInsightsCore;\n}\n\n// TODO @lramos15 maybe make more in line with src/vs/platform/telemetry/browser/appInsightsAppender.ts with caching support\nexport abstract class AbstractOneDataSystemAppender implements ITelemetryAppender {\n\n\tprotected _aiCoreOrKey: IAppInsightsCore | string | undefined;\n\tprivate _asyncAiCore: Promise | null;\n\tprotected readonly endPointUrl = endpointUrl;\n\tprotected readonly endPointHealthUrl = endpointHealthUrl;\n\n\tconstructor(\n\t\tprivate readonly _isInternalTelemetry: boolean,\n\t\tprivate _eventPrefix: string,\n\t\tprivate _defaultData: { [key: string]: any } | null,\n\t\tiKeyOrClientFactory: string | (() => IAppInsightsCore), // allow factory function for testing\n\t\tprivate _xhrOverride?: IXHROverride\n\t) {\n\t\tif (!this._defaultData) {\n\t\t\tthis._defaultData = {};\n\t\t}\n\n\t\tif (typeof iKeyOrClientFactory === 'function') {\n\t\t\tthis._aiCoreOrKey = iKeyOrClientFactory();\n\t\t} else {\n\t\t\tthis._aiCoreOrKey = iKeyOrClientFactory;\n\t\t}\n\t\tthis._asyncAiCore = null;\n\t}\n\n\tprivate _withAIClient(callback: (aiCore: IAppInsightsCore) => void): void {\n\t\tif (!this._aiCoreOrKey) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (typeof this._aiCoreOrKey !== 'string') {\n\t\t\tcallback(this._aiCoreOrKey);\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this._asyncAiCore) {\n\t\t\tthis._asyncAiCore = getClient(this._aiCoreOrKey, this._isInternalTelemetry, this._xhrOverride);\n\t\t}\n\n\t\tthis._asyncAiCore.then(\n\t\t\t(aiClient) => {\n\t\t\t\tcallback(aiClient);\n\t\t\t},\n\t\t\t(err) => {\n\t\t\t\tonUnexpectedError(err);\n\t\t\t\tconsole.error(err);\n\t\t\t}\n\t\t);\n\t}\n\n\tlog(eventName: string, data?: any): void {\n\t\tif (!this._aiCoreOrKey) {\n\t\t\treturn;\n\t\t}\n\t\tdata = mixin(data, this._defaultData);\n\t\tdata = validateTelemetryData(data);\n\t\tconst name = this._eventPrefix + '/' + eventName;\n\n\t\ttry {\n\t\t\tthis._withAIClient((aiClient) => {\n\t\t\t\taiClient.pluginVersionString = data?.properties.version ?? 'Unknown';\n\t\t\t\taiClient.track({\n\t\t\t\t\tname,\n\t\t\t\t\tbaseData: { name, properties: data?.properties, measurements: data?.measurements }\n\t\t\t\t});\n\t\t\t});\n\t\t} catch { }\n\t}\n\n\tflush(): Promise {\n\t\tif (this._aiCoreOrKey) {\n\t\t\treturn new Promise(resolve => {\n\t\t\t\tthis._withAIClient((aiClient) => {\n\t\t\t\t\taiClient.unload(true, () => {\n\t\t\t\t\t\tthis._aiCoreOrKey = undefined;\n\t\t\t\t\t\tresolve(undefined);\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\t\treturn Promise.resolve(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 { AbstractOneDataSystemAppender, IAppInsightsCore } from 'vs/platform/telemetry/common/1dsAppender';\n\n\nexport class OneDataSystemWebAppender extends AbstractOneDataSystemAppender {\n\tconstructor(\n\t\tisInternalTelemetry: boolean,\n\t\teventPrefix: string,\n\t\tdefaultData: { [key: string]: any } | null,\n\t\tiKeyOrClientFactory: string | (() => IAppInsightsCore), // allow factory function for testing\n\t) {\n\t\tsuper(isInternalTelemetry, eventPrefix, defaultData, iKeyOrClientFactory);\n\n\t\t// If we cannot fetch the endpoint it means it is down and we should not send any telemetry.\n\t\t// This is most likely due to ad blockers\n\t\tfetch(this.endPointHealthUrl, { method: 'GET' }).catch(err => {\n\t\t\tthis._aiCoreOrKey = 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 { Disposable } from 'vs/base/common/lifecycle';\nimport { localize } from 'vs/nls';\nimport { IEnvironmentService } from 'vs/platform/environment/common/environment';\nimport { ILogService, ILogger, ILoggerService, LogLevel } from 'vs/platform/log/common/log';\nimport { IProductService } from 'vs/platform/product/common/productService';\nimport { ITelemetryAppender, isLoggingOnly, supportsTelemetry, telemetryLogId, validateTelemetryData } from 'vs/platform/telemetry/common/telemetryUtils';\n\nexport class TelemetryLogAppender extends Disposable implements ITelemetryAppender {\n\n\tprivate readonly logger: ILogger;\n\n\tconstructor(\n\t\t@ILogService logService: ILogService,\n\t\t@ILoggerService loggerService: ILoggerService,\n\t\t@IEnvironmentService environmentService: IEnvironmentService,\n\t\t@IProductService productService: IProductService,\n\t\tprivate readonly prefix: string = '',\n\t) {\n\t\tsuper();\n\n\t\tconst logger = loggerService.getLogger(telemetryLogId);\n\t\tif (logger) {\n\t\t\tthis.logger = this._register(logger);\n\t\t} else {\n\t\t\t// Not a perfect check, but a nice way to indicate if we only have logging enabled for debug purposes and nothing is actually being sent\n\t\t\tconst justLoggingAndNotSending = isLoggingOnly(productService, environmentService);\n\t\t\tconst logSuffix = justLoggingAndNotSending ? ' (Not Sent)' : '';\n\t\t\tconst isVisible = () => supportsTelemetry(productService, environmentService) && logService.getLevel() === LogLevel.Trace;\n\t\t\tthis.logger = this._register(loggerService.createLogger(telemetryLogId, { name: localize('telemetryLog', \"Telemetry{0}\", logSuffix), hidden: !isVisible() }));\n\t\t\tthis._register(logService.onDidChangeLogLevel(() => loggerService.setVisibility(telemetryLogId, isVisible())));\n\t\t\tthis.logger.info('Below are logs for every telemetry event sent from VS Code once the log level is set to trace.');\n\t\t\tthis.logger.info('===========================================================');\n\t\t}\n\t}\n\n\tflush(): Promise {\n\t\treturn Promise.resolve(undefined);\n\t}\n\n\tlog(eventName: string, data: any): void {\n\t\tthis.logger.trace(`${this.prefix}telemetry/${eventName}`, validateTelemetryData(data));\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 { DisposableStore } from 'vs/base/common/lifecycle';\nimport { mixin } from 'vs/base/common/objects';\nimport { isWeb } from 'vs/base/common/platform';\nimport { escapeRegExpCharacters } from 'vs/base/common/strings';\nimport { localize } from 'vs/nls';\nimport { IConfigurationService } from 'vs/platform/configuration/common/configuration';\nimport { ConfigurationScope, Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';\nimport product from 'vs/platform/product/common/product';\nimport { IProductService } from 'vs/platform/product/common/productService';\nimport { Registry } from 'vs/platform/registry/common/platform';\nimport { ClassifiedEvent, IGDPRProperty, OmitMetadata, StrictPropertyCheck } from 'vs/platform/telemetry/common/gdprTypings';\nimport { ITelemetryData, ITelemetryService, TelemetryConfiguration, TelemetryLevel, TELEMETRY_CRASH_REPORTER_SETTING_ID, TELEMETRY_OLD_SETTING_ID, TELEMETRY_SECTION_ID, TELEMETRY_SETTING_ID, ICommonProperties } from 'vs/platform/telemetry/common/telemetry';\nimport { cleanData, getTelemetryLevel, ITelemetryAppender } from 'vs/platform/telemetry/common/telemetryUtils';\n\nexport interface ITelemetryServiceConfig {\n\tappenders: ITelemetryAppender[];\n\tsendErrorTelemetry?: boolean;\n\tcommonProperties?: ICommonProperties;\n\tpiiPaths?: string[];\n}\n\nexport class TelemetryService implements ITelemetryService {\n\n\tstatic readonly IDLE_START_EVENT_NAME = 'UserIdleStart';\n\tstatic readonly IDLE_STOP_EVENT_NAME = 'UserIdleStop';\n\n\tdeclare readonly _serviceBrand: undefined;\n\n\treadonly sessionId: string;\n\treadonly machineId: string;\n\treadonly sqmId: string;\n\treadonly firstSessionDate: string;\n\treadonly msftInternal: boolean | undefined;\n\n\tprivate _appenders: ITelemetryAppender[];\n\tprivate _commonProperties: ICommonProperties;\n\tprivate _experimentProperties: { [name: string]: string } = {};\n\tprivate _piiPaths: string[];\n\tprivate _telemetryLevel: TelemetryLevel;\n\tprivate _sendErrorTelemetry: boolean;\n\n\tprivate readonly _disposables = new DisposableStore();\n\tprivate _cleanupPatterns: RegExp[] = [];\n\n\tconstructor(\n\t\tconfig: ITelemetryServiceConfig,\n\t\t@IConfigurationService private _configurationService: IConfigurationService,\n\t\t@IProductService private _productService: IProductService\n\t) {\n\t\tthis._appenders = config.appenders;\n\t\tthis._commonProperties = config.commonProperties ?? Object.create(null);\n\n\t\tthis.sessionId = this._commonProperties['sessionID'] as string;\n\t\tthis.machineId = this._commonProperties['common.machineId'] as string;\n\t\tthis.sqmId = this._commonProperties['common.sqmId'] as string;\n\t\tthis.firstSessionDate = this._commonProperties['common.firstSessionDate'] as string;\n\t\tthis.msftInternal = this._commonProperties['common.msftInternal'] as boolean | undefined;\n\n\t\tthis._piiPaths = config.piiPaths || [];\n\t\tthis._telemetryLevel = TelemetryLevel.USAGE;\n\t\tthis._sendErrorTelemetry = !!config.sendErrorTelemetry;\n\n\t\t// static cleanup pattern for: `vscode-file:///DANGEROUS/PATH/resources/app/Useful/Information`\n\t\tthis._cleanupPatterns = [/(vscode-)?file:\\/\\/\\/.*?\\/resources\\/app\\//gi];\n\n\t\tfor (const piiPath of this._piiPaths) {\n\t\t\tthis._cleanupPatterns.push(new RegExp(escapeRegExpCharacters(piiPath), 'gi'));\n\n\t\t\tif (piiPath.indexOf('\\\\') >= 0) {\n\t\t\t\tthis._cleanupPatterns.push(new RegExp(escapeRegExpCharacters(piiPath.replace(/\\\\/g, '/')), 'gi'));\n\t\t\t}\n\t\t}\n\n\t\tthis._updateTelemetryLevel();\n\t\tthis._disposables.add(this._configurationService.onDidChangeConfiguration(e => {\n\t\t\t// Check on the telemetry settings and update the state if changed\n\t\t\tconst affectsTelemetryConfig =\n\t\t\t\te.affectsConfiguration(TELEMETRY_SETTING_ID)\n\t\t\t\t|| e.affectsConfiguration(TELEMETRY_OLD_SETTING_ID)\n\t\t\t\t|| e.affectsConfiguration(TELEMETRY_CRASH_REPORTER_SETTING_ID);\n\t\t\tif (affectsTelemetryConfig) {\n\t\t\t\tthis._updateTelemetryLevel();\n\t\t\t}\n\t\t}));\n\t}\n\n\tsetExperimentProperty(name: string, value: string): void {\n\t\tthis._experimentProperties[name] = value;\n\t}\n\n\tprivate _updateTelemetryLevel(): void {\n\t\tlet level = getTelemetryLevel(this._configurationService);\n\t\tconst collectableTelemetry = this._productService.enabledTelemetryLevels;\n\t\t// Also ensure that error telemetry is respecting the product configuration for collectable telemetry\n\t\tif (collectableTelemetry) {\n\t\t\tthis._sendErrorTelemetry = this.sendErrorTelemetry ? collectableTelemetry.error : false;\n\t\t\t// Make sure the telemetry level from the service is the minimum of the config and product\n\t\t\tconst maxCollectableTelemetryLevel = collectableTelemetry.usage ? TelemetryLevel.USAGE : collectableTelemetry.error ? TelemetryLevel.ERROR : TelemetryLevel.NONE;\n\t\t\tlevel = Math.min(level, maxCollectableTelemetryLevel);\n\t\t}\n\n\t\tthis._telemetryLevel = level;\n\t}\n\n\tget sendErrorTelemetry(): boolean {\n\t\treturn this._sendErrorTelemetry;\n\t}\n\n\tget telemetryLevel(): TelemetryLevel {\n\t\treturn this._telemetryLevel;\n\t}\n\n\tdispose(): void {\n\t\tthis._disposables.dispose();\n\t}\n\n\tprivate _log(eventName: string, eventLevel: TelemetryLevel, data?: ITelemetryData) {\n\t\t// don't send events when the user is optout\n\t\tif (this._telemetryLevel < eventLevel) {\n\t\t\treturn;\n\t\t}\n\n\t\t// add experiment properties\n\t\tdata = mixin(data, this._experimentProperties);\n\n\t\t// remove all PII from data\n\t\tdata = cleanData(data as Record, this._cleanupPatterns);\n\n\t\t// add common properties\n\t\tdata = mixin(data, this._commonProperties);\n\n\t\t// Log to the appenders of sufficient level\n\t\tthis._appenders.forEach(a => a.log(eventName, data));\n\t}\n\n\tpublicLog(eventName: string, data?: ITelemetryData) {\n\t\tthis._log(eventName, TelemetryLevel.USAGE, data);\n\t}\n\n\tpublicLog2> = never, T extends IGDPRProperty = never>(eventName: string, data?: StrictPropertyCheck) {\n\t\tthis.publicLog(eventName, data as ITelemetryData);\n\t}\n\n\tpublicLogError(errorEventName: string, data?: ITelemetryData) {\n\t\tif (!this._sendErrorTelemetry) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Send error event and anonymize paths\n\t\tthis._log(errorEventName, TelemetryLevel.ERROR, data);\n\t}\n\n\tpublicLogError2> = never, T extends IGDPRProperty = never>(eventName: string, data?: StrictPropertyCheck) {\n\t\tthis.publicLogError(eventName, data as ITelemetryData);\n\t}\n}\n\nfunction getTelemetryLevelSettingDescription(): string {\n\tconst telemetryText = localize('telemetry.telemetryLevelMd', \"Controls {0} telemetry, first-party extension telemetry, and participating third-party extension telemetry. Some third party extensions might not respect this setting. Consult the specific extension's documentation to be sure. Telemetry helps us better understand how {0} is performing, where improvements need to be made, and how features are being used.\", product.nameLong);\n\tconst externalLinksStatement = !product.privacyStatementUrl ?\n\t\tlocalize(\"telemetry.docsStatement\", \"Read more about the [data we collect]({0}).\", 'https://aka.ms/vscode-telemetry') :\n\t\tlocalize(\"telemetry.docsAndPrivacyStatement\", \"Read more about the [data we collect]({0}) and our [privacy statement]({1}).\", 'https://aka.ms/vscode-telemetry', product.privacyStatementUrl);\n\tconst restartString = !isWeb ? localize('telemetry.restart', 'A full restart of the application is necessary for crash reporting changes to take effect.') : '';\n\n\tconst crashReportsHeader = localize('telemetry.crashReports', \"Crash Reports\");\n\tconst errorsHeader = localize('telemetry.errors', \"Error Telemetry\");\n\tconst usageHeader = localize('telemetry.usage', \"Usage Data\");\n\n\tconst telemetryTableDescription = localize('telemetry.telemetryLevel.tableDescription', \"The following table outlines the data sent with each setting:\");\n\tconst telemetryTable = `\n| | ${crashReportsHeader} | ${errorsHeader} | ${usageHeader} |\n|:------|:---------------------:|:---------------:|:--------------:|\n| all | ✓ | ✓ | ✓ |\n| error | ✓ | ✓ | - |\n| crash | ✓ | - | - |\n| off | - | - | - |\n`;\n\n\tconst deprecatedSettingNote = localize('telemetry.telemetryLevel.deprecated', \"****Note:*** If this setting is 'off', no telemetry will be sent regardless of other telemetry settings. If this setting is set to anything except 'off' and telemetry is disabled with deprecated settings, no telemetry will be sent.*\");\n\tconst telemetryDescription = `\n${telemetryText} ${externalLinksStatement} ${restartString}\n\n \n\n${telemetryTableDescription}\n${telemetryTable}\n\n \n\n${deprecatedSettingNote}\n`;\n\n\treturn telemetryDescription;\n}\n\nRegistry.as(Extensions.Configuration).registerConfiguration({\n\t'id': TELEMETRY_SECTION_ID,\n\t'order': 1,\n\t'type': 'object',\n\t'title': localize('telemetryConfigurationTitle', \"Telemetry\"),\n\t'properties': {\n\t\t[TELEMETRY_SETTING_ID]: {\n\t\t\t'type': 'string',\n\t\t\t'enum': [TelemetryConfiguration.ON, TelemetryConfiguration.ERROR, TelemetryConfiguration.CRASH, TelemetryConfiguration.OFF],\n\t\t\t'enumDescriptions': [\n\t\t\t\tlocalize('telemetry.telemetryLevel.default', \"Sends usage data, errors, and crash reports.\"),\n\t\t\t\tlocalize('telemetry.telemetryLevel.error', \"Sends general error telemetry and crash reports.\"),\n\t\t\t\tlocalize('telemetry.telemetryLevel.crash', \"Sends OS level crash reports.\"),\n\t\t\t\tlocalize('telemetry.telemetryLevel.off', \"Disables all product telemetry.\")\n\t\t\t],\n\t\t\t'markdownDescription': getTelemetryLevelSettingDescription(),\n\t\t\t'default': TelemetryConfiguration.ON,\n\t\t\t'restricted': true,\n\t\t\t'scope': ConfigurationScope.APPLICATION,\n\t\t\t'tags': ['usesOnlineServices', 'telemetry']\n\t\t}\n\t}\n});\n\n// Deprecated telemetry setting\nRegistry.as(Extensions.Configuration).registerConfiguration({\n\t'id': TELEMETRY_SECTION_ID,\n\t'order': 110,\n\t'type': 'object',\n\t'title': localize('telemetryConfigurationTitle', \"Telemetry\"),\n\t'properties': {\n\t\t[TELEMETRY_OLD_SETTING_ID]: {\n\t\t\t'type': 'boolean',\n\t\t\t'markdownDescription':\n\t\t\t\t!product.privacyStatementUrl ?\n\t\t\t\t\tlocalize('telemetry.enableTelemetry', \"Enable diagnostic data to be collected. This helps us to better understand how {0} is performing and where improvements need to be made.\", product.nameLong) :\n\t\t\t\t\tlocalize('telemetry.enableTelemetryMd', \"Enable diagnostic data to be collected. This helps us to better understand how {0} is performing and where improvements need to be made. [Read more]({1}) about what we collect and our privacy statement.\", product.nameLong, product.privacyStatementUrl),\n\t\t\t'default': true,\n\t\t\t'restricted': true,\n\t\t\t'markdownDeprecationMessage': localize('enableTelemetryDeprecated', \"If this setting is false, no telemetry will be sent regardless of the new setting's value. Deprecated in favor of the {0} setting.\", `\\`#${TELEMETRY_SETTING_ID}#\\``),\n\t\t\t'scope': ConfigurationScope.APPLICATION,\n\t\t\t'tags': ['usesOnlineServices', 'telemetry']\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 { Emitter } from 'vs/base/common/event';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { IBufferMarkCapability, TerminalCapability, IMarkProperties } from 'vs/platform/terminal/common/capabilities/capabilities';\n// Importing types is safe in any layer\n// eslint-disable-next-line local/code-import-patterns\nimport type { IMarker, Terminal } from '@xterm/headless';\n\n/**\n * Manages \"marks\" in the buffer which are lines that are tracked when lines are added to or removed\n * from the buffer.\n */\nexport class BufferMarkCapability extends Disposable implements IBufferMarkCapability {\n\n\treadonly type = TerminalCapability.BufferMarkDetection;\n\n\tprivate _idToMarkerMap: Map = new Map();\n\tprivate _anonymousMarkers: Map = new Map();\n\n\tprivate readonly _onMarkAdded = this._register(new Emitter());\n\treadonly onMarkAdded = this._onMarkAdded.event;\n\n\tconstructor(\n\t\tprivate readonly _terminal: Terminal\n\t) {\n\t\tsuper();\n\t}\n\n\t*markers(): IterableIterator {\n\t\tfor (const m of this._idToMarkerMap.values()) {\n\t\t\tyield m;\n\t\t}\n\t\tfor (const m of this._anonymousMarkers.values()) {\n\t\t\tyield m;\n\t\t}\n\t}\n\n\taddMark(properties?: IMarkProperties): void {\n\t\tconst marker = properties?.marker || this._terminal.registerMarker();\n\t\tconst id = properties?.id;\n\t\tif (!marker) {\n\t\t\treturn;\n\t\t}\n\t\tif (id) {\n\t\t\tthis._idToMarkerMap.set(id, marker);\n\t\t\tmarker.onDispose(() => this._idToMarkerMap.delete(id));\n\t\t} else {\n\t\t\tthis._anonymousMarkers.set(marker.id, marker);\n\t\t\tmarker.onDispose(() => this._anonymousMarkers.delete(marker.id));\n\t\t}\n\t\tthis._onMarkAdded.fire({ marker, id, hidden: properties?.hidden, hoverMessage: properties?.hoverMessage });\n\t}\n\n\tgetMark(id: string): IMarker | undefined {\n\t\treturn this._idToMarkerMap.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 { IMarkProperties, IMarker, ISerializedTerminalCommand, ITerminalCommand, IXtermMarker } from 'vs/platform/terminal/common/capabilities/capabilities';\nimport { ITerminalOutputMatcher, ITerminalOutputMatch } from 'vs/platform/terminal/common/terminal';\n\n// Importing types is safe in any layer\n// eslint-disable-next-line local/code-import-patterns\nimport type { IBuffer, IBufferLine, Terminal } from '@xterm/headless';\n\nexport interface ITerminalCommandProperties {\n\tcommand: string;\n\tisTrusted: boolean;\n\ttimestamp: number;\n\tduration: number;\n\tmarker: IXtermMarker | undefined;\n\tcwd: string | undefined;\n\texitCode: number | undefined;\n\tcommandStartLineContent: string | undefined;\n\tmarkProperties: IMarkProperties | undefined;\n\texecutedX: number | undefined;\n\tstartX: number | undefined;\n\n\tpromptStartMarker?: IMarker | undefined;\n\tendMarker?: IXtermMarker | undefined;\n\texecutedMarker?: IXtermMarker | undefined;\n\taliases?: string[][] | undefined;\n\twasReplayed?: boolean | undefined;\n}\n\nexport class TerminalCommand implements ITerminalCommand {\n\n\tget command() { return this._properties.command; }\n\tget isTrusted() { return this._properties.isTrusted; }\n\tget timestamp() { return this._properties.timestamp; }\n\tget duration() { return this._properties.duration; }\n\tget promptStartMarker() { return this._properties.promptStartMarker; }\n\tget marker() { return this._properties.marker; }\n\tget endMarker() { return this._properties.endMarker; }\n\tset endMarker(value: IXtermMarker | undefined) { this._properties.endMarker = value; }\n\tget executedMarker() { return this._properties.executedMarker; }\n\tget aliases() { return this._properties.aliases; }\n\tget wasReplayed() { return this._properties.wasReplayed; }\n\tget cwd() { return this._properties.cwd; }\n\tget exitCode() { return this._properties.exitCode; }\n\tget commandStartLineContent() { return this._properties.commandStartLineContent; }\n\tget markProperties() { return this._properties.markProperties; }\n\tget executedX() { return this._properties.executedX; }\n\tget startX() { return this._properties.startX; }\n\n\tconstructor(\n\t\tprivate readonly _xterm: Terminal,\n\t\tprivate readonly _properties: ITerminalCommandProperties,\n\t) {\n\t}\n\n\tstatic deserialize(xterm: Terminal, serialized: ISerializedTerminalCommand & Required>, isCommandStorageDisabled: boolean): TerminalCommand | undefined {\n\t\tconst buffer = xterm.buffer.normal;\n\t\tconst marker = serialized.startLine !== undefined ? xterm.registerMarker(serialized.startLine - (buffer.baseY + buffer.cursorY)) : undefined;\n\n\t\t// Check for invalid command\n\t\tif (!marker) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst promptStartMarker = serialized.promptStartLine !== undefined ? xterm.registerMarker(serialized.promptStartLine - (buffer.baseY + buffer.cursorY)) : undefined;\n\n\t\t// Valid full command\n\t\tconst endMarker = serialized.endLine !== undefined ? xterm.registerMarker(serialized.endLine - (buffer.baseY + buffer.cursorY)) : undefined;\n\t\tconst executedMarker = serialized.executedLine !== undefined ? xterm.registerMarker(serialized.executedLine - (buffer.baseY + buffer.cursorY)) : undefined;\n\t\tconst newCommand = new TerminalCommand(xterm, {\n\t\t\tcommand: isCommandStorageDisabled ? '' : serialized.command,\n\t\t\tisTrusted: serialized.isTrusted,\n\t\t\tpromptStartMarker,\n\t\t\tmarker,\n\t\t\tstartX: serialized.startX,\n\t\t\tendMarker,\n\t\t\texecutedMarker,\n\t\t\texecutedX: serialized.executedX,\n\t\t\ttimestamp: serialized.timestamp,\n\t\t\tduration: serialized.duration,\n\t\t\tcwd: serialized.cwd,\n\t\t\tcommandStartLineContent: serialized.commandStartLineContent,\n\t\t\texitCode: serialized.exitCode,\n\t\t\tmarkProperties: serialized.markProperties,\n\t\t\taliases: undefined,\n\t\t\twasReplayed: true\n\t\t});\n\t\treturn newCommand;\n\t}\n\n\tserialize(isCommandStorageDisabled: boolean): ISerializedTerminalCommand {\n\t\treturn {\n\t\t\tpromptStartLine: this.promptStartMarker?.line,\n\t\t\tstartLine: this.marker?.line,\n\t\t\tstartX: undefined,\n\t\t\tendLine: this.endMarker?.line,\n\t\t\texecutedLine: this.executedMarker?.line,\n\t\t\texecutedX: this.executedX,\n\t\t\tcommand: isCommandStorageDisabled ? '' : this.command,\n\t\t\tisTrusted: this.isTrusted,\n\t\t\tcwd: this.cwd,\n\t\t\texitCode: this.exitCode,\n\t\t\tcommandStartLineContent: this.commandStartLineContent,\n\t\t\ttimestamp: this.timestamp,\n\t\t\tduration: this.duration,\n\t\t\tmarkProperties: this.markProperties,\n\t\t};\n\t}\n\n\tgetOutput(): string | undefined {\n\t\tif (!this.executedMarker || !this.endMarker) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst startLine = this.executedMarker.line;\n\t\tconst endLine = this.endMarker.line;\n\n\t\tif (startLine === endLine) {\n\t\t\treturn undefined;\n\t\t}\n\t\tlet output = '';\n\t\tlet line: IBufferLine | undefined;\n\t\tfor (let i = startLine; i < endLine; i++) {\n\t\t\tline = this._xterm.buffer.active.getLine(i);\n\t\t\tif (!line) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\toutput += line.translateToString(!line.isWrapped) + (line.isWrapped ? '' : '\\n');\n\t\t}\n\t\treturn output === '' ? undefined : output;\n\t}\n\n\tgetOutputMatch(outputMatcher: ITerminalOutputMatcher): ITerminalOutputMatch | undefined {\n\t\t// TODO: Add back this check? this._ptyHeuristics.value instanceof WindowsPtyHeuristics && (executedMarker?.line === endMarker?.line) ? this._currentCommand.commandStartMarker : executedMarker\n\t\tif (!this.executedMarker || !this.endMarker) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst endLine = this.endMarker.line;\n\t\tif (endLine === -1) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst buffer = this._xterm.buffer.active;\n\t\tconst startLine = Math.max(this.executedMarker.line, 0);\n\t\tconst matcher = outputMatcher.lineMatcher;\n\t\tconst linesToCheck = typeof matcher === 'string' ? 1 : outputMatcher.length || countNewLines(matcher);\n\t\tconst lines: string[] = [];\n\t\tlet match: RegExpMatchArray | null | undefined;\n\t\tif (outputMatcher.anchor === 'bottom') {\n\t\t\tfor (let i = endLine - (outputMatcher.offset || 0); i >= startLine; i--) {\n\t\t\t\tlet wrappedLineStart = i;\n\t\t\t\tconst wrappedLineEnd = i;\n\t\t\t\twhile (wrappedLineStart >= startLine && buffer.getLine(wrappedLineStart)?.isWrapped) {\n\t\t\t\t\twrappedLineStart--;\n\t\t\t\t}\n\t\t\t\ti = wrappedLineStart;\n\t\t\t\tlines.unshift(getXtermLineContent(buffer, wrappedLineStart, wrappedLineEnd, this._xterm.cols));\n\t\t\t\tif (!match) {\n\t\t\t\t\tmatch = lines[0].match(matcher);\n\t\t\t\t}\n\t\t\t\tif (lines.length >= linesToCheck) {\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 = startLine + (outputMatcher.offset || 0); i < endLine; i++) {\n\t\t\t\tconst wrappedLineStart = i;\n\t\t\t\tlet wrappedLineEnd = i;\n\t\t\t\twhile (wrappedLineEnd + 1 < endLine && buffer.getLine(wrappedLineEnd + 1)?.isWrapped) {\n\t\t\t\t\twrappedLineEnd++;\n\t\t\t\t}\n\t\t\t\ti = wrappedLineEnd;\n\t\t\t\tlines.push(getXtermLineContent(buffer, wrappedLineStart, wrappedLineEnd, this._xterm.cols));\n\t\t\t\tif (!match) {\n\t\t\t\t\tmatch = lines[lines.length - 1].match(matcher);\n\t\t\t\t}\n\t\t\t\tif (lines.length >= linesToCheck) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn match ? { regexMatch: match, outputLines: lines } : undefined;\n\t}\n\n\thasOutput(): boolean {\n\t\treturn (\n\t\t\t!this.executedMarker?.isDisposed &&\n\t\t\t!this.endMarker?.isDisposed &&\n\t\t\t!!(\n\t\t\t\tthis.executedMarker &&\n\t\t\t\tthis.endMarker &&\n\t\t\t\tthis.executedMarker.line < this.endMarker.line\n\t\t\t)\n\t\t);\n\t}\n\n\tgetPromptRowCount(): number {\n\t\treturn getPromptRowCount(this, this._xterm.buffer.active);\n\t}\n\n\tgetCommandRowCount(): number {\n\t\treturn getCommandRowCount(this);\n\t}\n}\n\nexport interface ICurrentPartialCommand {\n\tpromptStartMarker?: IMarker;\n\n\tcommandStartMarker?: IMarker;\n\tcommandStartX?: number;\n\tcommandStartLineContent?: string;\n\n\tcommandRightPromptStartX?: number;\n\tcommandRightPromptEndX?: number;\n\n\tcommandLines?: IMarker;\n\n\tcommandExecutedMarker?: IMarker;\n\tcommandExecutedX?: number;\n\n\tcommandFinishedMarker?: IMarker;\n\n\tcurrentContinuationMarker?: IMarker;\n\tcontinuations?: { marker: IMarker; end: number }[];\n\n\tcommand?: string;\n\n\t/**\n\t * Whether the command line is trusted via a nonce.\n\t */\n\tisTrusted?: boolean;\n\n\t/**\n\t * Something invalidated the command before it finished, this will prevent the onCommandFinished\n\t * event from firing.\n\t */\n\tisInvalid?: boolean;\n\n\tgetPromptRowCount(): number;\n\tgetCommandRowCount(): number;\n}\n\nexport class PartialTerminalCommand implements ICurrentPartialCommand {\n\tpromptStartMarker?: IMarker;\n\n\tcommandStartMarker?: IMarker;\n\tcommandStartX?: number;\n\tcommandStartLineContent?: string;\n\n\tcommandRightPromptStartX?: number;\n\tcommandRightPromptEndX?: number;\n\n\tcommandLines?: IMarker;\n\n\tcommandExecutedMarker?: IMarker;\n\tcommandExecutedX?: number;\n\n\tprivate commandExecutedTimestamp?: number;\n\tprivate commandDuration?: number;\n\n\tcommandFinishedMarker?: IMarker;\n\n\tcurrentContinuationMarker?: IMarker;\n\tcontinuations?: { marker: IMarker; end: number }[];\n\n\tcommand?: string;\n\n\tisTrusted?: boolean;\n\tisInvalid?: boolean;\n\n\tconstructor(\n\t\tprivate readonly _xterm: Terminal,\n\t) {\n\t}\n\n\tserialize(cwd: string | undefined): ISerializedTerminalCommand | undefined {\n\t\tif (!this.commandStartMarker) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn {\n\t\t\tpromptStartLine: this.promptStartMarker?.line,\n\t\t\tstartLine: this.commandStartMarker.line,\n\t\t\tstartX: this.commandStartX,\n\t\t\tendLine: undefined,\n\t\t\texecutedLine: undefined,\n\t\t\texecutedX: undefined,\n\t\t\tcommand: '',\n\t\t\tisTrusted: true,\n\t\t\tcwd,\n\t\t\texitCode: undefined,\n\t\t\tcommandStartLineContent: undefined,\n\t\t\ttimestamp: 0,\n\t\t\tduration: 0,\n\t\t\tmarkProperties: undefined\n\t\t};\n\t}\n\n\tpromoteToFullCommand(cwd: string | undefined, exitCode: number | undefined, ignoreCommandLine: boolean, markProperties: IMarkProperties | undefined): TerminalCommand | undefined {\n\t\t// When the command finishes and executed never fires the placeholder selector should be used.\n\t\tif (exitCode === undefined && this.command === undefined) {\n\t\t\tthis.command = '';\n\t\t}\n\n\t\tif ((this.command !== undefined && !this.command.startsWith('\\\\')) || ignoreCommandLine) {\n\t\t\treturn new TerminalCommand(this._xterm, {\n\t\t\t\tcommand: ignoreCommandLine ? '' : (this.command || ''),\n\t\t\t\tisTrusted: !!this.isTrusted,\n\t\t\t\tpromptStartMarker: this.promptStartMarker,\n\t\t\t\tmarker: this.commandStartMarker,\n\t\t\t\tstartX: this.commandStartX,\n\t\t\t\tendMarker: this.commandFinishedMarker,\n\t\t\t\texecutedMarker: this.commandExecutedMarker,\n\t\t\t\texecutedX: this.commandExecutedX,\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t\tduration: this.commandDuration || 0,\n\t\t\t\tcwd,\n\t\t\t\texitCode,\n\t\t\t\tcommandStartLineContent: this.commandStartLineContent,\n\t\t\t\tmarkProperties\n\t\t\t});\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tmarkExecutedTime() {\n\t\tif (this.commandExecutedTimestamp === undefined) {\n\t\t\tthis.commandExecutedTimestamp = Date.now();\n\t\t}\n\t}\n\n\tmarkFinishedTime() {\n\t\tif (this.commandDuration === undefined && this.commandExecutedTimestamp !== undefined) {\n\t\t\tthis.commandDuration = Date.now() - this.commandExecutedTimestamp;\n\t\t}\n\t}\n\n\tgetPromptRowCount(): number {\n\t\treturn getPromptRowCount(this, this._xterm.buffer.active);\n\t}\n\n\tgetCommandRowCount(): number {\n\t\treturn getCommandRowCount(this);\n\t}\n}\n\nfunction getXtermLineContent(buffer: IBuffer, lineStart: number, lineEnd: number, cols: number): string {\n\t// Cap the maximum number of lines generated to prevent potential performance problems. This is\n\t// more of a sanity check as the wrapped line should already be trimmed down at this point.\n\tconst maxLineLength = Math.max(2048 / cols * 2);\n\tlineEnd = Math.min(lineEnd, lineStart + maxLineLength);\n\tlet content = '';\n\tfor (let i = lineStart; i <= lineEnd; i++) {\n\t\t// Make sure only 0 to cols are considered as resizing when windows mode is enabled will\n\t\t// retain buffer data outside of the terminal width as reflow is disabled.\n\t\tconst line = buffer.getLine(i);\n\t\tif (line) {\n\t\t\tcontent += line.translateToString(true, 0, cols);\n\t\t}\n\t}\n\treturn content;\n}\n\nfunction countNewLines(regex: RegExp): number {\n\tif (!regex.multiline) {\n\t\treturn 1;\n\t}\n\tconst source = regex.source;\n\tlet count = 1;\n\tlet i = source.indexOf('\\\\n');\n\twhile (i !== -1) {\n\t\tcount++;\n\t\ti = source.indexOf('\\\\n', i + 1);\n\t}\n\treturn count;\n}\n\nfunction getPromptRowCount(command: ITerminalCommand | ICurrentPartialCommand, buffer: IBuffer): number {\n\tconst marker = 'hasOutput' in command ? command.marker : command.commandStartMarker;\n\tif (!marker || !command.promptStartMarker) {\n\t\treturn 1;\n\t}\n\tlet promptRowCount = 1;\n\tlet promptStartLine = command.promptStartMarker.line;\n\t// Trim any leading whitespace-only lines to retain vertical space\n\twhile (promptStartLine < marker.line && (buffer.getLine(promptStartLine)?.translateToString(true) ?? '').length === 0) {\n\t\tpromptStartLine++;\n\t}\n\tpromptRowCount = marker.line - promptStartLine + 1;\n\treturn promptRowCount;\n}\n\nfunction getCommandRowCount(command: ITerminalCommand | ICurrentPartialCommand): number {\n\tconst marker = 'hasOutput' in command ? command.marker : command.commandStartMarker;\n\tconst executedMarker = 'hasOutput' in command ? command.executedMarker : command.commandExecutedMarker;\n\tif (!marker || !executedMarker) {\n\t\treturn 1;\n\t}\n\tconst commandExecutedLine = Math.max(executedMarker.line, marker.line);\n\tlet commandRowCount = commandExecutedLine - marker.line + 1;\n\t// Trim the last line if the cursor X is in the left-most cell\n\tconst executedX = 'hasOutput' in command ? command.executedX : command.commandExecutedX;\n\tif (executedX === 0) {\n\t\tcommandRowCount--;\n\t}\n\treturn commandRowCount;\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { debounce } from 'vs/base/common/decorators';\nimport { Emitter } from 'vs/base/common/event';\nimport { Disposable, MandatoryMutableDisposable, MutableDisposable } from 'vs/base/common/lifecycle';\nimport { ILogService } from 'vs/platform/log/common/log';\nimport { CommandInvalidationReason, ICommandDetectionCapability, ICommandInvalidationRequest, IHandleCommandOptions, ISerializedCommandDetectionCapability, ISerializedTerminalCommand, ITerminalCommand, IXtermMarker, TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities';\nimport { ITerminalOutputMatcher } from 'vs/platform/terminal/common/terminal';\n\n// Importing types is safe in any layer\n// eslint-disable-next-line local/code-import-patterns\nimport type { IBuffer, IDisposable, IMarker, Terminal } from '@xterm/headless';\nimport { ICurrentPartialCommand, PartialTerminalCommand, TerminalCommand } from 'vs/platform/terminal/common/capabilities/commandDetection/terminalCommand';\n\ninterface ITerminalDimensions {\n\tcols: number;\n\trows: number;\n}\n\nexport class CommandDetectionCapability extends Disposable implements ICommandDetectionCapability {\n\treadonly type = TerminalCapability.CommandDetection;\n\n\tprotected _commands: TerminalCommand[] = [];\n\tprivate _cwd: string | undefined;\n\tprivate _currentCommand: PartialTerminalCommand = new PartialTerminalCommand(this._terminal);\n\tprivate _commandMarkers: IMarker[] = [];\n\tprivate _dimensions: ITerminalDimensions;\n\tprivate __isCommandStorageDisabled: boolean = false;\n\tprivate _handleCommandStartOptions?: IHandleCommandOptions;\n\n\tprivate _commitCommandFinished?: RunOnceScheduler;\n\n\tprivate _ptyHeuristicsHooks: ICommandDetectionHeuristicsHooks;\n\tprivate _ptyHeuristics: MandatoryMutableDisposable;\n\n\tget commands(): readonly TerminalCommand[] { return this._commands; }\n\tget executingCommand(): string | undefined { return this._currentCommand.command; }\n\t// TODO: as is unsafe here and it duplicates behavor of executingCommand\n\tget executingCommandObject(): ITerminalCommand | undefined {\n\t\tif (this._currentCommand.commandStartMarker) {\n\t\t\treturn { marker: this._currentCommand.commandStartMarker } as ITerminalCommand;\n\t\t}\n\t\treturn undefined;\n\t}\n\tget currentCommand(): ICurrentPartialCommand {\n\t\treturn this._currentCommand;\n\t}\n\tget cwd(): string | undefined { return this._cwd; }\n\tprivate get _isInputting(): boolean {\n\t\treturn !!(this._currentCommand.commandStartMarker && !this._currentCommand.commandExecutedMarker);\n\t}\n\n\tget hasInput(): boolean | undefined {\n\t\tif (!this._isInputting || !this._currentCommand?.commandStartMarker) {\n\t\t\treturn undefined;\n\t\t}\n\t\tif (this._terminal.buffer.active.baseY + this._terminal.buffer.active.cursorY === this._currentCommand.commandStartMarker?.line) {\n\t\t\tconst line = this._terminal.buffer.active.getLine(this._terminal.buffer.active.cursorY)?.translateToString(true, this._currentCommand.commandStartX);\n\t\t\tif (line === undefined) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\treturn line.length > 0;\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivate readonly _onCommandStarted = this._register(new Emitter());\n\treadonly onCommandStarted = this._onCommandStarted.event;\n\tprivate readonly _onBeforeCommandFinished = this._register(new Emitter());\n\treadonly onBeforeCommandFinished = this._onBeforeCommandFinished.event;\n\tprivate readonly _onCommandFinished = this._register(new Emitter());\n\treadonly onCommandFinished = this._onCommandFinished.event;\n\tprivate readonly _onCommandExecuted = this._register(new Emitter());\n\treadonly onCommandExecuted = this._onCommandExecuted.event;\n\tprivate readonly _onCommandInvalidated = this._register(new Emitter());\n\treadonly onCommandInvalidated = this._onCommandInvalidated.event;\n\tprivate readonly _onCurrentCommandInvalidated = this._register(new Emitter());\n\treadonly onCurrentCommandInvalidated = this._onCurrentCommandInvalidated.event;\n\n\tconstructor(\n\t\tprivate readonly _terminal: Terminal,\n\t\tprivate readonly _logService: ILogService\n\t) {\n\t\tsuper();\n\n\t\t// Set up platform-specific behaviors\n\t\tconst that = this;\n\t\tthis._ptyHeuristicsHooks = new class implements ICommandDetectionHeuristicsHooks {\n\t\t\tget onCurrentCommandInvalidatedEmitter() { return that._onCurrentCommandInvalidated; }\n\t\t\tget onCommandStartedEmitter() { return that._onCommandStarted; }\n\t\t\tget onCommandExecutedEmitter() { return that._onCommandExecuted; }\n\t\t\tget dimensions() { return that._dimensions; }\n\t\t\tget isCommandStorageDisabled() { return that.__isCommandStorageDisabled; }\n\t\t\tget commandMarkers() { return that._commandMarkers; }\n\t\t\tset commandMarkers(value) { that._commandMarkers = value; }\n\t\t\tget clearCommandsInViewport() { return that._clearCommandsInViewport.bind(that); }\n\t\t\tcommitCommandFinished() {\n\t\t\t\tthat._commitCommandFinished?.flush();\n\t\t\t\tthat._commitCommandFinished = undefined;\n\t\t\t}\n\t\t};\n\t\tthis._ptyHeuristics = this._register(new MandatoryMutableDisposable(new UnixPtyHeuristics(this._terminal, this, this._ptyHeuristicsHooks, this._logService)));\n\n\t\tthis._dimensions = {\n\t\t\tcols: this._terminal.cols,\n\t\t\trows: this._terminal.rows\n\t\t};\n\t\tthis._register(this._terminal.onResize(e => this._handleResize(e)));\n\t\tthis._register(this._terminal.onCursorMove(() => this._handleCursorMove()));\n\t}\n\n\tprivate _handleResize(e: { cols: number; rows: number }) {\n\t\tthis._ptyHeuristics.value.preHandleResize?.(e);\n\t\tthis._dimensions.cols = e.cols;\n\t\tthis._dimensions.rows = e.rows;\n\t}\n\n\t@debounce(500)\n\tprivate _handleCursorMove() {\n\t\t// Early versions of conpty do not have real support for an alt buffer, in addition certain\n\t\t// commands such as tsc watch will write to the top of the normal buffer. The following\n\t\t// checks when the cursor has moved while the normal buffer is empty and if it is above the\n\t\t// current command, all decorations within the viewport will be invalidated.\n\t\t//\n\t\t// This function is debounced so that the cursor is only checked when it is stable so\n\t\t// conpty's screen reprinting will not trigger decoration clearing.\n\t\t//\n\t\t// This is mostly a workaround for Windows but applies to all OS' because of the tsc watch\n\t\t// case.\n\t\tif (this._terminal.buffer.active === this._terminal.buffer.normal && this._currentCommand.commandStartMarker) {\n\t\t\tif (this._terminal.buffer.active.baseY + this._terminal.buffer.active.cursorY < this._currentCommand.commandStartMarker.line) {\n\t\t\t\tthis._clearCommandsInViewport();\n\t\t\t\tthis._currentCommand.isInvalid = true;\n\t\t\t\tthis._onCurrentCommandInvalidated.fire({ reason: CommandInvalidationReason.Windows });\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _clearCommandsInViewport(): void {\n\t\t// Find the number of commands on the tail end of the array that are within the viewport\n\t\tlet count = 0;\n\t\tfor (let i = this._commands.length - 1; i >= 0; i--) {\n\t\t\tconst line = this._commands[i].marker?.line;\n\t\t\tif (line && line < this._terminal.buffer.active.baseY) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcount++;\n\t\t}\n\t\t// Remove them\n\t\tif (count > 0) {\n\t\t\tthis._onCommandInvalidated.fire(this._commands.splice(this._commands.length - count, count));\n\t\t}\n\t}\n\n\tsetCwd(value: string) {\n\t\tthis._cwd = value;\n\t}\n\n\tsetIsWindowsPty(value: boolean) {\n\t\tif (value && !(this._ptyHeuristics.value instanceof WindowsPtyHeuristics)) {\n\t\t\tconst that = this;\n\t\t\tthis._ptyHeuristics.value = new WindowsPtyHeuristics(\n\t\t\t\tthis._terminal,\n\t\t\t\tthis,\n\t\t\t\tnew class {\n\t\t\t\t\tget onCurrentCommandInvalidatedEmitter() { return that._onCurrentCommandInvalidated; }\n\t\t\t\t\tget onCommandStartedEmitter() { return that._onCommandStarted; }\n\t\t\t\t\tget onCommandExecutedEmitter() { return that._onCommandExecuted; }\n\t\t\t\t\tget dimensions() { return that._dimensions; }\n\t\t\t\t\tget isCommandStorageDisabled() { return that.__isCommandStorageDisabled; }\n\t\t\t\t\tget commandMarkers() { return that._commandMarkers; }\n\t\t\t\t\tset commandMarkers(value) { that._commandMarkers = value; }\n\t\t\t\t\tget clearCommandsInViewport() { return that._clearCommandsInViewport.bind(that); }\n\t\t\t\t\tcommitCommandFinished() {\n\t\t\t\t\t\tthat._commitCommandFinished?.flush();\n\t\t\t\t\t\tthat._commitCommandFinished = undefined;\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tthis._logService\n\t\t\t);\n\t\t} else if (!value && !(this._ptyHeuristics.value instanceof UnixPtyHeuristics)) {\n\t\t\tthis._ptyHeuristics.value = new UnixPtyHeuristics(this._terminal, this, this._ptyHeuristicsHooks, this._logService);\n\t\t}\n\t}\n\n\tsetIsCommandStorageDisabled(): void {\n\t\tthis.__isCommandStorageDisabled = true;\n\t}\n\n\tgetCommandForLine(line: number): ITerminalCommand | ICurrentPartialCommand | undefined {\n\t\t// Handle the current partial command first, anything below it's prompt is considered part\n\t\t// of the current command\n\t\tif (this._currentCommand.promptStartMarker && line >= this._currentCommand.promptStartMarker?.line) {\n\t\t\treturn this._currentCommand;\n\t\t}\n\n\t\t// No commands\n\t\tif (this._commands.length === 0) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// Line is before any registered commands\n\t\tif ((this._commands[0].promptStartMarker ?? this._commands[0].marker!).line > line) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// Iterate backwards through commands to find the right one\n\t\tfor (let i = this.commands.length - 1; i >= 0; i--) {\n\t\t\tif ((this.commands[i].promptStartMarker ?? this.commands[i].marker!).line <= line) {\n\t\t\t\treturn this.commands[i];\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tgetCwdForLine(line: number): string | undefined {\n\t\t// Handle the current partial command first, anything below it's prompt is considered part\n\t\t// of the current command\n\t\tif (this._currentCommand.promptStartMarker && line >= this._currentCommand.promptStartMarker?.line) {\n\t\t\treturn this._cwd;\n\t\t}\n\n\t\tconst command = this.getCommandForLine(line);\n\t\tif (command && 'cwd' in command) {\n\t\t\treturn command.cwd;\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\thandlePromptStart(options?: IHandleCommandOptions): void {\n\t\t// Adjust the last command's finished marker when needed. The standard position for the\n\t\t// finished marker `D` to appear is at the same position as the following prompt started\n\t\t// `A`.\n\t\tconst lastCommand = this.commands.at(-1);\n\t\tif (lastCommand?.endMarker && lastCommand?.executedMarker && lastCommand.endMarker.line === lastCommand.executedMarker.line) {\n\t\t\tthis._logService.debug('CommandDetectionCapability#handlePromptStart adjusted commandFinished', `${lastCommand.endMarker.line} -> ${lastCommand.executedMarker.line + 1}`);\n\t\t\tlastCommand.endMarker = cloneMarker(this._terminal, lastCommand.executedMarker, 1);\n\t\t}\n\n\t\tthis._currentCommand.promptStartMarker = options?.marker || (lastCommand?.endMarker ? cloneMarker(this._terminal, lastCommand.endMarker) : this._terminal.registerMarker(0));\n\n\t\tthis._logService.debug('CommandDetectionCapability#handlePromptStart', this._terminal.buffer.active.cursorX, this._currentCommand.promptStartMarker?.line);\n\t}\n\n\thandleContinuationStart(): void {\n\t\tthis._currentCommand.currentContinuationMarker = this._terminal.registerMarker(0);\n\t\tthis._logService.debug('CommandDetectionCapability#handleContinuationStart', this._currentCommand.currentContinuationMarker);\n\t}\n\n\thandleContinuationEnd(): void {\n\t\tif (!this._currentCommand.currentContinuationMarker) {\n\t\t\tthis._logService.warn('CommandDetectionCapability#handleContinuationEnd Received continuation end without start');\n\t\t\treturn;\n\t\t}\n\t\tif (!this._currentCommand.continuations) {\n\t\t\tthis._currentCommand.continuations = [];\n\t\t}\n\t\tthis._currentCommand.continuations.push({\n\t\t\tmarker: this._currentCommand.currentContinuationMarker,\n\t\t\tend: this._terminal.buffer.active.cursorX\n\t\t});\n\t\tthis._currentCommand.currentContinuationMarker = undefined;\n\t\tthis._logService.debug('CommandDetectionCapability#handleContinuationEnd', this._currentCommand.continuations[this._currentCommand.continuations.length - 1]);\n\t}\n\n\thandleRightPromptStart(): void {\n\t\tthis._currentCommand.commandRightPromptStartX = this._terminal.buffer.active.cursorX;\n\t\tthis._logService.debug('CommandDetectionCapability#handleRightPromptStart', this._currentCommand.commandRightPromptStartX);\n\t}\n\n\thandleRightPromptEnd(): void {\n\t\tthis._currentCommand.commandRightPromptEndX = this._terminal.buffer.active.cursorX;\n\t\tthis._logService.debug('CommandDetectionCapability#handleRightPromptEnd', this._currentCommand.commandRightPromptEndX);\n\t}\n\n\thandleCommandStart(options?: IHandleCommandOptions): void {\n\t\tthis._handleCommandStartOptions = options;\n\t\t// Only update the column if the line has already been set\n\t\tthis._currentCommand.commandStartMarker = options?.marker || this._currentCommand.commandStartMarker;\n\t\tif (this._currentCommand.commandStartMarker?.line === this._terminal.buffer.active.cursorY) {\n\t\t\tthis._currentCommand.commandStartX = this._terminal.buffer.active.cursorX;\n\t\t\tthis._logService.debug('CommandDetectionCapability#handleCommandStart', this._currentCommand.commandStartX, this._currentCommand.commandStartMarker?.line);\n\t\t\treturn;\n\t\t}\n\t\tthis._ptyHeuristics.value.handleCommandStart(options);\n\t}\n\n\thandleGenericCommand(options?: IHandleCommandOptions): void {\n\t\tif (options?.markProperties?.disableCommandStorage) {\n\t\t\tthis.setIsCommandStorageDisabled();\n\t\t}\n\t\tthis.handlePromptStart(options);\n\t\tthis.handleCommandStart(options);\n\t\tthis.handleCommandExecuted(options);\n\t\tthis.handleCommandFinished(undefined, options);\n\t}\n\n\thandleCommandExecuted(options?: IHandleCommandOptions): void {\n\t\tthis._ptyHeuristics.value.handleCommandExecuted(options);\n\t\tthis._currentCommand.markExecutedTime();\n\t}\n\n\thandleCommandFinished(exitCode: number | undefined, options?: IHandleCommandOptions): void {\n\t\tthis._currentCommand.markFinishedTime();\n\t\tthis._ptyHeuristics.value.preHandleCommandFinished?.();\n\n\t\tthis._logService.debug('CommandDetectionCapability#handleCommandFinished', this._terminal.buffer.active.cursorX, options?.marker?.line, this._currentCommand.command, this._currentCommand);\n\n\t\t// HACK: Handle a special case on some versions of bash where identical commands get merged\n\t\t// in the output of `history`, this detects that case and sets the exit code to the the last\n\t\t// command's exit code. This covered the majority of cases but will fail if the same command\n\t\t// runs with a different exit code, that will need a more robust fix where we send the\n\t\t// command ID and exit code over to the capability to adjust there.\n\t\tif (exitCode === undefined) {\n\t\t\tconst lastCommand = this.commands.length > 0 ? this.commands[this.commands.length - 1] : undefined;\n\t\t\tif (this._currentCommand.command && this._currentCommand.command.length > 0 && lastCommand?.command === this._currentCommand.command) {\n\t\t\t\texitCode = lastCommand.exitCode;\n\t\t\t}\n\t\t}\n\n\t\tif (this._currentCommand.commandStartMarker === undefined || !this._terminal.buffer.active) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._currentCommand.commandFinishedMarker = options?.marker || this._terminal.registerMarker(0);\n\n\t\tthis._ptyHeuristics.value.postHandleCommandFinished?.();\n\n\t\tconst newCommand = this._currentCommand.promoteToFullCommand(this._cwd, exitCode, this._handleCommandStartOptions?.ignoreCommandLine ?? false, options?.markProperties);\n\n\t\tif (newCommand) {\n\t\t\tthis._commands.push(newCommand);\n\t\t\tthis._commitCommandFinished = new RunOnceScheduler(() => {\n\t\t\t\tthis._onBeforeCommandFinished.fire(newCommand);\n\t\t\t\tif (!this._currentCommand.isInvalid) {\n\t\t\t\t\tthis._logService.debug('CommandDetectionCapability#onCommandFinished', newCommand);\n\t\t\t\t\tthis._onCommandFinished.fire(newCommand);\n\t\t\t\t}\n\t\t\t}, 50);\n\t\t\tthis._commitCommandFinished.schedule();\n\t\t}\n\t\tthis._currentCommand = new PartialTerminalCommand(this._terminal);\n\t\tthis._handleCommandStartOptions = undefined;\n\t}\n\n\tsetCommandLine(commandLine: string, isTrusted: boolean) {\n\t\tthis._logService.debug('CommandDetectionCapability#setCommandLine', commandLine, isTrusted);\n\t\tthis._currentCommand.command = commandLine;\n\t\tthis._currentCommand.isTrusted = isTrusted;\n\t}\n\n\tserialize(): ISerializedCommandDetectionCapability {\n\t\tconst commands: ISerializedTerminalCommand[] = this.commands.map(e => e.serialize(this.__isCommandStorageDisabled));\n\t\tconst partialCommand = this._currentCommand.serialize(this._cwd);\n\t\tif (partialCommand) {\n\t\t\tcommands.push(partialCommand);\n\t\t}\n\t\treturn {\n\t\t\tisWindowsPty: this._ptyHeuristics.value instanceof WindowsPtyHeuristics,\n\t\t\tcommands\n\t\t};\n\t}\n\n\tdeserialize(serialized: ISerializedCommandDetectionCapability): void {\n\t\tif (serialized.isWindowsPty) {\n\t\t\tthis.setIsWindowsPty(serialized.isWindowsPty);\n\t\t}\n\t\tconst buffer = this._terminal.buffer.normal;\n\t\tfor (const e of serialized.commands) {\n\t\t\t// Partial command\n\t\t\tif (!e.endLine) {\n\t\t\t\t// Check for invalid command\n\t\t\t\tconst marker = e.startLine !== undefined ? this._terminal.registerMarker(e.startLine - (buffer.baseY + buffer.cursorY)) : undefined;\n\t\t\t\tif (!marker) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tthis._currentCommand.commandStartMarker = e.startLine !== undefined ? this._terminal.registerMarker(e.startLine - (buffer.baseY + buffer.cursorY)) : undefined;\n\t\t\t\tthis._currentCommand.commandStartX = e.startX;\n\t\t\t\tthis._currentCommand.promptStartMarker = e.promptStartLine !== undefined ? this._terminal.registerMarker(e.promptStartLine - (buffer.baseY + buffer.cursorY)) : undefined;\n\t\t\t\tthis._cwd = e.cwd;\n\t\t\t\tthis._onCommandStarted.fire({ marker } as ITerminalCommand);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Full command\n\t\t\tconst newCommand = TerminalCommand.deserialize(this._terminal, e, this.__isCommandStorageDisabled);\n\t\t\tif (!newCommand) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tthis._commands.push(newCommand);\n\t\t\tthis._logService.debug('CommandDetectionCapability#onCommandFinished', newCommand);\n\t\t\tthis._onCommandFinished.fire(newCommand);\n\t\t}\n\t}\n}\n\n/**\n * Additional hooks to private methods on {@link CommandDetectionCapability} that are needed by the\n * heuristics objects.\n */\ninterface ICommandDetectionHeuristicsHooks {\n\treadonly onCurrentCommandInvalidatedEmitter: Emitter;\n\treadonly onCommandStartedEmitter: Emitter;\n\treadonly onCommandExecutedEmitter: Emitter;\n\treadonly dimensions: ITerminalDimensions;\n\treadonly isCommandStorageDisabled: boolean;\n\n\tcommandMarkers: IMarker[];\n\n\tclearCommandsInViewport(): void;\n\tcommitCommandFinished(): void;\n}\n\ntype IPtyHeuristics = (\n\t// All optional methods\n\tPartial & Partial &\n\t// All common methods\n\t(UnixPtyHeuristics | WindowsPtyHeuristics) &\n\tIDisposable\n);\n\n/**\n * Non-Windows-specific behavior.\n */\nclass UnixPtyHeuristics extends Disposable {\n\tconstructor(\n\t\tprivate readonly _terminal: Terminal,\n\t\tprivate readonly _capability: CommandDetectionCapability,\n\t\tprivate readonly _hooks: ICommandDetectionHeuristicsHooks,\n\t\tprivate readonly _logService: ILogService\n\t) {\n\t\tsuper();\n\t\tthis._register(_terminal.parser.registerCsiHandler({ final: 'J' }, params => {\n\t\t\tif (params.length >= 1 && (params[0] === 2 || params[0] === 3)) {\n\t\t\t\t_hooks.clearCommandsInViewport();\n\t\t\t}\n\t\t\t// We don't want to override xterm.js' default behavior, just augment it\n\t\t\treturn false;\n\t\t}));\n\t}\n\n\tasync handleCommandStart(options?: IHandleCommandOptions) {\n\t\tthis._hooks.commitCommandFinished();\n\n\t\tconst currentCommand = this._capability.currentCommand;\n\t\tcurrentCommand.commandStartX = this._terminal.buffer.active.cursorX;\n\t\tcurrentCommand.commandStartMarker = options?.marker || this._terminal.registerMarker(0);\n\n\t\t// Clear executed as it must happen after command start\n\t\tcurrentCommand.commandExecutedMarker?.dispose();\n\t\tcurrentCommand.commandExecutedMarker = undefined;\n\t\tcurrentCommand.commandExecutedX = undefined;\n\t\tfor (const m of this._hooks.commandMarkers) {\n\t\t\tm.dispose();\n\t\t}\n\t\tthis._hooks.commandMarkers.length = 0;\n\n\t\tthis._hooks.onCommandStartedEmitter.fire({ marker: options?.marker || currentCommand.commandStartMarker, markProperties: options?.markProperties } as ITerminalCommand);\n\t\tthis._logService.debug('CommandDetectionCapability#handleCommandStart', currentCommand.commandStartX, currentCommand.commandStartMarker?.line);\n\t}\n\n\thandleCommandExecuted(options?: IHandleCommandOptions) {\n\t\tconst currentCommand = this._capability.currentCommand;\n\t\tcurrentCommand.commandExecutedMarker = options?.marker || this._terminal.registerMarker(0);\n\t\tcurrentCommand.commandExecutedX = this._terminal.buffer.active.cursorX;\n\t\tthis._logService.debug('CommandDetectionCapability#handleCommandExecuted', currentCommand.commandExecutedX, currentCommand.commandExecutedMarker?.line);\n\n\t\t// Sanity check optional props\n\t\tif (!currentCommand.commandStartMarker || !currentCommand.commandExecutedMarker || currentCommand.commandStartX === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Calculate the command\n\t\tcurrentCommand.command = this._hooks.isCommandStorageDisabled ? '' : this._terminal.buffer.active.getLine(currentCommand.commandStartMarker.line)?.translateToString(true, currentCommand.commandStartX, currentCommand.commandRightPromptStartX).trim();\n\t\tlet y = currentCommand.commandStartMarker.line + 1;\n\t\tconst commandExecutedLine = currentCommand.commandExecutedMarker.line;\n\t\tfor (; y < commandExecutedLine; y++) {\n\t\t\tconst line = this._terminal.buffer.active.getLine(y);\n\t\t\tif (line) {\n\t\t\t\tconst continuation = currentCommand.continuations?.find(e => e.marker.line === y);\n\t\t\t\tif (continuation) {\n\t\t\t\t\tcurrentCommand.command += '\\n';\n\t\t\t\t}\n\t\t\t\tconst startColumn = continuation?.end ?? 0;\n\t\t\t\tcurrentCommand.command += line.translateToString(true, startColumn);\n\t\t\t}\n\t\t}\n\t\tif (y === commandExecutedLine) {\n\t\t\tcurrentCommand.command += this._terminal.buffer.active.getLine(commandExecutedLine)?.translateToString(true, undefined, currentCommand.commandExecutedX) || '';\n\t\t}\n\t\tthis._hooks.onCommandExecutedEmitter.fire();\n\t}\n}\n\nconst enum AdjustCommandStartMarkerConstants {\n\tMaxCheckLineCount = 5,\n\tInterval = 20,\n\tMaximumPollCount = 50,\n}\n\n/**\n * An object that integrated with and decorates the command detection capability to add heuristics\n * that adjust various markers to work better with Windows and ConPTY. This isn't depended upon the\n * frontend OS, or even the backend OS, but the `IsWindows` property which technically a non-Windows\n * client can emit (for example in tests).\n */\nclass WindowsPtyHeuristics extends Disposable {\n\n\tprivate _onCursorMoveListener = this._register(new MutableDisposable());\n\n\tprivate _recentlyPerformedCsiJ = false;\n\n\tprivate _tryAdjustCommandStartMarkerScheduler?: RunOnceScheduler;\n\tprivate _tryAdjustCommandStartMarkerScannedLineCount: number = 0;\n\tprivate _tryAdjustCommandStartMarkerPollCount: number = 0;\n\n\tconstructor(\n\t\tprivate readonly _terminal: Terminal,\n\t\tprivate readonly _capability: CommandDetectionCapability,\n\t\tprivate readonly _hooks: ICommandDetectionHeuristicsHooks,\n\t\t@ILogService private readonly _logService: ILogService,\n\t) {\n\t\tsuper();\n\n\t\tthis._register(_terminal.parser.registerCsiHandler({ final: 'J' }, params => {\n\t\t\tif (params.length >= 1 && (params[0] === 2 || params[0] === 3)) {\n\t\t\t\tthis._recentlyPerformedCsiJ = true;\n\t\t\t\tthis._hooks.clearCommandsInViewport();\n\t\t\t}\n\t\t\t// We don't want to override xterm.js' default behavior, just augment it\n\t\t\treturn false;\n\t\t}));\n\n\t\tthis._register(this._capability.onBeforeCommandFinished(command => {\n\t\t\tif (this._recentlyPerformedCsiJ) {\n\t\t\t\tthis._recentlyPerformedCsiJ = false;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// For older Windows backends we cannot listen to CSI J, instead we assume running clear\n\t\t\t// or cls will clear all commands in the viewport. This is not perfect but it's right\n\t\t\t// most of the time.\n\t\t\tif (command.command.trim().toLowerCase() === 'clear' || command.command.trim().toLowerCase() === 'cls') {\n\t\t\t\tthis._tryAdjustCommandStartMarkerScheduler?.cancel();\n\t\t\t\tthis._tryAdjustCommandStartMarkerScheduler = undefined;\n\t\t\t\tthis._hooks.clearCommandsInViewport();\n\t\t\t\tthis._capability.currentCommand.isInvalid = true;\n\t\t\t\tthis._hooks.onCurrentCommandInvalidatedEmitter.fire({ reason: CommandInvalidationReason.Windows });\n\t\t\t}\n\t\t}));\n\t}\n\n\tpreHandleResize(e: { cols: number; rows: number }) {\n\t\t// Resize behavior is different under conpty; instead of bringing parts of the scrollback\n\t\t// back into the viewport, new lines are inserted at the bottom (ie. the same behavior as if\n\t\t// there was no scrollback).\n\t\t//\n\t\t// On resize this workaround will wait for a conpty reprint to occur by waiting for the\n\t\t// cursor to move, it will then calculate the number of lines that the commands within the\n\t\t// viewport _may have_ shifted. After verifying the content of the current line is\n\t\t// incorrect, the line after shifting is checked and if that matches delete events are fired\n\t\t// on the xterm.js buffer to move the markers.\n\t\t//\n\t\t// While a bit hacky, this approach is quite safe and seems to work great at least for pwsh.\n\t\tconst baseY = this._terminal.buffer.active.baseY;\n\t\tconst rowsDifference = e.rows - this._hooks.dimensions.rows;\n\t\t// Only do when rows increase, do in the next frame as this needs to happen after\n\t\t// conpty reprints the screen\n\t\tif (rowsDifference > 0) {\n\t\t\tthis._waitForCursorMove().then(() => {\n\t\t\t\t// Calculate the number of lines the content may have shifted, this will max out at\n\t\t\t\t// scrollback count since the standard behavior will be used then\n\t\t\t\tconst potentialShiftedLineCount = Math.min(rowsDifference, baseY);\n\t\t\t\t// For each command within the viewport, assume commands are in the correct order\n\t\t\t\tfor (let i = this._capability.commands.length - 1; i >= 0; i--) {\n\t\t\t\t\tconst command = this._capability.commands[i];\n\t\t\t\t\tif (!command.marker || command.marker.line < baseY || command.commandStartLineContent === undefined) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tconst line = this._terminal.buffer.active.getLine(command.marker.line);\n\t\t\t\t\tif (!line || line.translateToString(true) === command.commandStartLineContent) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tconst shiftedY = command.marker.line - potentialShiftedLineCount;\n\t\t\t\t\tconst shiftedLine = this._terminal.buffer.active.getLine(shiftedY);\n\t\t\t\t\tif (shiftedLine?.translateToString(true) !== command.commandStartLineContent) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t// HACK: xterm.js doesn't expose this by design as it's an internal core\n\t\t\t\t\t// function an embedder could easily do damage with. Additionally, this\n\t\t\t\t\t// can't really be upstreamed since the event relies on shell integration to\n\t\t\t\t\t// verify the shifting is necessary.\n\t\t\t\t\t(this._terminal as any)._core._bufferService.buffer.lines.onDeleteEmitter.fire({\n\t\t\t\t\t\tindex: this._terminal.buffer.active.baseY,\n\t\t\t\t\t\tamount: potentialShiftedLineCount\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\tasync handleCommandStart() {\n\t\tthis._capability.currentCommand.commandStartX = this._terminal.buffer.active.cursorX;\n\n\t\t// On Windows track all cursor movements after the command start sequence\n\t\tthis._hooks.commandMarkers.length = 0;\n\n\t\tconst initialCommandStartMarker = this._capability.currentCommand.commandStartMarker = (\n\t\t\tthis._capability.currentCommand.promptStartMarker\n\t\t\t\t? cloneMarker(this._terminal, this._capability.currentCommand.promptStartMarker)\n\t\t\t\t: this._terminal.registerMarker(0)\n\t\t)!;\n\t\tthis._capability.currentCommand.commandStartX = 0;\n\n\t\t// DEBUG: Add a decoration for the original unadjusted command start position\n\t\t// if ('registerDecoration' in this._terminal) {\n\t\t// \tconst d = (this._terminal as any).registerDecoration({\n\t\t// \t\tmarker: this._capability.currentCommand.commandStartMarker,\n\t\t// \t\tx: this._capability.currentCommand.commandStartX\n\t\t// \t});\n\t\t// \td?.onRender((e: HTMLElement) => {\n\t\t// \t\te.textContent = 'b';\n\t\t// \t\te.classList.add('xterm-sequence-decoration', 'top', 'right');\n\t\t// \t\te.title = 'Initial command start position';\n\t\t// \t});\n\t\t// }\n\n\t\t// The command started sequence may be printed before the actual prompt is, for example a\n\t\t// multi-line prompt will typically look like this where D, A and B signify the command\n\t\t// finished, prompt started and command started sequences respectively:\n\t\t//\n\t\t// D/my/cwdB\n\t\t// > C\n\t\t//\n\t\t// Due to this, it's likely that this will be called before the line has been parsed.\n\t\t// Unfortunately, it is also the case that the actual command start data may not be parsed\n\t\t// by the end of the task either, so a microtask cannot be used.\n\t\t//\n\t\t// The strategy used is to begin polling and scanning downwards for up to the next 5 lines.\n\t\t// If it looks like a prompt is found, the command started location is adjusted. If the\n\t\t// command executed sequences comes in before polling is done, polling is canceled and the\n\t\t// final polling task is executed synchronously.\n\t\tthis._tryAdjustCommandStartMarkerScannedLineCount = 0;\n\t\tthis._tryAdjustCommandStartMarkerPollCount = 0;\n\t\tthis._tryAdjustCommandStartMarkerScheduler = new RunOnceScheduler(() => this._tryAdjustCommandStartMarker(initialCommandStartMarker), AdjustCommandStartMarkerConstants.Interval);\n\t\tthis._tryAdjustCommandStartMarkerScheduler.schedule();\n\n\t\t// TODO: Cache details about polling for the future - eg. if it always fails, stop bothering\n\t}\n\n\tprivate _tryAdjustCommandStartMarker(start: IMarker) {\n\t\tif (this._store.isDisposed) {\n\t\t\treturn;\n\t\t}\n\t\tconst buffer = this._terminal.buffer.active;\n\t\tlet scannedLineCount = this._tryAdjustCommandStartMarkerScannedLineCount;\n\t\twhile (scannedLineCount < AdjustCommandStartMarkerConstants.MaxCheckLineCount && start.line + scannedLineCount < buffer.baseY + this._terminal.rows) {\n\t\t\tif (this._cursorOnNextLine()) {\n\t\t\t\tconst prompt = this._getWindowsPrompt(start.line + scannedLineCount);\n\t\t\t\tif (prompt) {\n\t\t\t\t\tconst adjustedPrompt = typeof prompt === 'string' ? prompt : prompt.prompt;\n\t\t\t\t\tthis._capability.currentCommand.commandStartMarker = this._terminal.registerMarker(0)!;\n\t\t\t\t\tif (typeof prompt === 'object' && prompt.likelySingleLine) {\n\t\t\t\t\t\tthis._logService.debug('CommandDetectionCapability#_tryAdjustCommandStartMarker adjusted promptStart', `${this._capability.currentCommand.promptStartMarker?.line} -> ${this._capability.currentCommand.commandStartMarker.line}`);\n\t\t\t\t\t\tthis._capability.currentCommand.promptStartMarker?.dispose();\n\t\t\t\t\t\tthis._capability.currentCommand.promptStartMarker = cloneMarker(this._terminal, this._capability.currentCommand.commandStartMarker);\n\t\t\t\t\t\t// Adjust the last command if it's not in the same position as the following\n\t\t\t\t\t\t// prompt start marker\n\t\t\t\t\t\tconst lastCommand = this._capability.commands.at(-1);\n\t\t\t\t\t\tif (lastCommand && this._capability.currentCommand.commandStartMarker.line !== lastCommand.endMarker?.line) {\n\t\t\t\t\t\t\tlastCommand.endMarker?.dispose();\n\t\t\t\t\t\t\tlastCommand.endMarker = cloneMarker(this._terminal, this._capability.currentCommand.commandStartMarker);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// use the regex to set the position as it's possible input has occurred\n\t\t\t\t\tthis._capability.currentCommand.commandStartX = adjustedPrompt.length;\n\t\t\t\t\tthis._logService.debug('CommandDetectionCapability#_tryAdjustCommandStartMarker adjusted commandStart', `${start.line} -> ${this._capability.currentCommand.commandStartMarker.line}:${this._capability.currentCommand.commandStartX}`);\n\t\t\t\t\tthis._flushPendingHandleCommandStartTask();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tscannedLineCount++;\n\t\t}\n\t\tif (scannedLineCount < AdjustCommandStartMarkerConstants.MaxCheckLineCount) {\n\t\t\tthis._tryAdjustCommandStartMarkerScannedLineCount = scannedLineCount;\n\t\t\tif (this._tryAdjustCommandStartMarkerPollCount < AdjustCommandStartMarkerConstants.MaximumPollCount) {\n\t\t\t\tthis._tryAdjustCommandStartMarkerScheduler?.schedule();\n\t\t\t} else {\n\t\t\t\tthis._flushPendingHandleCommandStartTask();\n\t\t\t}\n\t\t} else {\n\t\t\tthis._flushPendingHandleCommandStartTask();\n\t\t}\n\t}\n\n\tprivate _flushPendingHandleCommandStartTask() {\n\t\t// Perform final try adjust if necessary\n\t\tif (this._tryAdjustCommandStartMarkerScheduler) {\n\t\t\t// Max out poll count to ensure it's the last run\n\t\t\tthis._tryAdjustCommandStartMarkerPollCount = AdjustCommandStartMarkerConstants.MaximumPollCount;\n\t\t\tthis._tryAdjustCommandStartMarkerScheduler.flush();\n\t\t\tthis._tryAdjustCommandStartMarkerScheduler = undefined;\n\t\t}\n\n\t\tthis._hooks.commitCommandFinished();\n\n\t\tif (!this._capability.currentCommand.commandExecutedMarker) {\n\t\t\tthis._onCursorMoveListener.value = this._terminal.onCursorMove(() => {\n\t\t\t\tif (this._hooks.commandMarkers.length === 0 || this._hooks.commandMarkers[this._hooks.commandMarkers.length - 1].line !== this._terminal.buffer.active.cursorY) {\n\t\t\t\t\tconst marker = this._terminal.registerMarker(0);\n\t\t\t\t\tif (marker) {\n\t\t\t\t\t\tthis._hooks.commandMarkers.push(marker);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tif (this._capability.currentCommand.commandStartMarker) {\n\t\t\tconst line = this._terminal.buffer.active.getLine(this._capability.currentCommand.commandStartMarker.line);\n\t\t\tif (line) {\n\t\t\t\tthis._capability.currentCommand.commandStartLineContent = line.translateToString(true);\n\t\t\t}\n\t\t}\n\t\tthis._hooks.onCommandStartedEmitter.fire({ marker: this._capability.currentCommand.commandStartMarker } as ITerminalCommand);\n\t\tthis._logService.debug('CommandDetectionCapability#_handleCommandStartWindows', this._capability.currentCommand.commandStartX, this._capability.currentCommand.commandStartMarker?.line);\n\t}\n\n\thandleCommandExecuted(options: IHandleCommandOptions | undefined) {\n\t\tif (this._tryAdjustCommandStartMarkerScheduler) {\n\t\t\tthis._flushPendingHandleCommandStartTask();\n\t\t}\n\t\t// Use the gathered cursor move markers to correct the command start and executed markers\n\t\tthis._onCursorMoveListener.clear();\n\t\tthis._evaluateCommandMarkers();\n\t\tthis._capability.currentCommand.commandExecutedX = this._terminal.buffer.active.cursorX;\n\t\tthis._hooks.onCommandExecutedEmitter.fire();\n\t\tthis._logService.debug('CommandDetectionCapability#handleCommandExecuted', this._capability.currentCommand.commandExecutedX, this._capability.currentCommand.commandExecutedMarker?.line);\n\t}\n\n\tpreHandleCommandFinished() {\n\t\tif (this._capability.currentCommand.commandExecutedMarker) {\n\t\t\treturn;\n\t\t}\n\t\t// This is done on command finished just in case command executed never happens (for example\n\t\t// PSReadLine tab completion)\n\t\tif (this._hooks.commandMarkers.length === 0) {\n\t\t\t// If the command start timeout doesn't happen before command finished, just use the\n\t\t\t// current marker.\n\t\t\tif (!this._capability.currentCommand.commandStartMarker) {\n\t\t\t\tthis._capability.currentCommand.commandStartMarker = this._terminal.registerMarker(0);\n\t\t\t}\n\t\t\tif (this._capability.currentCommand.commandStartMarker) {\n\t\t\t\tthis._hooks.commandMarkers.push(this._capability.currentCommand.commandStartMarker);\n\t\t\t}\n\t\t}\n\t\tthis._evaluateCommandMarkers();\n\t}\n\n\tpostHandleCommandFinished(): void {\n\t\tconst currentCommand = this._capability.currentCommand;\n\t\tconst commandText = currentCommand.command;\n\t\tconst commandLine = currentCommand.commandStartMarker?.line;\n\t\tconst executedLine = currentCommand.commandExecutedMarker?.line;\n\t\tif (\n\t\t\t!commandText || commandText.length === 0 ||\n\t\t\tcommandLine === undefined || commandLine === -1 ||\n\t\t\texecutedLine === undefined || executedLine === -1\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Scan downwards from the command start line and search for every character in the actual\n\t\t// command line. This may end up matching the wrong characters, but it shouldn't matter at\n\t\t// least in the typical case as the entire command will still get matched.\n\t\tlet current = 0;\n\t\tlet found = false;\n\t\tfor (let i = commandLine; i <= executedLine; i++) {\n\t\t\tconst line = this._terminal.buffer.active.getLine(i);\n\t\t\tif (!line) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tconst text = line.translateToString(true);\n\t\t\tfor (let j = 0; j < text.length; j++) {\n\t\t\t\t// Skip whitespace in case it was not actually rendered or could be trimmed from the\n\t\t\t\t// end of the line\n\t\t\t\twhile (commandText.length < current && commandText[current] === ' ') {\n\t\t\t\t\tcurrent++;\n\t\t\t\t}\n\n\t\t\t\t// Character match\n\t\t\t\tif (text[j] === commandText[current]) {\n\t\t\t\t\tcurrent++;\n\t\t\t\t}\n\n\t\t\t\t// Full command match\n\t\t\t\tif (current === commandText.length) {\n\t\t\t\t\t// It's ambiguous whether the command executed marker should ideally appear at\n\t\t\t\t\t// the end of the line or at the beginning of the next line. Since it's more\n\t\t\t\t\t// useful for extracting the command at the end of the current line we go with\n\t\t\t\t\t// that.\n\t\t\t\t\tconst wrapsToNextLine = j >= this._terminal.cols - 1;\n\t\t\t\t\tcurrentCommand.commandExecutedMarker = this._terminal.registerMarker(i - (this._terminal.buffer.active.baseY + this._terminal.buffer.active.cursorY) + (wrapsToNextLine ? 1 : 0));\n\t\t\t\t\tcurrentCommand.commandExecutedX = wrapsToNextLine ? 0 : j + 1;\n\t\t\t\t\tfound = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (found) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _evaluateCommandMarkers(): void {\n\t\t// On Windows, use the gathered cursor move markers to correct the command start and\n\t\t// executed markers.\n\t\tif (this._hooks.commandMarkers.length === 0) {\n\t\t\treturn;\n\t\t}\n\t\tthis._hooks.commandMarkers = this._hooks.commandMarkers.sort((a, b) => a.line - b.line);\n\t\tthis._capability.currentCommand.commandStartMarker = this._hooks.commandMarkers[0];\n\t\tif (this._capability.currentCommand.commandStartMarker) {\n\t\t\tconst line = this._terminal.buffer.active.getLine(this._capability.currentCommand.commandStartMarker.line);\n\t\t\tif (line) {\n\t\t\t\tthis._capability.currentCommand.commandStartLineContent = line.translateToString(true);\n\t\t\t}\n\t\t}\n\t\tthis._capability.currentCommand.commandExecutedMarker = this._hooks.commandMarkers[this._hooks.commandMarkers.length - 1];\n\t\t// Fire this now to prevent issues like #197409\n\t\tthis._hooks.onCommandExecutedEmitter.fire();\n\t}\n\n\tprivate _cursorOnNextLine(): boolean {\n\t\tconst lastCommand = this._capability.commands.at(-1);\n\n\t\t// There is only a single command, so this check is unnecessary\n\t\tif (!lastCommand) {\n\t\t\treturn true;\n\t\t}\n\n\t\tconst cursorYAbsolute = this._terminal.buffer.active.baseY + this._terminal.buffer.active.cursorY;\n\t\t// If the cursor position is within the last command, we should poll.\n\t\tconst lastCommandYAbsolute = (lastCommand.endMarker ? lastCommand.endMarker.line : lastCommand.marker?.line) ?? -1;\n\t\treturn cursorYAbsolute > lastCommandYAbsolute;\n\t}\n\n\tprivate _waitForCursorMove(): Promise {\n\t\tconst cursorX = this._terminal.buffer.active.cursorX;\n\t\tconst cursorY = this._terminal.buffer.active.cursorY;\n\t\tlet totalDelay = 0;\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst interval = setInterval(() => {\n\t\t\t\tif (cursorX !== this._terminal.buffer.active.cursorX || cursorY !== this._terminal.buffer.active.cursorY) {\n\t\t\t\t\tresolve();\n\t\t\t\t\tclearInterval(interval);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\ttotalDelay += 10;\n\t\t\t\tif (totalDelay > 1000) {\n\t\t\t\t\tclearInterval(interval);\n\t\t\t\t\tresolve();\n\t\t\t\t}\n\t\t\t}, 10);\n\t\t});\n\t}\n\n\tprivate _getWindowsPrompt(y: number = this._terminal.buffer.active.baseY + this._terminal.buffer.active.cursorY): string | { prompt: string; likelySingleLine: true } | undefined {\n\t\tconst line = this._terminal.buffer.active.getLine(y);\n\t\tif (!line) {\n\t\t\treturn;\n\t\t}\n\t\t// TODO: fine tune prompt regex to accomodate for unique configurations.\n\t\tconst lineText = line.translateToString(true);\n\t\tif (!lineText) {\n\t\t\treturn;\n\t\t}\n\n\t\t// PowerShell\n\t\tconst pwshPrompt = lineText.match(/(?(\\(.+\\)\\s)?(?:PS.+>\\s?))/)?.groups?.prompt;\n\t\tif (pwshPrompt) {\n\t\t\tconst adjustedPrompt = this._adjustPrompt(pwshPrompt, lineText, '>');\n\t\t\tif (adjustedPrompt) {\n\t\t\t\treturn {\n\t\t\t\t\tprompt: adjustedPrompt,\n\t\t\t\t\tlikelySingleLine: true\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\t// Custom prompts like starship end in the common \\u276f character\n\t\tconst customPrompt = lineText.match(/.*\\u276f(?=[^\\u276f]*$)/g)?.[0];\n\t\tif (customPrompt) {\n\t\t\tconst adjustedPrompt = this._adjustPrompt(customPrompt, lineText, '\\u276f');\n\t\t\tif (adjustedPrompt) {\n\t\t\t\treturn adjustedPrompt;\n\t\t\t}\n\t\t}\n\n\t\t// Python Prompt\n\t\tconst pythonPrompt = lineText.match(/^(?>>> )/g)?.groups?.prompt;\n\t\tif (pythonPrompt) {\n\t\t\treturn {\n\t\t\t\tprompt: pythonPrompt,\n\t\t\t\tlikelySingleLine: true\n\t\t\t};\n\t\t}\n\n\t\t// Command Prompt\n\t\tconst cmdMatch = lineText.match(/^(?(\\(.+\\)\\s)?(?:[A-Z]:\\\\.*>))/);\n\t\treturn cmdMatch?.groups?.prompt ? {\n\t\t\tprompt: cmdMatch.groups.prompt,\n\t\t\tlikelySingleLine: true\n\t\t} : undefined;\n\t}\n\n\tprivate _adjustPrompt(prompt: string | undefined, lineText: string, char: string): string | undefined {\n\t\tif (!prompt) {\n\t\t\treturn;\n\t\t}\n\t\t// Conpty may not 'render' the space at the end of the prompt\n\t\tif (lineText === prompt && prompt.endsWith(char)) {\n\t\t\tprompt += ' ';\n\t\t}\n\t\treturn prompt;\n\t}\n}\n\nexport function getLinesForCommand(buffer: IBuffer, command: ITerminalCommand, cols: number, outputMatcher?: ITerminalOutputMatcher): string[] | undefined {\n\tif (!outputMatcher) {\n\t\treturn undefined;\n\t}\n\tconst executedMarker = command.executedMarker;\n\tconst endMarker = command.endMarker;\n\tif (!executedMarker || !endMarker) {\n\t\treturn undefined;\n\t}\n\tconst startLine = executedMarker.line;\n\tconst endLine = endMarker.line;\n\n\tconst linesToCheck = outputMatcher.length;\n\tconst lines: string[] = [];\n\tif (outputMatcher.anchor === 'bottom') {\n\t\tfor (let i = endLine - (outputMatcher.offset || 0); i >= startLine; i--) {\n\t\t\tlet wrappedLineStart = i;\n\t\t\tconst wrappedLineEnd = i;\n\t\t\twhile (wrappedLineStart >= startLine && buffer.getLine(wrappedLineStart)?.isWrapped) {\n\t\t\t\twrappedLineStart--;\n\t\t\t}\n\t\t\ti = wrappedLineStart;\n\t\t\tlines.unshift(getXtermLineContent(buffer, wrappedLineStart, wrappedLineEnd, cols));\n\t\t\tif (lines.length > linesToCheck) {\n\t\t\t\tlines.pop();\n\t\t\t}\n\t\t}\n\t} else {\n\t\tfor (let i = startLine + (outputMatcher.offset || 0); i < endLine; i++) {\n\t\t\tconst wrappedLineStart = i;\n\t\t\tlet wrappedLineEnd = i;\n\t\t\twhile (wrappedLineEnd + 1 < endLine && buffer.getLine(wrappedLineEnd + 1)?.isWrapped) {\n\t\t\t\twrappedLineEnd++;\n\t\t\t}\n\t\t\ti = wrappedLineEnd;\n\t\t\tlines.push(getXtermLineContent(buffer, wrappedLineStart, wrappedLineEnd, cols));\n\t\t\tif (lines.length === linesToCheck) {\n\t\t\t\tlines.shift();\n\t\t\t}\n\t\t}\n\t}\n\treturn lines;\n}\n\nfunction getXtermLineContent(buffer: IBuffer, lineStart: number, lineEnd: number, cols: number): string {\n\t// Cap the maximum number of lines generated to prevent potential performance problems. This is\n\t// more of a sanity check as the wrapped line should already be trimmed down at this point.\n\tconst maxLineLength = Math.max(2048 / cols * 2);\n\tlineEnd = Math.min(lineEnd, lineStart + maxLineLength);\n\tlet content = '';\n\tfor (let i = lineStart; i <= lineEnd; i++) {\n\t\t// Make sure only 0 to cols are considered as resizing when windows mode is enabled will\n\t\t// retain buffer data outside of the terminal width as reflow is disabled.\n\t\tconst line = buffer.getLine(i);\n\t\tif (line) {\n\t\t\tcontent += line.translateToString(true, 0, cols);\n\t\t}\n\t}\n\treturn content;\n}\n\nfunction cloneMarker(xterm: Terminal, marker: IXtermMarker, offset: number = 0): IXtermMarker | undefined {\n\treturn xterm.registerMarker(marker.line - (xterm.buffer.active.baseY + xterm.buffer.active.cursorY) + offset);\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { ICwdDetectionCapability, TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities';\n\nexport class CwdDetectionCapability extends Disposable implements ICwdDetectionCapability {\n\treadonly type = TerminalCapability.CwdDetection;\n\tprivate _cwd = '';\n\tprivate _cwds = new Map();\n\n\t/**\n\t * Gets the list of cwds seen in this session in order of last accessed.\n\t */\n\tget cwds(): string[] {\n\t\treturn Array.from(this._cwds.keys());\n\t}\n\n\tprivate readonly _onDidChangeCwd = this._register(new Emitter());\n\treadonly onDidChangeCwd = this._onDidChangeCwd.event;\n\n\tgetCwd(): string {\n\t\treturn this._cwd;\n\t}\n\n\tupdateCwd(cwd: string): void {\n\t\tconst didChange = this._cwd !== cwd;\n\t\tthis._cwd = cwd;\n\t\tconst count = this._cwds.get(this._cwd) || 0;\n\t\tthis._cwds.delete(this._cwd); // Delete to put it at the bottom of the iterable\n\t\tthis._cwds.set(this._cwd, count + 1);\n\t\tif (didChange) {\n\t\t\tthis._onDidChangeCwd.fire(cwd);\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 { Emitter } from 'vs/base/common/event';\nimport { ITerminalChildProcess } from 'vs/platform/terminal/common/terminal';\nimport { TerminalCapability, INaiveCwdDetectionCapability } from 'vs/platform/terminal/common/capabilities/capabilities';\n\nexport class NaiveCwdDetectionCapability implements INaiveCwdDetectionCapability {\n\tconstructor(private readonly _process: ITerminalChildProcess) { }\n\treadonly type = TerminalCapability.NaiveCwdDetection;\n\tprivate _cwd = '';\n\n\tprivate readonly _onDidChangeCwd = new Emitter();\n\treadonly onDidChangeCwd = this._onDidChangeCwd.event;\n\n\tasync getCwd(): Promise {\n\t\tif (!this._process) {\n\t\t\treturn Promise.resolve('');\n\t\t}\n\t\tconst newCwd = await this._process.getCwd();\n\t\tif (newCwd !== this._cwd) {\n\t\t\tthis._onDidChangeCwd.fire(newCwd);\n\t\t}\n\t\tthis._cwd = newCwd;\n\t\treturn this._cwd;\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { DisposableStore } from 'vs/base/common/lifecycle';\nimport { IPartialCommandDetectionCapability, TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities';\n// Importing types is safe in any layer\n// eslint-disable-next-line local/code-import-patterns\nimport type { IMarker, Terminal } from '@xterm/headless';\n\nconst enum Constants {\n\t/**\n\t * The minimum size of the prompt in which to assume the line is a command.\n\t */\n\tMinimumPromptLength = 2\n}\n\n/**\n * This capability guesses where commands are based on where the cursor was when enter was pressed.\n * It's very hit or miss but it's often correct and better than nothing.\n */\nexport class PartialCommandDetectionCapability extends DisposableStore implements IPartialCommandDetectionCapability {\n\treadonly type = TerminalCapability.PartialCommandDetection;\n\n\tprivate readonly _commands: IMarker[] = [];\n\n\tget commands(): readonly IMarker[] { return this._commands; }\n\n\tprivate readonly _onCommandFinished = this.add(new Emitter());\n\treadonly onCommandFinished = this._onCommandFinished.event;\n\n\tconstructor(\n\t\tprivate readonly _terminal: Terminal,\n\t) {\n\t\tsuper();\n\t\tthis.add(this._terminal.onData(e => this._onData(e)));\n\t\tthis.add(this._terminal.parser.registerCsiHandler({ final: 'J' }, params => {\n\t\t\tif (params.length >= 1 && (params[0] === 2 || params[0] === 3)) {\n\t\t\t\tthis._clearCommandsInViewport();\n\t\t\t}\n\t\t\t// We don't want to override xterm.js' default behavior, just augment it\n\t\t\treturn false;\n\t\t}));\n\t}\n\n\tprivate _onData(data: string): void {\n\t\tif (data === '\\x0d') {\n\t\t\tthis._onEnter();\n\t\t}\n\t}\n\n\tprivate _onEnter(): void {\n\t\tif (!this._terminal) {\n\t\t\treturn;\n\t\t}\n\t\tif (this._terminal.buffer.active.cursorX >= Constants.MinimumPromptLength) {\n\t\t\tconst marker = this._terminal.registerMarker(0);\n\t\t\tif (marker) {\n\t\t\t\tthis._commands.push(marker);\n\t\t\t\tthis._onCommandFinished.fire(marker);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _clearCommandsInViewport(): void {\n\t\t// Find the number of commands on the tail end of the array that are within the viewport\n\t\tlet count = 0;\n\t\tfor (let i = this._commands.length - 1; i >= 0; i--) {\n\t\t\tif (this._commands[i].line < this._terminal.buffer.active.baseY) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcount++;\n\t\t}\n\t\t// Remove them\n\t\tthis._commands.splice(this._commands.length - count, 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 { Emitter } from 'vs/base/common/event';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { ITerminalCapabilityImplMap, ITerminalCapabilityStore, TerminalCapability, TerminalCapabilityChangeEvent } from 'vs/platform/terminal/common/capabilities/capabilities';\n\nexport class TerminalCapabilityStore extends Disposable implements ITerminalCapabilityStore {\n\tprivate _map: Map = new Map();\n\n\tprivate readonly _onDidRemoveCapabilityType = this._register(new Emitter());\n\treadonly onDidRemoveCapabilityType = this._onDidRemoveCapabilityType.event;\n\tprivate readonly _onDidAddCapabilityType = this._register(new Emitter());\n\treadonly onDidAddCapabilityType = this._onDidAddCapabilityType.event;\n\n\tprivate readonly _onDidRemoveCapability = this._register(new Emitter>());\n\treadonly onDidRemoveCapability = this._onDidRemoveCapability.event;\n\tprivate readonly _onDidAddCapability = this._register(new Emitter>());\n\treadonly onDidAddCapability = this._onDidAddCapability.event;\n\n\tget items(): IterableIterator {\n\t\treturn this._map.keys();\n\t}\n\n\tadd(capability: T, impl: ITerminalCapabilityImplMap[T]) {\n\t\tthis._map.set(capability, impl);\n\t\tthis._onDidAddCapabilityType.fire(capability);\n\t\tthis._onDidAddCapability.fire({ id: capability, capability: impl });\n\t}\n\n\tget(capability: T): ITerminalCapabilityImplMap[T] | undefined {\n\t\t// HACK: This isn't totally safe since the Map key and value are not connected\n\t\treturn this._map.get(capability) as ITerminalCapabilityImplMap[T] | undefined;\n\t}\n\n\tremove(capability: TerminalCapability) {\n\t\tconst impl = this._map.get(capability);\n\t\tif (!impl) {\n\t\t\treturn;\n\t\t}\n\t\tthis._map.delete(capability);\n\t\tthis._onDidRemoveCapabilityType.fire(capability);\n\t\tthis._onDidAddCapability.fire({ id: capability, capability: impl });\n\t}\n\n\thas(capability: TerminalCapability) {\n\t\treturn this._map.has(capability);\n\t}\n}\n\nexport class TerminalCapabilityStoreMultiplexer extends Disposable implements ITerminalCapabilityStore {\n\treadonly _stores: ITerminalCapabilityStore[] = [];\n\n\tprivate readonly _onDidRemoveCapabilityType = this._register(new Emitter());\n\treadonly onDidRemoveCapabilityType = this._onDidRemoveCapabilityType.event;\n\tprivate readonly _onDidAddCapabilityType = this._register(new Emitter());\n\treadonly onDidAddCapabilityType = this._onDidAddCapabilityType.event;\n\n\tprivate readonly _onDidRemoveCapability = this._register(new Emitter>());\n\treadonly onDidRemoveCapability = this._onDidRemoveCapability.event;\n\tprivate readonly _onDidAddCapability = this._register(new Emitter>());\n\treadonly onDidAddCapability = this._onDidAddCapability.event;\n\n\tget items(): IterableIterator {\n\t\treturn this._items();\n\t}\n\n\tprivate *_items(): IterableIterator {\n\t\tfor (const store of this._stores) {\n\t\t\tfor (const c of store.items) {\n\t\t\t\tyield c;\n\t\t\t}\n\t\t}\n\t}\n\n\thas(capability: TerminalCapability): boolean {\n\t\tfor (const store of this._stores) {\n\t\t\tfor (const c of store.items) {\n\t\t\t\tif (c === capability) {\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\tget(capability: T): ITerminalCapabilityImplMap[T] | undefined {\n\t\tfor (const store of this._stores) {\n\t\t\tconst c = store.get(capability);\n\t\t\tif (c) {\n\t\t\t\treturn c;\n\t\t\t}\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tadd(store: ITerminalCapabilityStore) {\n\t\tthis._stores.push(store);\n\t\tfor (const capability of store.items) {\n\t\t\tthis._onDidAddCapabilityType.fire(capability);\n\t\t\tthis._onDidAddCapability.fire({ id: capability, capability: store.get(capability)! });\n\t\t}\n\t\tthis._register(store.onDidAddCapabilityType(e => this._onDidAddCapabilityType.fire(e)));\n\t\tthis._register(store.onDidAddCapability(e => this._onDidAddCapability.fire(e)));\n\t\tthis._register(store.onDidRemoveCapabilityType(e => this._onDidRemoveCapabilityType.fire(e)));\n\t\tthis._register(store.onDidRemoveCapability(e => this._onDidRemoveCapability.fire(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 { IProcessEnvironment } from 'vs/base/common/platform';\nimport { IWorkspaceFolderData } from 'vs/platform/workspace/common/workspace';\n\nexport enum EnvironmentVariableMutatorType {\n\tReplace = 1,\n\tAppend = 2,\n\tPrepend = 3\n}\nexport interface IEnvironmentVariableMutator {\n\treadonly variable: string;\n\treadonly value: string;\n\treadonly type: EnvironmentVariableMutatorType;\n\treadonly scope?: EnvironmentVariableScope;\n\treadonly options?: IEnvironmentVariableMutatorOptions;\n}\n\nexport interface IEnvironmentVariableCollectionDescription {\n\treadonly description: string | undefined;\n\treadonly scope?: EnvironmentVariableScope;\n}\n\nexport interface IEnvironmentVariableMutatorOptions {\n\tapplyAtProcessCreation?: boolean;\n\tapplyAtShellIntegration?: boolean;\n}\n\nexport type EnvironmentVariableScope = {\n\tworkspaceFolder?: IWorkspaceFolderData;\n};\n\nexport interface IEnvironmentVariableCollection {\n\treadonly map: ReadonlyMap;\n\treadonly descriptionMap?: ReadonlyMap;\n}\n\n/** [variable, mutator] */\nexport type ISerializableEnvironmentVariableCollection = [string, IEnvironmentVariableMutator][];\n\nexport type ISerializableEnvironmentDescriptionMap = [string, IEnvironmentVariableCollectionDescription][];\nexport interface IExtensionOwnedEnvironmentDescriptionMutator extends IEnvironmentVariableCollectionDescription {\n\treadonly extensionIdentifier: string;\n}\n\n/** [extension, collection, description] */\nexport type ISerializableEnvironmentVariableCollections = [string, ISerializableEnvironmentVariableCollection, ISerializableEnvironmentDescriptionMap][];\n\nexport interface IExtensionOwnedEnvironmentVariableMutator extends IEnvironmentVariableMutator {\n\treadonly extensionIdentifier: string;\n}\n\nexport interface IMergedEnvironmentVariableCollectionDiff {\n\tadded: ReadonlyMap;\n\tchanged: ReadonlyMap;\n\tremoved: ReadonlyMap;\n}\n\ntype VariableResolver = (str: string) => Promise;\n\n/**\n * Represents an environment variable collection that results from merging several collections\n * together.\n */\nexport interface IMergedEnvironmentVariableCollection {\n\treadonly collections: ReadonlyMap;\n\t/**\n\t * Gets the variable map for a given scope.\n\t * @param scope The scope to get the variable map for. If undefined, the global scope is used.\n\t */\n\tgetVariableMap(scope: EnvironmentVariableScope | undefined): Map;\n\t/**\n\t * Gets the description map for a given scope.\n\t * @param scope The scope to get the description map for. If undefined, description map for the\n\t * global scope is returned.\n\t */\n\tgetDescriptionMap(scope: EnvironmentVariableScope | undefined): Map;\n\t/**\n\t * Applies this collection to a process environment.\n\t * @param variableResolver An optional function to use to resolve variables within the\n\t * environment values.\n\t */\n\tapplyToProcessEnvironment(env: IProcessEnvironment, scope: EnvironmentVariableScope | undefined, variableResolver?: VariableResolver): Promise;\n\n\t/**\n\t * Generates a diff of this collection against another. Returns undefined if the collections are\n\t * the same.\n\t */\n\tdiff(other: IMergedEnvironmentVariableCollection, scope: EnvironmentVariableScope | undefined): IMergedEnvironmentVariableCollectionDiff | 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 { IProcessEnvironment, isWindows } from 'vs/base/common/platform';\nimport { EnvironmentVariableMutatorType, EnvironmentVariableScope, IEnvironmentVariableCollection, IExtensionOwnedEnvironmentDescriptionMutator, IExtensionOwnedEnvironmentVariableMutator, IMergedEnvironmentVariableCollection, IMergedEnvironmentVariableCollectionDiff } from 'vs/platform/terminal/common/environmentVariable';\n\ntype VariableResolver = (str: string) => Promise;\n\nconst mutatorTypeToLabelMap: Map = new Map([\n\t[EnvironmentVariableMutatorType.Append, 'APPEND'],\n\t[EnvironmentVariableMutatorType.Prepend, 'PREPEND'],\n\t[EnvironmentVariableMutatorType.Replace, 'REPLACE']\n]);\n\nexport class MergedEnvironmentVariableCollection implements IMergedEnvironmentVariableCollection {\n\tprivate readonly map: Map = new Map();\n\tprivate readonly descriptionMap: Map = new Map();\n\n\tconstructor(\n\t\treadonly collections: ReadonlyMap,\n\t) {\n\t\tcollections.forEach((collection, extensionIdentifier) => {\n\t\t\tthis.populateDescriptionMap(collection, extensionIdentifier);\n\t\t\tconst it = collection.map.entries();\n\t\t\tlet next = it.next();\n\t\t\twhile (!next.done) {\n\t\t\t\tconst mutator = next.value[1];\n\t\t\t\tconst key = next.value[0];\n\t\t\t\tlet entry = this.map.get(key);\n\t\t\t\tif (!entry) {\n\t\t\t\t\tentry = [];\n\t\t\t\t\tthis.map.set(key, entry);\n\t\t\t\t}\n\n\t\t\t\t// If the first item in the entry is replace ignore any other entries as they would\n\t\t\t\t// just get replaced by this one.\n\t\t\t\tif (entry.length > 0 && entry[0].type === EnvironmentVariableMutatorType.Replace) {\n\t\t\t\t\tnext = it.next();\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst extensionMutator = {\n\t\t\t\t\textensionIdentifier,\n\t\t\t\t\tvalue: mutator.value,\n\t\t\t\t\ttype: mutator.type,\n\t\t\t\t\tscope: mutator.scope,\n\t\t\t\t\tvariable: mutator.variable,\n\t\t\t\t\toptions: mutator.options\n\t\t\t\t};\n\t\t\t\tif (!extensionMutator.scope) {\n\t\t\t\t\tdelete extensionMutator.scope; // Convenient for tests\n\t\t\t\t}\n\t\t\t\t// Mutators get applied in the reverse order than they are created\n\t\t\t\tentry.unshift(extensionMutator);\n\n\t\t\t\tnext = it.next();\n\t\t\t}\n\t\t});\n\t}\n\n\tasync applyToProcessEnvironment(env: IProcessEnvironment, scope: EnvironmentVariableScope | undefined, variableResolver?: VariableResolver): Promise {\n\t\tlet lowerToActualVariableNames: { [lowerKey: string]: string | undefined } | undefined;\n\t\tif (isWindows) {\n\t\t\tlowerToActualVariableNames = {};\n\t\t\tObject.keys(env).forEach(e => lowerToActualVariableNames![e.toLowerCase()] = e);\n\t\t}\n\t\tfor (const [variable, mutators] of this.getVariableMap(scope)) {\n\t\t\tconst actualVariable = isWindows ? lowerToActualVariableNames![variable.toLowerCase()] || variable : variable;\n\t\t\tfor (const mutator of mutators) {\n\t\t\t\tconst value = variableResolver ? await variableResolver(mutator.value) : mutator.value;\n\t\t\t\t// Default: true\n\t\t\t\tif (mutator.options?.applyAtProcessCreation ?? true) {\n\t\t\t\t\tswitch (mutator.type) {\n\t\t\t\t\t\tcase EnvironmentVariableMutatorType.Append:\n\t\t\t\t\t\t\tenv[actualVariable] = (env[actualVariable] || '') + value;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase EnvironmentVariableMutatorType.Prepend:\n\t\t\t\t\t\t\tenv[actualVariable] = value + (env[actualVariable] || '');\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase EnvironmentVariableMutatorType.Replace:\n\t\t\t\t\t\t\tenv[actualVariable] = value;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Default: false\n\t\t\t\tif (mutator.options?.applyAtShellIntegration ?? false) {\n\t\t\t\t\tconst key = `VSCODE_ENV_${mutatorTypeToLabelMap.get(mutator.type)!}`;\n\t\t\t\t\tenv[key] = (env[key] ? env[key] + ':' : '') + variable + '=' + this._encodeColons(value);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _encodeColons(value: string): string {\n\t\treturn value.replaceAll(':', '\\\\x3a');\n\t}\n\n\tdiff(other: IMergedEnvironmentVariableCollection, scope: EnvironmentVariableScope | undefined): IMergedEnvironmentVariableCollectionDiff | undefined {\n\t\tconst added: Map = new Map();\n\t\tconst changed: Map = new Map();\n\t\tconst removed: Map = new Map();\n\n\t\t// Find added\n\t\tother.getVariableMap(scope).forEach((otherMutators, variable) => {\n\t\t\tconst currentMutators = this.getVariableMap(scope).get(variable);\n\t\t\tconst result = getMissingMutatorsFromArray(otherMutators, currentMutators);\n\t\t\tif (result) {\n\t\t\t\tadded.set(variable, result);\n\t\t\t}\n\t\t});\n\n\t\t// Find removed\n\t\tthis.getVariableMap(scope).forEach((currentMutators, variable) => {\n\t\t\tconst otherMutators = other.getVariableMap(scope).get(variable);\n\t\t\tconst result = getMissingMutatorsFromArray(currentMutators, otherMutators);\n\t\t\tif (result) {\n\t\t\t\tremoved.set(variable, result);\n\t\t\t}\n\t\t});\n\n\t\t// Find changed\n\t\tthis.getVariableMap(scope).forEach((currentMutators, variable) => {\n\t\t\tconst otherMutators = other.getVariableMap(scope).get(variable);\n\t\t\tconst result = getChangedMutatorsFromArray(currentMutators, otherMutators);\n\t\t\tif (result) {\n\t\t\t\tchanged.set(variable, result);\n\t\t\t}\n\t\t});\n\n\t\tif (added.size === 0 && changed.size === 0 && removed.size === 0) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn { added, changed, removed };\n\t}\n\n\tgetVariableMap(scope: EnvironmentVariableScope | undefined): Map {\n\t\tconst result = new Map();\n\t\tfor (const mutators of this.map.values()) {\n\t\t\tconst filteredMutators = mutators.filter(m => filterScope(m, scope));\n\t\t\tif (filteredMutators.length > 0) {\n\t\t\t\t// All of these mutators are for the same variable because they are in the same scope, hence choose anyone to form a key.\n\t\t\t\tresult.set(filteredMutators[0].variable, filteredMutators);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tgetDescriptionMap(scope: EnvironmentVariableScope | undefined): Map {\n\t\tconst result = new Map();\n\t\tfor (const mutators of this.descriptionMap.values()) {\n\t\t\tconst filteredMutators = mutators.filter(m => filterScope(m, scope, true));\n\t\t\tfor (const mutator of filteredMutators) {\n\t\t\t\tresult.set(mutator.extensionIdentifier, mutator.description);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate populateDescriptionMap(collection: IEnvironmentVariableCollection, extensionIdentifier: string): void {\n\t\tif (!collection.descriptionMap) {\n\t\t\treturn;\n\t\t}\n\t\tconst it = collection.descriptionMap.entries();\n\t\tlet next = it.next();\n\t\twhile (!next.done) {\n\t\t\tconst mutator = next.value[1];\n\t\t\tconst key = next.value[0];\n\t\t\tlet entry = this.descriptionMap.get(key);\n\t\t\tif (!entry) {\n\t\t\t\tentry = [];\n\t\t\t\tthis.descriptionMap.set(key, entry);\n\t\t\t}\n\t\t\tconst extensionMutator = {\n\t\t\t\textensionIdentifier,\n\t\t\t\tscope: mutator.scope,\n\t\t\t\tdescription: mutator.description\n\t\t\t};\n\t\t\tif (!extensionMutator.scope) {\n\t\t\t\tdelete extensionMutator.scope; // Convenient for tests\n\t\t\t}\n\t\t\tentry.push(extensionMutator);\n\n\t\t\tnext = it.next();\n\t\t}\n\n\t}\n}\n\n/**\n * Returns whether a mutator matches with the scope provided.\n * @param mutator Mutator to filter\n * @param scope Scope to be used for querying\n * @param strictFilter If true, mutators with global scope is not returned when querying for workspace scope.\n * i.e whether mutator scope should always exactly match with query scope.\n */\nfunction filterScope(\n\tmutator: IExtensionOwnedEnvironmentVariableMutator | IExtensionOwnedEnvironmentDescriptionMutator,\n\tscope: EnvironmentVariableScope | undefined,\n\tstrictFilter = false\n): boolean {\n\tif (!mutator.scope) {\n\t\tif (strictFilter) {\n\t\t\treturn scope === mutator.scope;\n\t\t}\n\t\treturn true;\n\t}\n\t// If a mutator is scoped to a workspace folder, only apply it if the workspace\n\t// folder matches.\n\tif (mutator.scope.workspaceFolder && scope?.workspaceFolder && mutator.scope.workspaceFolder.index === scope.workspaceFolder.index) {\n\t\treturn true;\n\t}\n\treturn false;\n}\n\nfunction getMissingMutatorsFromArray(\n\tcurrent: IExtensionOwnedEnvironmentVariableMutator[],\n\tother: IExtensionOwnedEnvironmentVariableMutator[] | undefined\n): IExtensionOwnedEnvironmentVariableMutator[] | undefined {\n\t// If it doesn't exist, all are removed\n\tif (!other) {\n\t\treturn current;\n\t}\n\n\t// Create a map to help\n\tconst otherMutatorExtensions = new Set();\n\tother.forEach(m => otherMutatorExtensions.add(m.extensionIdentifier));\n\n\t// Find entries removed from other\n\tconst result: IExtensionOwnedEnvironmentVariableMutator[] = [];\n\tcurrent.forEach(mutator => {\n\t\tif (!otherMutatorExtensions.has(mutator.extensionIdentifier)) {\n\t\t\tresult.push(mutator);\n\t\t}\n\t});\n\n\treturn result.length === 0 ? undefined : result;\n}\n\nfunction getChangedMutatorsFromArray(\n\tcurrent: IExtensionOwnedEnvironmentVariableMutator[],\n\tother: IExtensionOwnedEnvironmentVariableMutator[] | undefined\n): IExtensionOwnedEnvironmentVariableMutator[] | undefined {\n\t// If it doesn't exist, none are changed (they are removed)\n\tif (!other) {\n\t\treturn undefined;\n\t}\n\n\t// Create a map to help\n\tconst otherMutatorExtensions = new Map();\n\tother.forEach(m => otherMutatorExtensions.set(m.extensionIdentifier, m));\n\n\t// Find entries that exist in both but are not equal\n\tconst result: IExtensionOwnedEnvironmentVariableMutator[] = [];\n\tcurrent.forEach(mutator => {\n\t\tconst otherMutator = otherMutatorExtensions.get(mutator.extensionIdentifier);\n\t\tif (otherMutator && (mutator.type !== otherMutator.type || mutator.value !== otherMutator.value || mutator.scope?.workspaceFolder?.index !== otherMutator.scope?.workspaceFolder?.index)) {\n\t\t\t// Return the new result, not the old one\n\t\t\tresult.push(otherMutator);\n\t\t}\n\t});\n\n\treturn result.length === 0 ? undefined : 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 { IEnvironmentVariableCollectionDescription, IEnvironmentVariableCollection, IEnvironmentVariableMutator, ISerializableEnvironmentDescriptionMap as ISerializableEnvironmentDescriptionMap, ISerializableEnvironmentVariableCollection, ISerializableEnvironmentVariableCollections } from 'vs/platform/terminal/common/environmentVariable';\n\n// This file is shared between the renderer and extension host\n\nexport function serializeEnvironmentVariableCollection(collection: ReadonlyMap): ISerializableEnvironmentVariableCollection {\n\treturn [...collection.entries()];\n}\n\nexport function serializeEnvironmentDescriptionMap(descriptionMap: ReadonlyMap | undefined): ISerializableEnvironmentDescriptionMap {\n\treturn descriptionMap ? [...descriptionMap.entries()] : [];\n}\n\nexport function deserializeEnvironmentVariableCollection(\n\tserializedCollection: ISerializableEnvironmentVariableCollection\n): Map {\n\treturn new Map(serializedCollection);\n}\n\nexport function deserializeEnvironmentDescriptionMap(\n\tserializableEnvironmentDescription: ISerializableEnvironmentDescriptionMap | undefined\n): Map {\n\treturn new Map(serializableEnvironmentDescription ?? []);\n}\n\nexport function serializeEnvironmentVariableCollections(collections: ReadonlyMap): ISerializableEnvironmentVariableCollections {\n\treturn Array.from(collections.entries()).map(e => {\n\t\treturn [e[0], serializeEnvironmentVariableCollection(e[1].map), serializeEnvironmentDescriptionMap(e[1].descriptionMap)];\n\t});\n}\n\nexport function deserializeEnvironmentVariableCollections(\n\tserializedCollection: ISerializableEnvironmentVariableCollections\n): Map {\n\treturn new Map(serializedCollection.map(e => {\n\t\treturn [e[0], { map: deserializeEnvironmentVariableCollection(e[1]), descriptionMap: deserializeEnvironmentDescriptionMap(e[2]) }];\n\t}));\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { IProcessEnvironment, OperatingSystem } from 'vs/base/common/platform';\nimport { URI, UriComponents } from 'vs/base/common/uri';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\nimport { IPtyHostProcessReplayEvent, ISerializedCommandDetectionCapability, ITerminalCapabilityStore } from 'vs/platform/terminal/common/capabilities/capabilities';\nimport { IGetTerminalLayoutInfoArgs, IProcessDetails, ISetTerminalLayoutInfoArgs } from 'vs/platform/terminal/common/terminalProcess';\nimport { ThemeIcon } from 'vs/base/common/themables';\nimport { ISerializableEnvironmentVariableCollections } from 'vs/platform/terminal/common/environmentVariable';\nimport { RawContextKey } from 'vs/platform/contextkey/common/contextkey';\nimport { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';\nimport { Registry } from 'vs/platform/registry/common/platform';\nimport type * as performance from 'vs/base/common/performance';\nimport { ILogService } from 'vs/platform/log/common/log';\n\nexport const terminalTabFocusModeContextKey = new RawContextKey('terminalTabFocusMode', false, true);\n\nexport const enum TerminalSettingPrefix {\n\tAutomationProfile = 'terminal.integrated.automationProfile.',\n\tDefaultProfile = 'terminal.integrated.defaultProfile.',\n\tProfiles = 'terminal.integrated.profiles.'\n}\n\nexport const enum TerminalSettingId {\n\tSendKeybindingsToShell = 'terminal.integrated.sendKeybindingsToShell',\n\tAutomationProfileLinux = 'terminal.integrated.automationProfile.linux',\n\tAutomationProfileMacOs = 'terminal.integrated.automationProfile.osx',\n\tAutomationProfileWindows = 'terminal.integrated.automationProfile.windows',\n\tProfilesWindows = 'terminal.integrated.profiles.windows',\n\tProfilesMacOs = 'terminal.integrated.profiles.osx',\n\tProfilesLinux = 'terminal.integrated.profiles.linux',\n\tDefaultProfileLinux = 'terminal.integrated.defaultProfile.linux',\n\tDefaultProfileMacOs = 'terminal.integrated.defaultProfile.osx',\n\tDefaultProfileWindows = 'terminal.integrated.defaultProfile.windows',\n\tUseWslProfiles = 'terminal.integrated.useWslProfiles',\n\tTabsDefaultColor = 'terminal.integrated.tabs.defaultColor',\n\tTabsDefaultIcon = 'terminal.integrated.tabs.defaultIcon',\n\tTabsEnabled = 'terminal.integrated.tabs.enabled',\n\tTabsEnableAnimation = 'terminal.integrated.tabs.enableAnimation',\n\tTabsHideCondition = 'terminal.integrated.tabs.hideCondition',\n\tTabsShowActiveTerminal = 'terminal.integrated.tabs.showActiveTerminal',\n\tTabsShowActions = 'terminal.integrated.tabs.showActions',\n\tTabsLocation = 'terminal.integrated.tabs.location',\n\tTabsFocusMode = 'terminal.integrated.tabs.focusMode',\n\tMacOptionIsMeta = 'terminal.integrated.macOptionIsMeta',\n\tMacOptionClickForcesSelection = 'terminal.integrated.macOptionClickForcesSelection',\n\tAltClickMovesCursor = 'terminal.integrated.altClickMovesCursor',\n\tCopyOnSelection = 'terminal.integrated.copyOnSelection',\n\tEnableMultiLinePasteWarning = 'terminal.integrated.enableMultiLinePasteWarning',\n\tDrawBoldTextInBrightColors = 'terminal.integrated.drawBoldTextInBrightColors',\n\tFontFamily = 'terminal.integrated.fontFamily',\n\tFontSize = 'terminal.integrated.fontSize',\n\tLetterSpacing = 'terminal.integrated.letterSpacing',\n\tLineHeight = 'terminal.integrated.lineHeight',\n\tMinimumContrastRatio = 'terminal.integrated.minimumContrastRatio',\n\tTabStopWidth = 'terminal.integrated.tabStopWidth',\n\tFastScrollSensitivity = 'terminal.integrated.fastScrollSensitivity',\n\tMouseWheelScrollSensitivity = 'terminal.integrated.mouseWheelScrollSensitivity',\n\tBellDuration = 'terminal.integrated.bellDuration',\n\tFontWeight = 'terminal.integrated.fontWeight',\n\tFontWeightBold = 'terminal.integrated.fontWeightBold',\n\tCursorBlinking = 'terminal.integrated.cursorBlinking',\n\tCursorStyle = 'terminal.integrated.cursorStyle',\n\tCursorStyleInactive = 'terminal.integrated.cursorStyleInactive',\n\tCursorWidth = 'terminal.integrated.cursorWidth',\n\tScrollback = 'terminal.integrated.scrollback',\n\tDetectLocale = 'terminal.integrated.detectLocale',\n\tDefaultLocation = 'terminal.integrated.defaultLocation',\n\tGpuAcceleration = 'terminal.integrated.gpuAcceleration',\n\tTerminalTitleSeparator = 'terminal.integrated.tabs.separator',\n\tTerminalTitle = 'terminal.integrated.tabs.title',\n\tTerminalDescription = 'terminal.integrated.tabs.description',\n\tRightClickBehavior = 'terminal.integrated.rightClickBehavior',\n\tCwd = 'terminal.integrated.cwd',\n\tConfirmOnExit = 'terminal.integrated.confirmOnExit',\n\tConfirmOnKill = 'terminal.integrated.confirmOnKill',\n\tEnableBell = 'terminal.integrated.enableBell',\n\tEnableVisualBell = 'terminal.integrated.enableVisualBell',\n\tCommandsToSkipShell = 'terminal.integrated.commandsToSkipShell',\n\tAllowChords = 'terminal.integrated.allowChords',\n\tAllowMnemonics = 'terminal.integrated.allowMnemonics',\n\tTabFocusMode = 'terminal.integrated.tabFocusMode',\n\tEnvMacOs = 'terminal.integrated.env.osx',\n\tEnvLinux = 'terminal.integrated.env.linux',\n\tEnvWindows = 'terminal.integrated.env.windows',\n\tEnvironmentChangesIndicator = 'terminal.integrated.environmentChangesIndicator',\n\tEnvironmentChangesRelaunch = 'terminal.integrated.environmentChangesRelaunch',\n\tShowExitAlert = 'terminal.integrated.showExitAlert',\n\tSplitCwd = 'terminal.integrated.splitCwd',\n\tWindowsEnableConpty = 'terminal.integrated.windowsEnableConpty',\n\tWordSeparators = 'terminal.integrated.wordSeparators',\n\tEnableFileLinks = 'terminal.integrated.enableFileLinks',\n\tUnicodeVersion = 'terminal.integrated.unicodeVersion',\n\tLocalEchoLatencyThreshold = 'terminal.integrated.localEchoLatencyThreshold',\n\tLocalEchoEnabled = 'terminal.integrated.localEchoEnabled',\n\tLocalEchoExcludePrograms = 'terminal.integrated.localEchoExcludePrograms',\n\tLocalEchoStyle = 'terminal.integrated.localEchoStyle',\n\tEnablePersistentSessions = 'terminal.integrated.enablePersistentSessions',\n\tPersistentSessionReviveProcess = 'terminal.integrated.persistentSessionReviveProcess',\n\tHideOnStartup = 'terminal.integrated.hideOnStartup',\n\tCustomGlyphs = 'terminal.integrated.customGlyphs',\n\tPersistentSessionScrollback = 'terminal.integrated.persistentSessionScrollback',\n\tInheritEnv = 'terminal.integrated.inheritEnv',\n\tShowLinkHover = 'terminal.integrated.showLinkHover',\n\tIgnoreProcessNames = 'terminal.integrated.ignoreProcessNames',\n\tAutoReplies = 'terminal.integrated.autoReplies',\n\tShellIntegrationEnabled = 'terminal.integrated.shellIntegration.enabled',\n\tShellIntegrationShowWelcome = 'terminal.integrated.shellIntegration.showWelcome',\n\tShellIntegrationDecorationsEnabled = 'terminal.integrated.shellIntegration.decorationsEnabled',\n\tShellIntegrationCommandHistory = 'terminal.integrated.shellIntegration.history',\n\tShellIntegrationSuggestEnabled = 'terminal.integrated.shellIntegration.suggestEnabled',\n\tEnableImages = 'terminal.integrated.enableImages',\n\tSmoothScrolling = 'terminal.integrated.smoothScrolling',\n\tIgnoreBracketedPasteMode = 'terminal.integrated.ignoreBracketedPasteMode',\n\tFocusAfterRun = 'terminal.integrated.focusAfterRun',\n\tAccessibleViewPreserveCursorPosition = 'terminal.integrated.accessibleViewPreserveCursorPosition',\n\tAccessibleViewFocusOnCommandExecution = 'terminal.integrated.accessibleViewFocusOnCommandExecution',\n\tStickyScrollEnabled = 'terminal.integrated.stickyScroll.enabled',\n\tStickyScrollMaxLineCount = 'terminal.integrated.stickyScroll.maxLineCount',\n\tMouseWheelZoom = 'terminal.integrated.mouseWheelZoom',\n\n\t// Debug settings that are hidden from user\n\n\t/** Simulated latency applied to all calls made to the pty host */\n\tDeveloperPtyHostLatency = 'terminal.integrated.developer.ptyHost.latency',\n\t/** Simulated startup delay of the pty host process */\n\tDeveloperPtyHostStartupDelay = 'terminal.integrated.developer.ptyHost.startupDelay',\n\t/** Shows the textarea element */\n\tDevMode = 'terminal.integrated.developer.devMode'\n}\n\nexport const enum PosixShellType {\n\tPowerShell = 'pwsh',\n\tBash = 'bash',\n\tFish = 'fish',\n\tSh = 'sh',\n\tCsh = 'csh',\n\tKsh = 'ksh',\n\tZsh = 'zsh',\n\tPython = 'python'\n}\nexport const enum WindowsShellType {\n\tCommandPrompt = 'cmd',\n\tPowerShell = 'pwsh',\n\tWsl = 'wsl',\n\tGitBash = 'gitbash',\n\tPython = 'python'\n}\nexport type TerminalShellType = PosixShellType | WindowsShellType;\n\nexport interface IRawTerminalInstanceLayoutInfo {\n\trelativeSize: number;\n\tterminal: T;\n}\nexport type ITerminalInstanceLayoutInfoById = IRawTerminalInstanceLayoutInfo;\nexport type ITerminalInstanceLayoutInfo = IRawTerminalInstanceLayoutInfo;\n\nexport interface IRawTerminalTabLayoutInfo {\n\tisActive: boolean;\n\tactivePersistentProcessId: number | undefined;\n\tterminals: IRawTerminalInstanceLayoutInfo[];\n}\n\nexport type ITerminalTabLayoutInfoById = IRawTerminalTabLayoutInfo;\n\nexport interface IRawTerminalsLayoutInfo {\n\ttabs: IRawTerminalTabLayoutInfo[];\n}\n\nexport interface IPtyHostAttachTarget {\n\tid: number;\n\tpid: number;\n\ttitle: string;\n\ttitleSource: TitleEventSource;\n\tcwd: string;\n\tworkspaceId: string;\n\tworkspaceName: string;\n\tisOrphan: boolean;\n\ticon: TerminalIcon | undefined;\n\tfixedDimensions: IFixedTerminalDimensions | undefined;\n\tenvironmentVariableCollections: ISerializableEnvironmentVariableCollections | undefined;\n\treconnectionProperties?: IReconnectionProperties;\n\twaitOnExit?: WaitOnExitValue;\n\thideFromUser?: boolean;\n\tisFeatureTerminal?: boolean;\n\ttype?: TerminalType;\n\thasChildProcesses: boolean;\n\tshellIntegrationNonce: string;\n}\n\nexport interface IReconnectionProperties {\n\townerId: string;\n\tdata?: unknown;\n}\n\nexport type TerminalType = 'Task' | 'Local' | undefined;\n\nexport enum TitleEventSource {\n\t/** From the API or the rename command that overrides any other type */\n\tApi,\n\t/** From the process name property*/\n\tProcess,\n\t/** From the VT sequence */\n\tSequence,\n\t/** Config changed */\n\tConfig\n}\n\nexport type ITerminalsLayoutInfo = IRawTerminalsLayoutInfo;\nexport type ITerminalsLayoutInfoById = IRawTerminalsLayoutInfo;\n\nexport enum TerminalIpcChannels {\n\t/**\n\t * Communicates between the renderer process and shared process.\n\t */\n\tLocalPty = 'localPty',\n\t/**\n\t * Communicates between the shared process and the pty host process.\n\t */\n\tPtyHost = 'ptyHost',\n\t/**\n\t * Communicates between the renderer process and the pty host process.\n\t */\n\tPtyHostWindow = 'ptyHostWindow',\n\t/**\n\t * Deals with logging from the pty host process.\n\t */\n\tLogger = 'logger',\n\t/**\n\t * Enables the detection of unresponsive pty hosts.\n\t */\n\tHeartbeat = 'heartbeat'\n}\n\nexport const enum ProcessPropertyType {\n\tCwd = 'cwd',\n\tInitialCwd = 'initialCwd',\n\tFixedDimensions = 'fixedDimensions',\n\tTitle = 'title',\n\tShellType = 'shellType',\n\tHasChildProcesses = 'hasChildProcesses',\n\tResolvedShellLaunchConfig = 'resolvedShellLaunchConfig',\n\tOverrideDimensions = 'overrideDimensions',\n\tFailedShellIntegrationActivation = 'failedShellIntegrationActivation',\n\tUsedShellIntegrationInjection = 'usedShellIntegrationInjection'\n}\n\nexport interface IProcessProperty {\n\ttype: T;\n\tvalue: IProcessPropertyMap[T];\n}\n\nexport interface IProcessPropertyMap {\n\t[ProcessPropertyType.Cwd]: string;\n\t[ProcessPropertyType.InitialCwd]: string;\n\t[ProcessPropertyType.FixedDimensions]: IFixedTerminalDimensions;\n\t[ProcessPropertyType.Title]: string;\n\t[ProcessPropertyType.ShellType]: TerminalShellType | undefined;\n\t[ProcessPropertyType.HasChildProcesses]: boolean;\n\t[ProcessPropertyType.ResolvedShellLaunchConfig]: IShellLaunchConfig;\n\t[ProcessPropertyType.OverrideDimensions]: ITerminalDimensionsOverride | undefined;\n\t[ProcessPropertyType.FailedShellIntegrationActivation]: boolean | undefined;\n\t[ProcessPropertyType.UsedShellIntegrationInjection]: boolean | undefined;\n}\n\nexport interface IFixedTerminalDimensions {\n\t/**\n\t * The fixed columns of the terminal.\n\t */\n\tcols?: number;\n\n\t/**\n\t * The fixed rows of the terminal.\n\t */\n\trows?: number;\n}\n\n/**\n * A service that communicates with a pty host.\n*/\nexport interface IPtyService {\n\treadonly _serviceBrand: undefined;\n\n\treadonly onProcessData: Event<{ id: number; event: IProcessDataEvent | string }>;\n\treadonly onProcessReady: Event<{ id: number; event: IProcessReadyEvent }>;\n\treadonly onProcessReplay: Event<{ id: number; event: IPtyHostProcessReplayEvent }>;\n\treadonly onProcessOrphanQuestion: Event<{ id: number }>;\n\treadonly onDidRequestDetach: Event<{ requestId: number; workspaceId: string; instanceId: number }>;\n\treadonly onDidChangeProperty: Event<{ id: number; property: IProcessProperty }>;\n\treadonly onProcessExit: Event<{ id: number; event: number | undefined }>;\n\n\tcreateProcess(\n\t\tshellLaunchConfig: IShellLaunchConfig,\n\t\tcwd: string,\n\t\tcols: number,\n\t\trows: number,\n\t\tunicodeVersion: '6' | '11',\n\t\tenv: IProcessEnvironment,\n\t\texecutableEnv: IProcessEnvironment,\n\t\toptions: ITerminalProcessOptions,\n\t\tshouldPersist: boolean,\n\t\tworkspaceId: string,\n\t\tworkspaceName: string\n\t): Promise;\n\tattachToProcess(id: number): Promise;\n\tdetachFromProcess(id: number, forcePersist?: boolean): Promise;\n\tshutdownAll(): Promise;\n\n\t/**\n\t * Lists all orphaned processes, ie. those without a connected frontend.\n\t */\n\tlistProcesses(): Promise;\n\tgetPerformanceMarks(): Promise;\n\t/**\n\t * Measures and returns the latency of the current and all other processes to the pty host.\n\t */\n\tgetLatency(): Promise;\n\n\tstart(id: number): Promise;\n\tshutdown(id: number, immediate: boolean): Promise;\n\tinput(id: number, data: string): Promise;\n\tresize(id: number, cols: number, rows: number): Promise;\n\tclearBuffer(id: number): Promise;\n\tgetInitialCwd(id: number): Promise;\n\tgetCwd(id: number): Promise;\n\tacknowledgeDataEvent(id: number, charCount: number): Promise;\n\tsetUnicodeVersion(id: number, version: '6' | '11'): Promise;\n\tprocessBinary(id: number, data: string): Promise;\n\t/** Confirm the process is _not_ an orphan. */\n\torphanQuestionReply(id: number): Promise;\n\tupdateTitle(id: number, title: string, titleSource: TitleEventSource): Promise;\n\tupdateIcon(id: number, userInitiated: boolean, icon: TerminalIcon, color?: string): Promise;\n\n\tinstallAutoReply(match: string, reply: string): Promise;\n\tuninstallAllAutoReplies(): Promise;\n\tuninstallAutoReply(match: string): Promise;\n\tgetDefaultSystemShell(osOverride?: OperatingSystem): Promise;\n\tgetEnvironment(): Promise;\n\tgetWslPath(original: string, direction: 'unix-to-win' | 'win-to-unix'): Promise;\n\tgetRevivedPtyNewId(workspaceId: string, id: number): Promise;\n\tsetTerminalLayoutInfo(args: ISetTerminalLayoutInfoArgs): Promise;\n\tgetTerminalLayoutInfo(args: IGetTerminalLayoutInfoArgs): Promise;\n\treduceConnectionGraceTime(): Promise;\n\trequestDetachInstance(workspaceId: string, instanceId: number): Promise;\n\tacceptDetachInstanceReply(requestId: number, persistentProcessId?: number): Promise;\n\tfreePortKillProcess(port: string): Promise<{ port: string; processId: string }>;\n\t/**\n\t * Serializes and returns terminal state.\n\t * @param ids The persistent terminal IDs to serialize.\n\t */\n\tserializeTerminalState(ids: number[]): Promise;\n\t/**\n\t * Revives a workspaces terminal processes, these can then be reconnected to using the normal\n\t * flow for restoring terminals after reloading.\n\t */\n\treviveTerminalProcesses(workspaceId: string, state: ISerializedTerminalState[], dateTimeFormatLocate: string): Promise;\n\trefreshProperty(id: number, property: T): Promise;\n\tupdateProperty(id: number, property: T, value: IProcessPropertyMap[T]): Promise;\n\n\t// TODO: Make mandatory and remove impl from pty host service\n\trefreshIgnoreProcessNames?(names: string[]): Promise;\n}\nexport const IPtyService = createDecorator('ptyService');\n\nexport interface IPtyHostController {\n\treadonly onPtyHostExit: Event;\n\treadonly onPtyHostStart: Event;\n\treadonly onPtyHostUnresponsive: Event;\n\treadonly onPtyHostResponsive: Event;\n\treadonly onPtyHostRequestResolveVariables: Event;\n\n\trestartPtyHost(): Promise;\n\tacceptPtyHostResolvedVariables(requestId: number, resolved: string[]): Promise;\n\tgetProfiles(workspaceId: string, profiles: unknown, defaultProfile: unknown, includeDetectedProfiles?: boolean): Promise;\n}\n\n/**\n * A service that communicates with a pty host controller (eg. main or server\n * process) and is able to launch and forward requests to the pty host.\n*/\nexport interface IPtyHostService extends IPtyService, IPtyHostController {\n}\n\nexport interface IPtyHostLatencyMeasurement {\n\tlabel: string;\n\tlatency: number;\n}\n\n/**\n * Serialized terminal state matching the interface that can be used across versions, the version\n * should be verified before using the state payload.\n */\nexport interface ICrossVersionSerializedTerminalState {\n\tversion: number;\n\tstate: unknown;\n}\n\nexport interface ISerializedTerminalState {\n\tid: number;\n\tshellLaunchConfig: IShellLaunchConfig;\n\tprocessDetails: IProcessDetails;\n\tprocessLaunchConfig: IPersistentTerminalProcessLaunchConfig;\n\tunicodeVersion: '6' | '11';\n\treplayEvent: IPtyHostProcessReplayEvent;\n\ttimestamp: number;\n}\n\nexport interface IPersistentTerminalProcessLaunchConfig {\n\tenv: IProcessEnvironment;\n\texecutableEnv: IProcessEnvironment;\n\toptions: ITerminalProcessOptions;\n}\n\nexport interface IRequestResolveVariablesEvent {\n\trequestId: number;\n\tworkspaceId: string;\n\toriginalText: string[];\n}\n\nexport enum HeartbeatConstants {\n\t/**\n\t * The duration between heartbeats\n\t */\n\tBeatInterval = 5000,\n\t/**\n\t * The duration of the first heartbeat while the pty host is starting up. This is much larger\n\t * than the regular BeatInterval to accommodate slow machines, we still want to warn about the\n\t * pty host's unresponsiveness eventually though.\n\t */\n\tConnectingBeatInterval = 20000,\n\t/**\n\t * Defines a multiplier for BeatInterval for how long to wait before starting the second wait\n\t * timer.\n\t */\n\tFirstWaitMultiplier = 1.2,\n\t/**\n\t * Defines a multiplier for BeatInterval for how long to wait before telling the user about\n\t * non-responsiveness. The second timer is to avoid informing the user incorrectly when waking\n\t * the computer up from sleep\n\t */\n\tSecondWaitMultiplier = 1,\n\t/**\n\t * How long to wait before telling the user about non-responsiveness when they try to create a\n\t * process. This short circuits the standard wait timeouts to tell the user sooner and only\n\t * create process is handled to avoid additional perf overhead.\n\t */\n\tCreateProcessTimeout = 5000\n}\n\nexport interface IHeartbeatService {\n\treadonly onBeat: Event;\n}\n\n\nexport interface IShellLaunchConfig {\n\t/**\n\t * The name of the terminal, if this is not set the name of the process will be used.\n\t */\n\tname?: string;\n\n\t/**\n\t * A string to follow the name of the terminal with, indicating the type of terminal\n\t */\n\ttype?: 'Task' | 'Local';\n\n\t/**\n\t * The shell executable (bash, cmd, etc.).\n\t */\n\texecutable?: string;\n\n\t/**\n\t * The CLI arguments to use with executable, a string[] is in argv format and will be escaped,\n\t * a string is in \"CommandLine\" pre-escaped format and will be used as is. The string option is\n\t * only supported on Windows and will throw an exception if used on macOS or Linux.\n\t */\n\targs?: string[] | string;\n\n\t/**\n\t * The current working directory of the terminal, this overrides the `terminal.integrated.cwd`\n\t * settings key.\n\t */\n\tcwd?: string | URI;\n\n\t/**\n\t * A custom environment for the terminal, if this is not set the environment will be inherited\n\t * from the VS Code process.\n\t */\n\tenv?: ITerminalEnvironment;\n\n\t/**\n\t * Whether to ignore a custom cwd from the `terminal.integrated.cwd` settings key (e.g. if the\n\t * shell is being launched by an extension).\n\t */\n\tignoreConfigurationCwd?: boolean;\n\n\t/**\n\t * The reconnection properties for this terminal\n\t */\n\treconnectionProperties?: IReconnectionProperties;\n\n\t/** Whether to wait for a key press before closing the terminal. */\n\twaitOnExit?: WaitOnExitValue;\n\n\t/**\n\t * A string including ANSI escape sequences that will be written to the terminal emulator\n\t * _before_ the terminal process has launched, when a string is specified, a trailing \\n is\n\t * added at the end. This allows for example the terminal instance to display a styled message\n\t * as the first line of the terminal. Use \\x1b over \\033 or \\e for the escape control character.\n\t */\n\tinitialText?: string | { text: string; trailingNewLine: boolean };\n\n\t/**\n\t * Custom PTY/pseudoterminal process to use.\n\t */\n\tcustomPtyImplementation?: (terminalId: number, cols: number, rows: number) => ITerminalChildProcess;\n\n\t/**\n\t * A UUID generated by the extension host process for terminals created on the extension host process.\n\t */\n\textHostTerminalId?: string;\n\n\t/**\n\t * This is a terminal that attaches to an already running terminal.\n\t */\n\tattachPersistentProcess?: {\n\t\tid: number;\n\t\tfindRevivedId?: boolean;\n\t\tpid: number;\n\t\ttitle: string;\n\t\ttitleSource: TitleEventSource;\n\t\tcwd: string;\n\t\ticon?: TerminalIcon;\n\t\tcolor?: string;\n\t\thasChildProcesses?: boolean;\n\t\tfixedDimensions?: IFixedTerminalDimensions;\n\t\tenvironmentVariableCollections?: ISerializableEnvironmentVariableCollections;\n\t\treconnectionProperties?: IReconnectionProperties;\n\t\ttype?: TerminalType;\n\t\twaitOnExit?: WaitOnExitValue;\n\t\thideFromUser?: boolean;\n\t\tisFeatureTerminal?: boolean;\n\t\tshellIntegrationNonce: string;\n\t};\n\n\t/**\n\t * Whether the terminal process environment should be exactly as provided in\n\t * `TerminalOptions.env`. When this is false (default), the environment will be based on the\n\t * window's environment and also apply configured platform settings like\n\t * `terminal.integrated.env.windows` on top. When this is true, the complete environment must be\n\t * provided as nothing will be inherited from the process or any configuration.\n\t */\n\tstrictEnv?: boolean;\n\n\t/**\n\t * Whether the terminal process environment will inherit VS Code's \"shell environment\" that may\n\t * get sourced from running a login shell depnding on how the application was launched.\n\t * Consumers that rely on development tools being present in the $PATH should set this to true.\n\t * This will overwrite the value of the inheritEnv setting.\n\t */\n\tuseShellEnvironment?: boolean;\n\n\t/**\n\t * When enabled the terminal will run the process as normal but not be surfaced to the user\n\t * until `Terminal.show` is called. The typical usage for this is when you need to run\n\t * something that may need interactivity but only want to tell the user about it when\n\t * interaction is needed. Note that the terminals will still be exposed to all extensions\n\t * as normal and they will remain hidden when the workspace is reloaded.\n\t */\n\thideFromUser?: boolean;\n\n\t/**\n\t * Whether this terminal is not a terminal that the user directly created and uses, but rather\n\t * a terminal used to drive some VS Code feature.\n\t */\n\tisFeatureTerminal?: boolean;\n\n\t/**\n\t * Whether this terminal was created by an extension.\n\t */\n\tisExtensionOwnedTerminal?: boolean;\n\n\t/**\n\t * The icon for the terminal, used primarily in the terminal tab.\n\t */\n\ticon?: TerminalIcon;\n\n\t/**\n\t * The color ID to use for this terminal. If not specified it will use the default fallback\n\t */\n\tcolor?: string;\n\n\t/**\n\t * When a parent terminal is provided via API, the group needs\n\t * to find the index in order to place the child\n\t * directly to the right of its parent.\n\t */\n\tparentTerminalId?: number;\n\n\t/**\n\t * The dimensions for the instance as set by the user\n\t * or via Size to Content Width\n\t */\n\tfixedDimensions?: IFixedTerminalDimensions;\n\n\t/**\n\t * Opt-out of the default terminal persistence on restart and reload\n\t */\n\tisTransient?: boolean;\n\n\t/**\n\t * Create a terminal without shell integration even when it's enabled\n\t */\n\tignoreShellIntegration?: boolean;\n}\n\nexport type WaitOnExitValue = boolean | string | ((exitCode: number) => string);\n\nexport interface ICreateContributedTerminalProfileOptions {\n\ticon?: URI | string | { light: URI; dark: URI };\n\tcolor?: string;\n\tlocation?: TerminalLocation | { viewColumn: number; preserveState?: boolean } | { splitActiveTerminal: boolean };\n\tcwd?: string | URI;\n}\n\nexport enum TerminalLocation {\n\tPanel = 1,\n\tEditor = 2\n}\n\nexport const enum TerminalLocationString {\n\tTerminalView = 'view',\n\tEditor = 'editor'\n}\n\nexport type TerminalIcon = ThemeIcon | URI | { light: URI; dark: URI };\n\nexport interface IShellLaunchConfigDto {\n\tname?: string;\n\texecutable?: string;\n\targs?: string[] | string;\n\tcwd?: string | UriComponents;\n\tenv?: ITerminalEnvironment;\n\tuseShellEnvironment?: boolean;\n\thideFromUser?: boolean;\n\treconnectionProperties?: IReconnectionProperties;\n\ttype?: 'Task' | 'Local';\n\tisFeatureTerminal?: boolean;\n}\n\n/**\n * A set of options for the terminal process. These differ from the shell launch config in that they\n * are set internally to the terminal component, not from the outside.\n */\nexport interface ITerminalProcessOptions {\n\tshellIntegration: {\n\t\tenabled: boolean;\n\t\tsuggestEnabled: boolean;\n\t\tnonce: string;\n\t};\n\twindowsEnableConpty: boolean;\n\tenvironmentVariableCollections: ISerializableEnvironmentVariableCollections | undefined;\n\tworkspaceFolder: IWorkspaceFolder | undefined;\n}\n\nexport interface ITerminalEnvironment {\n\t[key: string]: string | null | undefined;\n}\n\nexport interface ITerminalLaunchError {\n\tmessage: string;\n\tcode?: number;\n}\n\nexport interface IProcessReadyEvent {\n\tpid: number;\n\tcwd: string;\n\twindowsPty: IProcessReadyWindowsPty | undefined;\n}\n\nexport interface IProcessReadyWindowsPty {\n\t/**\n\t * What pty emulation backend is being used.\n\t */\n\tbackend: 'conpty' | 'winpty';\n\t/**\n\t * The Windows build version (eg. 19045)\n\t */\n\tbuildNumber: number;\n}\n\n/**\n * An interface representing a raw terminal child process, this contains a subset of the\n * child_process.ChildProcess node.js interface.\n */\nexport interface ITerminalChildProcess {\n\t/**\n\t * A unique identifier for the terminal process. Note that the uniqueness only applies to a\n\t * given pty service connection, IDs will be duplicated for remote and local terminals for\n\t * example. The ID will be 0 if it does not support reconnection.\n\t */\n\tid: number;\n\n\t/**\n\t * Whether the process should be persisted across reloads.\n\t */\n\tshouldPersist: boolean;\n\n\tonProcessData: Event;\n\tonProcessReady: Event;\n\tonProcessReplayComplete?: Event;\n\tonDidChangeProperty: Event>;\n\tonProcessExit: Event;\n\tonRestoreCommands?: Event;\n\n\t/**\n\t * Starts the process.\n\t *\n\t * @returns undefined when the process was successfully started, otherwise an object containing\n\t * information on what went wrong.\n\t */\n\tstart(): Promise;\n\n\t/**\n\t * Detach the process from the UI and await reconnect.\n\t * @param forcePersist Whether to force the process to persist if it supports persistence.\n\t */\n\tdetach?(forcePersist?: boolean): Promise;\n\n\t/**\n\t * Frees the port and kills the process\n\t */\n\tfreePortKillProcess?(port: string): Promise<{ port: string; processId: string }>;\n\n\t/**\n\t * Shutdown the terminal process.\n\t *\n\t * @param immediate When true the process will be killed immediately, otherwise the process will\n\t * be given some time to make sure no additional data comes through.\n\t */\n\tshutdown(immediate: boolean): void;\n\tinput(data: string): void;\n\tprocessBinary(data: string): Promise;\n\tresize(cols: number, rows: number): void;\n\tclearBuffer(): void | Promise;\n\n\t/**\n\t * Acknowledge a data event has been parsed by the terminal, this is used to implement flow\n\t * control to ensure remote processes to not get too far ahead of the client and flood the\n\t * connection.\n\t * @param charCount The number of characters being acknowledged.\n\t */\n\tacknowledgeDataEvent(charCount: number): void;\n\n\t/**\n\t * Sets the unicode version for the process, this drives the size of some characters in the\n\t * xterm-headless instance.\n\t */\n\tsetUnicodeVersion(version: '6' | '11'): Promise;\n\n\tgetInitialCwd(): Promise;\n\tgetCwd(): Promise;\n\trefreshProperty(property: T): Promise;\n\tupdateProperty(property: T, value: IProcessPropertyMap[T]): Promise;\n}\n\nexport interface IReconnectConstants {\n\tgraceTime: number;\n\tshortGraceTime: number;\n\tscrollback: number;\n}\n\nexport const enum LocalReconnectConstants {\n\t/**\n\t * If there is no reconnection within this time-frame, consider the connection permanently closed...\n\t*/\n\tGraceTime = 60000, // 60 seconds\n\t/**\n\t * Maximal grace time between the first and the last reconnection...\n\t*/\n\tShortGraceTime = 6000, // 6 seconds\n}\n\nexport const enum FlowControlConstants {\n\t/**\n\t * The number of _unacknowledged_ chars to have been sent before the pty is paused in order for\n\t * the client to catch up.\n\t */\n\tHighWatermarkChars = 100000,\n\t/**\n\t * After flow control pauses the pty for the client the catch up, this is the number of\n\t * _unacknowledged_ chars to have been caught up to on the client before resuming the pty again.\n\t * This is used to attempt to prevent pauses in the flowing data; ideally while the pty is\n\t * paused the number of unacknowledged chars would always be greater than 0 or the client will\n\t * appear to stutter. In reality this balance is hard to accomplish though so heavy commands\n\t * will likely pause as latency grows, not flooding the connection is the important thing as\n\t * it's shared with other core functionality.\n\t */\n\tLowWatermarkChars = 5000,\n\t/**\n\t * The number characters that are accumulated on the client side before sending an ack event.\n\t * This must be less than or equal to LowWatermarkChars or the terminal max never unpause.\n\t */\n\tCharCountAckSize = 5000\n}\n\nexport interface IProcessDataEvent {\n\tdata: string;\n\ttrackCommit: boolean;\n\t/**\n\t * When trackCommit is set, this will be set to a promise that resolves when the data is parsed.\n\t */\n\twritePromise?: Promise;\n}\n\nexport interface ITerminalDimensions {\n\t/**\n\t * The columns of the terminal.\n\t */\n\tcols: number;\n\n\t/**\n\t * The rows of the terminal.\n\t */\n\trows: number;\n}\n\nexport interface ITerminalProfile {\n\tprofileName: string;\n\tpath: string;\n\tisDefault: boolean;\n\t/**\n\t * Whether the terminal profile contains a potentially unsafe {@link path}. For example, the path\n\t * `C:\\Cygwin` is the default install for Cygwin on Windows, but it could be created by any\n\t * user in a multi-user environment. As such, we don't want to blindly present it as a profile\n\t * without a warning.\n\t */\n\tisUnsafePath?: boolean;\n\t/**\n\t * An additional unsafe path that must exist, for example a script that appears in {@link args}.\n\t */\n\trequiresUnsafePath?: string;\n\tisAutoDetected?: boolean;\n\t/**\n\t * Whether the profile path was found on the `$PATH` environment variable, if so it will be\n\t * cleaner to display this profile in the UI using only `basename(path)`.\n\t */\n\tisFromPath?: boolean;\n\targs?: string | string[] | undefined;\n\tenv?: ITerminalEnvironment;\n\toverrideName?: boolean;\n\tcolor?: string;\n\ticon?: ThemeIcon | URI | { light: URI; dark: URI };\n}\n\nexport interface ITerminalDimensionsOverride extends Readonly {\n\t/**\n\t * indicate that xterm must receive these exact dimensions, even if they overflow the ui!\n\t */\n\tforceExactSize?: boolean;\n}\n\nexport const enum ProfileSource {\n\tGitBash = 'Git Bash',\n\tPwsh = 'PowerShell'\n}\n\nexport interface IBaseUnresolvedTerminalProfile {\n\targs?: string | string[] | undefined;\n\tisAutoDetected?: boolean;\n\toverrideName?: boolean;\n\ticon?: string | ThemeIcon | URI | { light: URI; dark: URI };\n\tcolor?: string;\n\tenv?: ITerminalEnvironment;\n\trequiresPath?: string | ITerminalUnsafePath;\n}\n\ntype OneOrN = T | T[];\n\nexport interface ITerminalUnsafePath {\n\tpath: string;\n\tisUnsafe: true;\n}\n\nexport interface ITerminalExecutable extends IBaseUnresolvedTerminalProfile {\n\tpath: OneOrN;\n}\n\nexport interface ITerminalProfileSource extends IBaseUnresolvedTerminalProfile {\n\tsource: ProfileSource;\n}\n\nexport interface ITerminalProfileContribution {\n\ttitle: string;\n\tid: string;\n\ticon?: URI | { light: URI; dark: URI } | string;\n\tcolor?: string;\n}\n\nexport interface IExtensionTerminalProfile extends ITerminalProfileContribution {\n\textensionIdentifier: string;\n}\n\nexport type ITerminalProfileObject = ITerminalExecutable | ITerminalProfileSource | IExtensionTerminalProfile | null;\n\nexport interface IShellIntegration {\n\treadonly capabilities: ITerminalCapabilityStore;\n\treadonly status: ShellIntegrationStatus;\n\n\treadonly onDidChangeStatus: Event;\n\n\tdeserialize(serialized: ISerializedCommandDetectionCapability): void;\n}\n\nexport interface ITerminalContributions {\n\tprofiles?: ITerminalProfileContribution[];\n}\n\nexport const enum ShellIntegrationStatus {\n\t/** No shell integration sequences have been encountered. */\n\tOff,\n\t/** Final term shell integration sequences have been encountered. */\n\tFinalTerm,\n\t/** VS Code shell integration sequences have been encountered. Supercedes FinalTerm. */\n\tVSCode\n}\n\nexport enum TerminalExitReason {\n\tUnknown = 0,\n\tShutdown = 1,\n\tProcess = 2,\n\tUser = 3,\n\tExtension = 4,\n}\n\nexport interface ITerminalOutputMatch {\n\tregexMatch: RegExpMatchArray;\n\toutputLines: string[];\n}\n\n/**\n * A matcher that runs on a sub-section of a terminal command's output\n */\nexport interface ITerminalOutputMatcher {\n\t/**\n\t * A string or regex to match against the unwrapped line. If this is a regex with the multiline\n\t * flag, it will scan an amount of lines equal to `\\n` instances in the regex + 1.\n\t */\n\tlineMatcher: string | RegExp;\n\t/**\n\t * Which side of the output to anchor the {@link offset} and {@link length} against.\n\t */\n\tanchor: 'top' | 'bottom';\n\t/**\n\t * The number of rows above or below the {@link anchor} to start matching against.\n\t */\n\toffset: number;\n\t/**\n\t * The number of rows to match against, this should be as small as possible for performance\n\t * reasons. This is capped at 40.\n\t */\n\tlength: number;\n\n\t/**\n\t * If multiple matches are expected - this will result in {@link outputLines} being returned\n\t * when there's a {@link regexMatch} from {@link offset} to {@link length}\n\t */\n\tmultipleMatches?: boolean;\n}\n\nexport interface ITerminalCommandSelector {\n\tid: string;\n\tcommandLineMatcher: string | RegExp;\n\toutputMatcher?: ITerminalOutputMatcher;\n\texitStatus: boolean;\n\tcommandExitResult: 'success' | 'error';\n\tkind?: 'fix' | 'explain';\n}\n\nexport interface ITerminalBackend {\n\treadonly remoteAuthority: string | undefined;\n\n\treadonly isResponsive: boolean;\n\n\t/**\n\t * A promise that resolves when the backend is ready to be used, ie. after terminal persistence\n\t * has been actioned.\n\t */\n\treadonly whenReady: Promise;\n\t/**\n\t * Signal to the backend that persistence has been actioned and is ready for use.\n\t */\n\tsetReady(): void;\n\n\t/**\n\t * Fired when the ptyHost process becomes non-responsive, this should disable stdin for all\n\t * terminals using this pty host connection and mark them as disconnected.\n\t */\n\tonPtyHostUnresponsive: Event;\n\t/**\n\t * Fired when the ptyHost process becomes responsive after being non-responsive. Allowing\n\t * previously disconnected terminals to reconnect.\n\t */\n\tonPtyHostResponsive: Event;\n\t/**\n\t * Fired when the ptyHost has been restarted, this is used as a signal for listening terminals\n\t * that its pty has been lost and will remain disconnected.\n\t */\n\tonPtyHostRestart: Event;\n\n\tonDidRequestDetach: Event<{ requestId: number; workspaceId: string; instanceId: number }>;\n\n\tattachToProcess(id: number): Promise;\n\tattachToRevivedProcess(id: number): Promise;\n\tlistProcesses(): Promise;\n\tgetLatency(): Promise;\n\tgetDefaultSystemShell(osOverride?: OperatingSystem): Promise;\n\tgetProfiles(profiles: unknown, defaultProfile: unknown, includeDetectedProfiles?: boolean): Promise;\n\tgetWslPath(original: string, direction: 'unix-to-win' | 'win-to-unix'): Promise;\n\tgetEnvironment(): Promise;\n\tgetShellEnvironment(): Promise;\n\tsetTerminalLayoutInfo(layoutInfo?: ITerminalsLayoutInfoById): Promise;\n\tupdateTitle(id: number, title: string, titleSource: TitleEventSource): Promise;\n\tupdateIcon(id: number, userInitiated: boolean, icon: TerminalIcon, color?: string): Promise;\n\tgetTerminalLayoutInfo(): Promise;\n\tgetPerformanceMarks(): Promise;\n\treduceConnectionGraceTime(): Promise;\n\trequestDetachInstance(workspaceId: string, instanceId: number): Promise;\n\tacceptDetachInstanceReply(requestId: number, persistentProcessId?: number): Promise;\n\tpersistTerminalState(): Promise;\n\n\tcreateProcess(\n\t\tshellLaunchConfig: IShellLaunchConfig,\n\t\tcwd: string,\n\t\tcols: number,\n\t\trows: number,\n\t\tunicodeVersion: '6' | '11',\n\t\tenv: IProcessEnvironment,\n\t\toptions: ITerminalProcessOptions,\n\t\tshouldPersist: boolean\n\t): Promise;\n\n\trestartPtyHost(): void;\n}\n\nexport const TerminalExtensions = {\n\tBackend: 'workbench.contributions.terminal.processBackend'\n};\n\nexport interface ITerminalBackendRegistry {\n\t/**\n\t * Gets all backends in the registry.\n\t */\n\tbackends: ReadonlyMap;\n\n\t/**\n\t * Registers a terminal backend for a remote authority.\n\t */\n\tregisterTerminalBackend(backend: ITerminalBackend): void;\n\n\t/**\n\t * Returns the registered terminal backend for a remote authority.\n\t */\n\tgetTerminalBackend(remoteAuthority?: string): ITerminalBackend | undefined;\n}\n\nclass TerminalBackendRegistry implements ITerminalBackendRegistry {\n\tprivate readonly _backends = new Map();\n\n\tget backends(): ReadonlyMap { return this._backends; }\n\n\tregisterTerminalBackend(backend: ITerminalBackend): void {\n\t\tconst key = this._sanitizeRemoteAuthority(backend.remoteAuthority);\n\t\tif (this._backends.has(key)) {\n\t\t\tthrow new Error(`A terminal backend with remote authority '${key}' was already registered.`);\n\t\t}\n\t\tthis._backends.set(key, backend);\n\t}\n\n\tgetTerminalBackend(remoteAuthority: string | undefined): ITerminalBackend | undefined {\n\t\treturn this._backends.get(this._sanitizeRemoteAuthority(remoteAuthority));\n\t}\n\n\tprivate _sanitizeRemoteAuthority(remoteAuthority: string | undefined) {\n\t\t// Normalize the key to lowercase as the authority is case-insensitive\n\t\treturn remoteAuthority?.toLowerCase() ?? '';\n\t}\n}\nRegistry.add(TerminalExtensions.Backend, new TerminalBackendRegistry());\n\nexport const ILocalPtyService = createDecorator('localPtyService');\n\n/**\n * A service responsible for communicating with the pty host process on Electron.\n *\n * **This service should only be used within the terminal component.**\n */\nexport interface ILocalPtyService extends IPtyHostService { }\n\nexport const ITerminalLogService = createDecorator('terminalLogService');\nexport interface ITerminalLogService extends ILogService {\n\t/**\n\t * Similar to _serviceBrand but used to differentiate this service at compile time from\n\t * ILogService; ITerminalLogService is an ILogService, but ILogService is not an\n\t * ITerminalLogService.\n\t */\n\treadonly _logBrand: 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 { Event } from 'vs/base/common/event';\nimport { IDisposable } from 'vs/base/common/lifecycle';\nimport { IProcessDataEvent } from 'vs/platform/terminal/common/terminal';\n\ninterface TerminalDataBuffer extends IDisposable {\n\tdata: string[];\n\ttimeoutId: any;\n}\n\nexport class TerminalDataBufferer implements IDisposable {\n\tprivate readonly _terminalBufferMap = new Map();\n\n\tconstructor(private readonly _callback: (id: number, data: string) => void) {\n\t}\n\n\tdispose() {\n\t\tfor (const buffer of this._terminalBufferMap.values()) {\n\t\t\tbuffer.dispose();\n\t\t}\n\t}\n\n\tstartBuffering(id: number, event: Event, throttleBy: number = 5): IDisposable {\n\n\t\tconst disposable = event((e: string | IProcessDataEvent) => {\n\t\t\tconst data = (typeof e === 'string' ? e : e.data);\n\t\t\tlet buffer = this._terminalBufferMap.get(id);\n\t\t\tif (buffer) {\n\t\t\t\tbuffer.data.push(data);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst timeoutId = setTimeout(() => this.flushBuffer(id), throttleBy);\n\t\t\tbuffer = {\n\t\t\t\tdata: [data],\n\t\t\t\ttimeoutId: timeoutId,\n\t\t\t\tdispose: () => {\n\t\t\t\t\tclearTimeout(timeoutId);\n\t\t\t\t\tthis.flushBuffer(id);\n\t\t\t\t\tdisposable.dispose();\n\t\t\t\t}\n\t\t\t};\n\t\t\tthis._terminalBufferMap.set(id, buffer);\n\t\t});\n\t\treturn disposable;\n\t}\n\n\tstopBuffering(id: number) {\n\t\tconst buffer = this._terminalBufferMap.get(id);\n\t\tbuffer?.dispose();\n\t}\n\n\tflushBuffer(id: number): void {\n\t\tconst buffer = this._terminalBufferMap.get(id);\n\t\tif (buffer) {\n\t\t\tthis._terminalBufferMap.delete(id);\n\t\t\tthis._callback(id, buffer.data.join(''));\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 { OperatingSystem, OS } from 'vs/base/common/platform';\n\n/**\n * Aggressively escape non-windows paths to prepare for being sent to a shell. This will do some\n * escaping inaccurately to be careful about possible script injection via the file path. For\n * example, we're trying to prevent this sort of attack: `/foo/file$(echo evil)`.\n */\nexport function escapeNonWindowsPath(path: string): string {\n\tlet newPath = path;\n\tif (newPath.includes('\\\\')) {\n\t\tnewPath = newPath.replace(/\\\\/g, '\\\\\\\\');\n\t}\n\tconst bannedChars = /[\\`\\$\\|\\&\\>\\~\\#\\!\\^\\*\\;\\<\\\"\\']/g;\n\tnewPath = newPath.replace(bannedChars, '');\n\treturn `'${newPath}'`;\n}\n\n/**\n * Collapses the user's home directory into `~` if it exists within the path, this gives a shorter\n * path that is more suitable within the context of a terminal.\n */\nexport function collapseTildePath(path: string | undefined, userHome: string | undefined, separator: string): string {\n\tif (!path) {\n\t\treturn '';\n\t}\n\tif (!userHome) {\n\t\treturn path;\n\t}\n\t// Trim the trailing separator from the end if it exists\n\tif (userHome.match(/[\\/\\\\]$/)) {\n\t\tuserHome = userHome.slice(0, userHome.length - 1);\n\t}\n\tconst normalizedPath = path.replace(/\\\\/g, '/').toLowerCase();\n\tconst normalizedUserHome = userHome.replace(/\\\\/g, '/').toLowerCase();\n\tif (!normalizedPath.includes(normalizedUserHome)) {\n\t\treturn path;\n\t}\n\treturn `~${separator}${path.slice(userHome.length + 1)}`;\n}\n\n/**\n * Sanitizes a cwd string, removing any wrapping quotes and making the Windows drive letter\n * uppercase.\n * @param cwd The directory to sanitize.\n */\nexport function sanitizeCwd(cwd: string): string {\n\t// Sanity check that the cwd is not wrapped in quotes (see #160109)\n\tif (cwd.match(/^['\"].*['\"]$/)) {\n\t\tcwd = cwd.substring(1, cwd.length - 1);\n\t}\n\t// Make the drive letter uppercase on Windows (see #9448)\n\tif (OS === OperatingSystem.Windows && cwd && cwd[1] === ':') {\n\t\treturn cwd[0].toUpperCase() + cwd.substring(1);\n\t}\n\treturn cwd;\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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';\nimport { URI, UriComponents } from 'vs/base/common/uri';\nimport { localize } from 'vs/nls';\nimport { IExtensionTerminalProfile, ITerminalProfile, TerminalIcon } from 'vs/platform/terminal/common/terminal';\nimport { ThemeIcon } from 'vs/base/common/themables';\n\nexport function createProfileSchemaEnums(detectedProfiles: ITerminalProfile[], extensionProfiles?: readonly IExtensionTerminalProfile[]): {\n\tvalues: (string | null)[] | undefined;\n\tmarkdownDescriptions: string[] | undefined;\n} {\n\tconst result: { name: string | null; description: string }[] = [{\n\t\tname: null,\n\t\tdescription: localize('terminalAutomaticProfile', 'Automatically detect the default')\n\t}];\n\tresult.push(...detectedProfiles.map(e => {\n\t\treturn {\n\t\t\tname: e.profileName,\n\t\t\tdescription: createProfileDescription(e)\n\t\t};\n\t}));\n\tif (extensionProfiles) {\n\t\tresult.push(...extensionProfiles.map(extensionProfile => {\n\t\t\treturn {\n\t\t\t\tname: extensionProfile.title,\n\t\t\t\tdescription: createExtensionProfileDescription(extensionProfile)\n\t\t\t};\n\t\t}));\n\t}\n\treturn {\n\t\tvalues: result.map(e => e.name),\n\t\tmarkdownDescriptions: result.map(e => e.description)\n\t};\n}\n\nfunction createProfileDescription(profile: ITerminalProfile): string {\n\tlet description = `$(${ThemeIcon.isThemeIcon(profile.icon) ? profile.icon.id : profile.icon ? profile.icon : Codicon.terminal.id}) ${profile.profileName}\\n- path: ${profile.path}`;\n\tif (profile.args) {\n\t\tif (typeof profile.args === 'string') {\n\t\t\tdescription += `\\n- args: \"${profile.args}\"`;\n\t\t} else {\n\t\t\tdescription += `\\n- args: [${profile.args.length === 0 ? '' : `'${profile.args.join(`','`)}'`}]`;\n\t\t}\n\t}\n\tif (profile.overrideName !== undefined) {\n\t\tdescription += `\\n- overrideName: ${profile.overrideName}`;\n\t}\n\tif (profile.color) {\n\t\tdescription += `\\n- color: ${profile.color}`;\n\t}\n\tif (profile.env) {\n\t\tdescription += `\\n- env: ${JSON.stringify(profile.env)}`;\n\t}\n\treturn description;\n}\n\nfunction createExtensionProfileDescription(profile: IExtensionTerminalProfile): string {\n\tconst description = `$(${ThemeIcon.isThemeIcon(profile.icon) ? profile.icon.id : profile.icon ? profile.icon : Codicon.terminal.id}) ${profile.title}\\n- extensionIdentifier: ${profile.extensionIdentifier}`;\n\treturn description;\n}\n\n\nexport function terminalProfileArgsMatch(args1: string | string[] | undefined, args2: string | string[] | undefined): boolean {\n\tif (!args1 && !args2) {\n\t\treturn true;\n\t} else if (typeof args1 === 'string' && typeof args2 === 'string') {\n\t\treturn args1 === args2;\n\t} else if (Array.isArray(args1) && Array.isArray(args2)) {\n\t\tif (args1.length !== args2.length) {\n\t\t\treturn false;\n\t\t}\n\t\tfor (let i = 0; i < args1.length; i++) {\n\t\t\tif (args1[i] !== args2[i]) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\treturn false;\n}\n\nexport function terminalIconsEqual(a?: TerminalIcon, b?: TerminalIcon): boolean {\n\tif (!a && !b) {\n\t\treturn true;\n\t} else if (!a || !b) {\n\t\treturn false;\n\t}\n\n\tif (ThemeIcon.isThemeIcon(a) && ThemeIcon.isThemeIcon(b)) {\n\t\treturn a.id === b.id && a.color === b.color;\n\t}\n\tif (typeof a === 'object' && 'light' in a && 'dark' in a\n\t\t&& typeof b === 'object' && 'light' in b && 'dark' in b) {\n\t\tconst castedA = (a as { light: unknown; dark: unknown });\n\t\tconst castedB = (b as { light: unknown; dark: unknown });\n\t\tif ((URI.isUri(castedA.light) || isUriComponents(castedA.light)) && (URI.isUri(castedA.dark) || isUriComponents(castedA.dark))\n\t\t\t&& (URI.isUri(castedB.light) || isUriComponents(castedB.light)) && (URI.isUri(castedB.dark) || isUriComponents(castedB.dark))) {\n\t\t\treturn castedA.light.path === castedB.light.path && castedA.dark.path === castedB.dark.path;\n\t\t}\n\t}\n\tif ((URI.isUri(a) && URI.isUri(b)) || (isUriComponents(a) || isUriComponents(b))) {\n\t\tconst castedA = (a as { scheme: unknown; path: unknown });\n\t\tconst castedB = (b as { scheme: unknown; path: unknown });\n\t\treturn castedA.path === castedB.path && castedA.scheme === castedB.scheme;\n\t}\n\n\treturn false;\n}\n\n\nexport function isUriComponents(thing: unknown): thing is UriComponents {\n\tif (!thing) {\n\t\treturn false;\n\t}\n\treturn typeof (thing).path === 'string' &&\n\t\ttypeof (thing).scheme === '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 { getAllCodicons } from 'vs/base/common/codicons';\nimport { IJSONSchema, IJSONSchemaMap } from 'vs/base/common/jsonSchema';\nimport { OperatingSystem, Platform, PlatformToString } from 'vs/base/common/platform';\nimport { localize } from 'vs/nls';\nimport { ConfigurationScope, Extensions, IConfigurationNode, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';\nimport { Registry } from 'vs/platform/registry/common/platform';\nimport { IExtensionTerminalProfile, ITerminalProfile, TerminalSettingId } from 'vs/platform/terminal/common/terminal';\nimport { createProfileSchemaEnums } from 'vs/platform/terminal/common/terminalProfiles';\n\nexport const terminalColorSchema: IJSONSchema = {\n\ttype: ['string', 'null'],\n\tenum: [\n\t\t'terminal.ansiBlack',\n\t\t'terminal.ansiRed',\n\t\t'terminal.ansiGreen',\n\t\t'terminal.ansiYellow',\n\t\t'terminal.ansiBlue',\n\t\t'terminal.ansiMagenta',\n\t\t'terminal.ansiCyan',\n\t\t'terminal.ansiWhite'\n\t],\n\tdefault: null\n};\n\nexport const terminalIconSchema: IJSONSchema = {\n\ttype: 'string',\n\tenum: Array.from(getAllCodicons(), icon => icon.id),\n\tmarkdownEnumDescriptions: Array.from(getAllCodicons(), icon => `$(${icon.id})`),\n};\n\nconst terminalProfileBaseProperties: IJSONSchemaMap = {\n\targs: {\n\t\tdescription: localize('terminalProfile.args', 'An optional set of arguments to run the shell executable with.'),\n\t\ttype: 'array',\n\t\titems: {\n\t\t\ttype: 'string'\n\t\t}\n\t},\n\toverrideName: {\n\t\tdescription: localize('terminalProfile.overrideName', 'Whether or not to replace the dynamic terminal title that detects what program is running with the static profile name.'),\n\t\ttype: 'boolean'\n\t},\n\ticon: {\n\t\tdescription: localize('terminalProfile.icon', 'A codicon ID to associate with the terminal icon.'),\n\t\t...terminalIconSchema\n\t},\n\tcolor: {\n\t\tdescription: localize('terminalProfile.color', 'A theme color ID to associate with the terminal icon.'),\n\t\t...terminalColorSchema\n\t},\n\tenv: {\n\t\tmarkdownDescription: localize('terminalProfile.env', \"An object with environment variables that will be added to the terminal profile process. Set to `null` to delete environment variables from the base environment.\"),\n\t\ttype: 'object',\n\t\tadditionalProperties: {\n\t\t\ttype: ['string', 'null']\n\t\t},\n\t\tdefault: {}\n\t}\n};\n\nconst terminalProfileSchema: IJSONSchema = {\n\ttype: 'object',\n\trequired: ['path'],\n\tproperties: {\n\t\tpath: {\n\t\t\tdescription: localize('terminalProfile.path', 'A single path to a shell executable or an array of paths that will be used as fallbacks when one fails.'),\n\t\t\ttype: ['string', 'array'],\n\t\t\titems: {\n\t\t\t\ttype: 'string'\n\t\t\t}\n\t\t},\n\t\t...terminalProfileBaseProperties\n\t}\n};\n\nconst terminalAutomationProfileSchema: IJSONSchema = {\n\ttype: 'object',\n\trequired: ['path'],\n\tproperties: {\n\t\tpath: {\n\t\t\tdescription: localize('terminalAutomationProfile.path', 'A single path to a shell executable.'),\n\t\t\ttype: ['string'],\n\t\t\titems: {\n\t\t\t\ttype: 'string'\n\t\t\t}\n\t\t},\n\t\t...terminalProfileBaseProperties\n\t}\n};\n\nfunction createTerminalProfileMarkdownDescription(platform: Platform.Linux | Platform.Mac | Platform.Windows): string {\n\tconst key = platform === Platform.Linux ? 'linux' : platform === Platform.Mac ? 'osx' : 'windows';\n\treturn localize(\n\t\t{\n\t\t\tkey: 'terminal.integrated.profile',\n\t\t\tcomment: ['{0} is the platform, {1} is a code block, {2} and {3} are a link start and end']\n\t\t},\n\t\t\"A set of terminal profile customizations for {0} which allows adding, removing or changing how terminals are launched. Profiles are made up of a mandatory path, optional arguments and other presentation options.\\n\\nTo override an existing profile use its profile name as the key, for example:\\n\\n{1}\\n\\n{2}Read more about configuring profiles{3}.\",\n\t\tPlatformToString(platform),\n\t\t'```json\\n\"terminal.integrated.profile.' + key + '\": {\\n \"bash\": null\\n}\\n```',\n\t\t'[',\n\t\t'](https://code.visualstudio.com/docs/terminal/profiles)'\n\t);\n}\n\nconst terminalPlatformConfiguration: IConfigurationNode = {\n\tid: 'terminal',\n\torder: 100,\n\ttitle: localize('terminalIntegratedConfigurationTitle', \"Integrated Terminal\"),\n\ttype: 'object',\n\tproperties: {\n\t\t[TerminalSettingId.AutomationProfileLinux]: {\n\t\t\trestricted: true,\n\t\t\tmarkdownDescription: localize('terminal.integrated.automationProfile.linux', \"The terminal profile to use on Linux for automation-related terminal usage like tasks and debug.\"),\n\t\t\ttype: ['object', 'null'],\n\t\t\tdefault: null,\n\t\t\t'anyOf': [\n\t\t\t\t{ type: 'null' },\n\t\t\t\tterminalAutomationProfileSchema\n\t\t\t],\n\t\t\tdefaultSnippets: [\n\t\t\t\t{\n\t\t\t\t\tbody: {\n\t\t\t\t\t\tpath: '${1}',\n\t\t\t\t\t\ticon: '${2}'\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t[TerminalSettingId.AutomationProfileMacOs]: {\n\t\t\trestricted: true,\n\t\t\tmarkdownDescription: localize('terminal.integrated.automationProfile.osx', \"The terminal profile to use on macOS for automation-related terminal usage like tasks and debug.\"),\n\t\t\ttype: ['object', 'null'],\n\t\t\tdefault: null,\n\t\t\t'anyOf': [\n\t\t\t\t{ type: 'null' },\n\t\t\t\tterminalAutomationProfileSchema\n\t\t\t],\n\t\t\tdefaultSnippets: [\n\t\t\t\t{\n\t\t\t\t\tbody: {\n\t\t\t\t\t\tpath: '${1}',\n\t\t\t\t\t\ticon: '${2}'\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t[TerminalSettingId.AutomationProfileWindows]: {\n\t\t\trestricted: true,\n\t\t\tmarkdownDescription: localize('terminal.integrated.automationProfile.windows', \"The terminal profile to use for automation-related terminal usage like tasks and debug. This setting will currently be ignored if {0} (now deprecated) is set.\", '`terminal.integrated.automationShell.windows`'),\n\t\t\ttype: ['object', 'null'],\n\t\t\tdefault: null,\n\t\t\t'anyOf': [\n\t\t\t\t{ type: 'null' },\n\t\t\t\tterminalAutomationProfileSchema\n\t\t\t],\n\t\t\tdefaultSnippets: [\n\t\t\t\t{\n\t\t\t\t\tbody: {\n\t\t\t\t\t\tpath: '${1}',\n\t\t\t\t\t\ticon: '${2}'\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t[TerminalSettingId.ProfilesWindows]: {\n\t\t\trestricted: true,\n\t\t\tmarkdownDescription: createTerminalProfileMarkdownDescription(Platform.Windows),\n\t\t\ttype: 'object',\n\t\t\tdefault: {\n\t\t\t\t'PowerShell': {\n\t\t\t\t\tsource: 'PowerShell',\n\t\t\t\t\ticon: 'terminal-powershell'\n\t\t\t\t},\n\t\t\t\t'Command Prompt': {\n\t\t\t\t\tpath: [\n\t\t\t\t\t\t'${env:windir}\\\\Sysnative\\\\cmd.exe',\n\t\t\t\t\t\t'${env:windir}\\\\System32\\\\cmd.exe'\n\t\t\t\t\t],\n\t\t\t\t\targs: [],\n\t\t\t\t\ticon: 'terminal-cmd'\n\t\t\t\t},\n\t\t\t\t'Git Bash': {\n\t\t\t\t\tsource: 'Git Bash'\n\t\t\t\t}\n\t\t\t},\n\t\t\tadditionalProperties: {\n\t\t\t\t'anyOf': [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'object',\n\t\t\t\t\t\trequired: ['source'],\n\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\tsource: {\n\t\t\t\t\t\t\t\tdescription: localize('terminalProfile.windowsSource', 'A profile source that will auto detect the paths to the shell. Note that non-standard executable locations are not supported and must be created manually in a new profile.'),\n\t\t\t\t\t\t\t\tenum: ['PowerShell', 'Git Bash']\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t...terminalProfileBaseProperties\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\ttype: 'object',\n\t\t\t\t\t\trequired: ['extensionIdentifier', 'id', 'title'],\n\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\textensionIdentifier: {\n\t\t\t\t\t\t\t\tdescription: localize('terminalProfile.windowsExtensionIdentifier', 'The extension that contributed this profile.'),\n\t\t\t\t\t\t\t\ttype: 'string'\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tid: {\n\t\t\t\t\t\t\t\tdescription: localize('terminalProfile.windowsExtensionId', 'The id of the extension terminal'),\n\t\t\t\t\t\t\t\ttype: 'string'\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\ttitle: {\n\t\t\t\t\t\t\t\tdescription: localize('terminalProfile.windowsExtensionTitle', 'The name of the extension terminal'),\n\t\t\t\t\t\t\t\ttype: 'string'\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t...terminalProfileBaseProperties\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t{ type: 'null' },\n\t\t\t\t\tterminalProfileSchema\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t[TerminalSettingId.ProfilesMacOs]: {\n\t\t\trestricted: true,\n\t\t\tmarkdownDescription: createTerminalProfileMarkdownDescription(Platform.Mac),\n\t\t\ttype: 'object',\n\t\t\tdefault: {\n\t\t\t\t'bash': {\n\t\t\t\t\tpath: 'bash',\n\t\t\t\t\targs: ['-l'],\n\t\t\t\t\ticon: 'terminal-bash'\n\t\t\t\t},\n\t\t\t\t'zsh': {\n\t\t\t\t\tpath: 'zsh',\n\t\t\t\t\targs: ['-l']\n\t\t\t\t},\n\t\t\t\t'fish': {\n\t\t\t\t\tpath: 'fish',\n\t\t\t\t\targs: ['-l']\n\t\t\t\t},\n\t\t\t\t'tmux': {\n\t\t\t\t\tpath: 'tmux',\n\t\t\t\t\ticon: 'terminal-tmux'\n\t\t\t\t},\n\t\t\t\t'pwsh': {\n\t\t\t\t\tpath: 'pwsh',\n\t\t\t\t\ticon: 'terminal-powershell'\n\t\t\t\t}\n\t\t\t},\n\t\t\tadditionalProperties: {\n\t\t\t\t'anyOf': [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'object',\n\t\t\t\t\t\trequired: ['extensionIdentifier', 'id', 'title'],\n\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\textensionIdentifier: {\n\t\t\t\t\t\t\t\tdescription: localize('terminalProfile.osxExtensionIdentifier', 'The extension that contributed this profile.'),\n\t\t\t\t\t\t\t\ttype: 'string'\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tid: {\n\t\t\t\t\t\t\t\tdescription: localize('terminalProfile.osxExtensionId', 'The id of the extension terminal'),\n\t\t\t\t\t\t\t\ttype: 'string'\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\ttitle: {\n\t\t\t\t\t\t\t\tdescription: localize('terminalProfile.osxExtensionTitle', 'The name of the extension terminal'),\n\t\t\t\t\t\t\t\ttype: 'string'\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t...terminalProfileBaseProperties\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t{ type: 'null' },\n\t\t\t\t\tterminalProfileSchema\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t[TerminalSettingId.ProfilesLinux]: {\n\t\t\trestricted: true,\n\t\t\tmarkdownDescription: createTerminalProfileMarkdownDescription(Platform.Linux),\n\t\t\ttype: 'object',\n\t\t\tdefault: {\n\t\t\t\t'bash': {\n\t\t\t\t\tpath: 'bash',\n\t\t\t\t\ticon: 'terminal-bash'\n\t\t\t\t},\n\t\t\t\t'zsh': {\n\t\t\t\t\tpath: 'zsh'\n\t\t\t\t},\n\t\t\t\t'fish': {\n\t\t\t\t\tpath: 'fish'\n\t\t\t\t},\n\t\t\t\t'tmux': {\n\t\t\t\t\tpath: 'tmux',\n\t\t\t\t\ticon: 'terminal-tmux'\n\t\t\t\t},\n\t\t\t\t'pwsh': {\n\t\t\t\t\tpath: 'pwsh',\n\t\t\t\t\ticon: 'terminal-powershell'\n\t\t\t\t}\n\t\t\t},\n\t\t\tadditionalProperties: {\n\t\t\t\t'anyOf': [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'object',\n\t\t\t\t\t\trequired: ['extensionIdentifier', 'id', 'title'],\n\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\textensionIdentifier: {\n\t\t\t\t\t\t\t\tdescription: localize('terminalProfile.linuxExtensionIdentifier', 'The extension that contributed this profile.'),\n\t\t\t\t\t\t\t\ttype: 'string'\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tid: {\n\t\t\t\t\t\t\t\tdescription: localize('terminalProfile.linuxExtensionId', 'The id of the extension terminal'),\n\t\t\t\t\t\t\t\ttype: 'string'\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\ttitle: {\n\t\t\t\t\t\t\t\tdescription: localize('terminalProfile.linuxExtensionTitle', 'The name of the extension terminal'),\n\t\t\t\t\t\t\t\ttype: 'string'\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t...terminalProfileBaseProperties\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t{ type: 'null' },\n\t\t\t\t\tterminalProfileSchema\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t[TerminalSettingId.UseWslProfiles]: {\n\t\t\tdescription: localize('terminal.integrated.useWslProfiles', 'Controls whether or not WSL distros are shown in the terminal dropdown'),\n\t\t\ttype: 'boolean',\n\t\t\tdefault: true\n\t\t},\n\t\t[TerminalSettingId.InheritEnv]: {\n\t\t\tscope: ConfigurationScope.APPLICATION,\n\t\t\tdescription: localize('terminal.integrated.inheritEnv', \"Whether new shells should inherit their environment from VS Code, which may source a login shell to ensure $PATH and other development variables are initialized. This has no effect on Windows.\"),\n\t\t\ttype: 'boolean',\n\t\t\tdefault: true\n\t\t},\n\t\t[TerminalSettingId.PersistentSessionScrollback]: {\n\t\t\tscope: ConfigurationScope.APPLICATION,\n\t\t\tmarkdownDescription: localize('terminal.integrated.persistentSessionScrollback', \"Controls the maximum amount of lines that will be restored when reconnecting to a persistent terminal session. Increasing this will restore more lines of scrollback at the cost of more memory and increase the time it takes to connect to terminals on start up. This setting requires a restart to take effect and should be set to a value less than or equal to `#terminal.integrated.scrollback#`.\"),\n\t\t\ttype: 'number',\n\t\t\tdefault: 100\n\t\t},\n\t\t[TerminalSettingId.ShowLinkHover]: {\n\t\t\tscope: ConfigurationScope.APPLICATION,\n\t\t\tdescription: localize('terminal.integrated.showLinkHover', \"Whether to show hovers for links in the terminal output.\"),\n\t\t\ttype: 'boolean',\n\t\t\tdefault: true\n\t\t},\n\t\t[TerminalSettingId.IgnoreProcessNames]: {\n\t\t\tmarkdownDescription: localize('terminal.integrated.confirmIgnoreProcesses', \"A set of process names to ignore when using the {0} setting.\", '`#terminal.integrated.confirmOnKill#`'),\n\t\t\ttype: 'array',\n\t\t\titems: {\n\t\t\t\ttype: 'string',\n\t\t\t\tuniqueItems: true\n\t\t\t},\n\t\t\tdefault: [\n\t\t\t\t// Popular prompt programs, these should not count as child processes\n\t\t\t\t'starship',\n\t\t\t\t'oh-my-posh',\n\t\t\t\t// Git bash may runs a subprocess of itself (bin\\bash.exe -> usr\\bin\\bash.exe)\n\t\t\t\t'bash',\n\t\t\t\t'zsh',\n\t\t\t]\n\t\t}\n\t}\n};\n\n/**\n * Registers terminal configurations required by shared process and remote server.\n */\nexport function registerTerminalPlatformConfiguration() {\n\tRegistry.as(Extensions.Configuration).registerConfiguration(terminalPlatformConfiguration);\n\tregisterTerminalDefaultProfileConfiguration();\n}\n\nlet defaultProfilesConfiguration: IConfigurationNode | undefined;\nexport function registerTerminalDefaultProfileConfiguration(detectedProfiles?: { os: OperatingSystem; profiles: ITerminalProfile[] }, extensionContributedProfiles?: readonly IExtensionTerminalProfile[]) {\n\tconst registry = Registry.as(Extensions.Configuration);\n\tlet profileEnum;\n\tif (detectedProfiles) {\n\t\tprofileEnum = createProfileSchemaEnums(detectedProfiles?.profiles, extensionContributedProfiles);\n\t}\n\tconst oldDefaultProfilesConfiguration = defaultProfilesConfiguration;\n\tdefaultProfilesConfiguration = {\n\t\tid: 'terminal',\n\t\torder: 100,\n\t\ttitle: localize('terminalIntegratedConfigurationTitle', \"Integrated Terminal\"),\n\t\ttype: 'object',\n\t\tproperties: {\n\t\t\t[TerminalSettingId.DefaultProfileLinux]: {\n\t\t\t\trestricted: true,\n\t\t\t\tmarkdownDescription: localize('terminal.integrated.defaultProfile.linux', \"The default terminal profile on Linux.\"),\n\t\t\t\ttype: ['string', 'null'],\n\t\t\t\tdefault: null,\n\t\t\t\tenum: detectedProfiles?.os === OperatingSystem.Linux ? profileEnum?.values : undefined,\n\t\t\t\tmarkdownEnumDescriptions: detectedProfiles?.os === OperatingSystem.Linux ? profileEnum?.markdownDescriptions : undefined\n\t\t\t},\n\t\t\t[TerminalSettingId.DefaultProfileMacOs]: {\n\t\t\t\trestricted: true,\n\t\t\t\tmarkdownDescription: localize('terminal.integrated.defaultProfile.osx', \"The default terminal profile on macOS.\"),\n\t\t\t\ttype: ['string', 'null'],\n\t\t\t\tdefault: null,\n\t\t\t\tenum: detectedProfiles?.os === OperatingSystem.Macintosh ? profileEnum?.values : undefined,\n\t\t\t\tmarkdownEnumDescriptions: detectedProfiles?.os === OperatingSystem.Macintosh ? profileEnum?.markdownDescriptions : undefined\n\t\t\t},\n\t\t\t[TerminalSettingId.DefaultProfileWindows]: {\n\t\t\t\trestricted: true,\n\t\t\t\tmarkdownDescription: localize('terminal.integrated.defaultProfile.windows', \"The default terminal profile on Windows.\"),\n\t\t\t\ttype: ['string', 'null'],\n\t\t\t\tdefault: null,\n\t\t\t\tenum: detectedProfiles?.os === OperatingSystem.Windows ? profileEnum?.values : undefined,\n\t\t\t\tmarkdownEnumDescriptions: detectedProfiles?.os === OperatingSystem.Windows ? profileEnum?.markdownDescriptions : undefined\n\t\t\t},\n\t\t}\n\t};\n\tregistry.updateConfigurations({ add: [defaultProfilesConfiguration], remove: oldDefaultProfilesConfiguration ? [oldDefaultProfilesConfiguration] : [] });\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { IPtyHostProcessReplayEvent } from 'vs/platform/terminal/common/capabilities/capabilities';\nimport { ReplayEntry } from 'vs/platform/terminal/common/terminalProcess';\n\nconst enum Constants {\n\tMaxRecorderDataSize = 1024 * 1024 // 1MB\n}\n\ninterface RecorderEntry {\n\tcols: number;\n\trows: number;\n\tdata: string[];\n}\n\nexport interface IRemoteTerminalProcessReplayEvent {\n\tevents: ReplayEntry[];\n}\n\nexport class TerminalRecorder {\n\n\tprivate _entries: RecorderEntry[];\n\tprivate _totalDataLength: number = 0;\n\n\tconstructor(cols: number, rows: number) {\n\t\tthis._entries = [{ cols, rows, data: [] }];\n\t}\n\n\thandleResize(cols: number, rows: number): void {\n\t\tif (this._entries.length > 0) {\n\t\t\tconst lastEntry = this._entries[this._entries.length - 1];\n\t\t\tif (lastEntry.data.length === 0) {\n\t\t\t\t// last entry is just a resize, so just remove it\n\t\t\t\tthis._entries.pop();\n\t\t\t}\n\t\t}\n\n\t\tif (this._entries.length > 0) {\n\t\t\tconst lastEntry = this._entries[this._entries.length - 1];\n\t\t\tif (lastEntry.cols === cols && lastEntry.rows === rows) {\n\t\t\t\t// nothing changed\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (lastEntry.cols === 0 && lastEntry.rows === 0) {\n\t\t\t\t// we finally received a good size!\n\t\t\t\tlastEntry.cols = cols;\n\t\t\t\tlastEntry.rows = rows;\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tthis._entries.push({ cols, rows, data: [] });\n\t}\n\n\thandleData(data: string): void {\n\t\tconst lastEntry = this._entries[this._entries.length - 1];\n\t\tlastEntry.data.push(data);\n\n\t\tthis._totalDataLength += data.length;\n\t\twhile (this._totalDataLength > Constants.MaxRecorderDataSize) {\n\t\t\tconst firstEntry = this._entries[0];\n\t\t\tconst remainingToDelete = this._totalDataLength - Constants.MaxRecorderDataSize;\n\t\t\tif (remainingToDelete >= firstEntry.data[0].length) {\n\t\t\t\t// the first data piece must be deleted\n\t\t\t\tthis._totalDataLength -= firstEntry.data[0].length;\n\t\t\t\tfirstEntry.data.shift();\n\t\t\t\tif (firstEntry.data.length === 0) {\n\t\t\t\t\t// the first entry must be deleted\n\t\t\t\t\tthis._entries.shift();\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// the first data piece must be partially deleted\n\t\t\t\tfirstEntry.data[0] = firstEntry.data[0].substr(remainingToDelete);\n\t\t\t\tthis._totalDataLength -= remainingToDelete;\n\t\t\t}\n\t\t}\n\t}\n\n\tgenerateReplayEventSync(): IPtyHostProcessReplayEvent {\n\t\t// normalize entries to one element per data array\n\t\tthis._entries.forEach((entry) => {\n\t\t\tif (entry.data.length > 0) {\n\t\t\t\tentry.data = [entry.data.join('')];\n\t\t\t}\n\t\t});\n\t\treturn {\n\t\t\tevents: this._entries.map(entry => ({ cols: entry.cols, rows: entry.rows, data: entry.data[0] ?? '' })),\n\t\t\t// No command restoration is needed when relaunching terminals\n\t\t\tcommands: {\n\t\t\t\tisWindowsPty: false,\n\t\t\t\tcommands: []\n\t\t\t}\n\t\t};\n\t}\n\n\tasync generateReplayEvent(): Promise {\n\t\treturn this.generateReplayEventSync();\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (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 ITerminalFormatMessageOptions {\n\t/**\n\t * Whether to exclude the new line at the start of the message. Defaults to false.\n\t */\n\texcludeLeadingNewLine?: boolean;\n\t/**\n\t * Whether to use \"loud\" formatting, this is for more important messages where the it's\n\t * desirable to visually break the buffer up. Defaults to false.\n\t */\n\tloudFormatting?: boolean;\n}\n\n/**\n * Formats a message from the product to be written to the terminal.\n */\nexport function formatMessageForTerminal(message: string, options: ITerminalFormatMessageOptions = {}): string {\n\tlet result = '';\n\tif (!options.excludeLeadingNewLine) {\n\t\tresult += '\\r\\n';\n\t}\n\tresult += '\\x1b[0m\\x1b[7m * ';\n\tif (options.loudFormatting) {\n\t\tresult += '\\x1b[0;104m';\n\t} else {\n\t\tresult += '\\x1b[0m';\n\t}\n\tresult += ` ${message} \\x1b[0m\\n\\r`;\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 { IShellIntegration, ShellIntegrationStatus } from 'vs/platform/terminal/common/terminal';\nimport { Disposable, dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle';\nimport { TerminalCapabilityStore } from 'vs/platform/terminal/common/capabilities/terminalCapabilityStore';\nimport { CommandDetectionCapability } from 'vs/platform/terminal/common/capabilities/commandDetectionCapability';\nimport { CwdDetectionCapability } from 'vs/platform/terminal/common/capabilities/cwdDetectionCapability';\nimport { IBufferMarkCapability, ICommandDetectionCapability, ICwdDetectionCapability, ISerializedCommandDetectionCapability, TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities';\nimport { PartialCommandDetectionCapability } from 'vs/platform/terminal/common/capabilities/partialCommandDetectionCapability';\nimport { ILogService } from 'vs/platform/log/common/log';\n// Importing types is safe in any layer\n// eslint-disable-next-line local/code-import-patterns\nimport { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';\nimport { Emitter } from 'vs/base/common/event';\nimport { BufferMarkCapability } from 'vs/platform/terminal/common/capabilities/bufferMarkCapability';\n// Importing types is safe in any layer\n// eslint-disable-next-line local/code-import-patterns\nimport type { ITerminalAddon, Terminal } from '@xterm/headless';\nimport { URI } from 'vs/base/common/uri';\nimport { sanitizeCwd } from 'vs/platform/terminal/common/terminalEnvironment';\n\n\n/**\n * Shell integration is a feature that enhances the terminal's understanding of what's happening\n * in the shell by injecting special sequences into the shell's prompt using the \"Set Text\n * Parameters\" sequence (`OSC Ps ; Pt ST`).\n *\n * Definitions:\n * - OSC: `\\x1b]`\n * - Ps: A single (usually optional) numeric parameter, composed of one or more digits.\n * - Pt: A text parameter composed of printable characters.\n * - ST: `\\x7`\n *\n * This is inspired by a feature of the same name in the FinalTerm, iTerm2 and kitty terminals.\n */\n\n/**\n * The identifier for the first numeric parameter (`Ps`) for OSC commands used by shell integration.\n */\nconst enum ShellIntegrationOscPs {\n\t/**\n\t * Sequences pioneered by FinalTerm.\n\t */\n\tFinalTerm = 133,\n\t/**\n\t * Sequences pioneered by VS Code. The number is derived from the least significant digit of\n\t * \"VSC\" when encoded in hex (\"VSC\" = 0x56, 0x53, 0x43).\n\t */\n\tVSCode = 633,\n\t/**\n\t * Sequences pioneered by iTerm.\n\t */\n\tITerm = 1337,\n\tSetCwd = 7,\n\tSetWindowsFriendlyCwd = 9\n}\n\n/**\n * VS Code-specific shell integration sequences. Some of these are based on more common alternatives\n * like those pioneered in FinalTerm. The decision to move to entirely custom sequences was to try\n * to improve reliability and prevent the possibility of applications confusing the terminal. If\n * multiple shell integration scripts run, VS Code will prioritize the VS Code-specific ones.\n *\n * It's recommended that authors of shell integration scripts use the common sequences (eg. 133)\n * when building general purpose scripts and the VS Code-specific (633) when targeting only VS Code\n * or when there are no other alternatives.\n */\nconst enum VSCodeOscPt {\n\t/**\n\t * The start of the prompt, this is expected to always appear at the start of a line.\n\t * Based on FinalTerm's `OSC 133 ; A ST`.\n\t */\n\tPromptStart = 'A',\n\n\t/**\n\t * The start of a command, ie. where the user inputs their command.\n\t * Based on FinalTerm's `OSC 133 ; B ST`.\n\t */\n\tCommandStart = 'B',\n\n\t/**\n\t * Sent just before the command output begins.\n\t * Based on FinalTerm's `OSC 133 ; C ST`.\n\t */\n\tCommandExecuted = 'C',\n\n\t/**\n\t * Sent just after a command has finished. The exit code is optional, when not specified it\n\t * means no command was run (ie. enter on empty prompt or ctrl+c).\n\t * Based on FinalTerm's `OSC 133 ; D [; ] ST`.\n\t */\n\tCommandFinished = 'D',\n\n\t/**\n\t * Explicitly set the command line. This helps workaround performance and reliability problems\n\t * with parsing out the command, such as conpty not guaranteeing the position of the sequence or\n\t * the shell not guaranteeing that the entire command is even visible.\n\t *\n\t * The command line can escape ascii characters using the `\\xAB` format, where AB are the\n\t * hexadecimal representation of the character code (case insensitive), and escape the `\\`\n\t * character using `\\\\`. It's required to escape semi-colon (`0x3b`) and characters 0x20 and\n\t * below, this is particularly important for new line and semi-colon.\n\t *\n\t * Some examples:\n\t *\n\t * ```\n\t * \"\\\" -> \"\\\\\"\n\t * \"\\n\" -> \"\\x0a\"\n\t * \";\" -> \"\\x3b\"\n\t * ```\n\t *\n\t * An optional nonce can be provided which is may be required by the terminal in order enable\n\t * some features. This helps ensure no malicious command injection has occurred.\n\t *\n\t * Format: `OSC 633 ; E [; [; ]] ST`.\n\t */\n\tCommandLine = 'E',\n\n\t/**\n\t * Similar to prompt start but for line continuations.\n\t *\n\t * WARNING: This sequence is unfinalized, DO NOT use this in your shell integration script.\n\t */\n\tContinuationStart = 'F',\n\n\t/**\n\t * Similar to command start but for line continuations.\n\t *\n\t * WARNING: This sequence is unfinalized, DO NOT use this in your shell integration script.\n\t */\n\tContinuationEnd = 'G',\n\n\t/**\n\t * The start of the right prompt.\n\t *\n\t * WARNING: This sequence is unfinalized, DO NOT use this in your shell integration script.\n\t */\n\tRightPromptStart = 'H',\n\n\t/**\n\t * The end of the right prompt.\n\t *\n\t * WARNING: This sequence is unfinalized, DO NOT use this in your shell integration script.\n\t */\n\tRightPromptEnd = 'I',\n\n\t/**\n\t * Set an arbitrary property: `OSC 633 ; P ; = ST`, only known properties will\n\t * be handled.\n\t *\n\t * Known properties:\n\t *\n\t * - `Cwd` - Reports the current working directory to the terminal.\n\t * - `IsWindows` - Indicates whether the terminal is using a Windows backend like winpty or\n\t * conpty. This may be used to enable additional heuristics as the positioning of the shell\n\t * integration sequences are not guaranteed to be correct. Valid values: `True`, `False`.\n\t *\n\t * WARNING: Any other properties may be changed and are not guaranteed to work in the future.\n\t */\n\tProperty = 'P',\n\n\t/**\n\t * Sets a mark/point-of-interest in the buffer. `OSC 633 ; SetMark [; Id=] [; Hidden]`\n\t * `Id` - The identifier of the mark that can be used to reference it\n\t * `Hidden` - When set, the mark will be available to reference internally but will not visible\n\t *\n\t * WARNING: This sequence is unfinalized, DO NOT use this in your shell integration script.\n\t */\n\tSetMark = 'SetMark',\n}\n\n/**\n * ITerm sequences\n */\nconst enum ITermOscPt {\n\t/**\n\t * Sets a mark/point-of-interest in the buffer. `OSC 1337 ; SetMark`\n\t */\n\tSetMark = 'SetMark',\n\n\t/**\n\t * Reports current working directory (CWD). `OSC 1337 ; CurrentDir= ST`\n\t */\n\tCurrentDir = 'CurrentDir'\n}\n\n/**\n * The shell integration addon extends xterm by reading shell integration sequences and creating\n * capabilities and passing along relevant sequences to the capabilities. This is meant to\n * encapsulate all handling/parsing of sequences so the capabilities don't need to.\n */\nexport class ShellIntegrationAddon extends Disposable implements IShellIntegration, ITerminalAddon {\n\tprivate _terminal?: Terminal;\n\treadonly capabilities = this._register(new TerminalCapabilityStore());\n\tprivate _hasUpdatedTelemetry: boolean = false;\n\tprivate _activationTimeout: any;\n\tprivate _commonProtocolDisposables: IDisposable[] = [];\n\tprivate _status: ShellIntegrationStatus = ShellIntegrationStatus.Off;\n\n\tget status(): ShellIntegrationStatus { return this._status; }\n\n\tprivate readonly _onDidChangeStatus = new Emitter();\n\treadonly onDidChangeStatus = this._onDidChangeStatus.event;\n\n\tconstructor(\n\t\tprivate _nonce: string,\n\t\tprivate readonly _disableTelemetry: boolean | undefined,\n\t\tprivate readonly _telemetryService: ITelemetryService | undefined,\n\t\tprivate readonly _logService: ILogService\n\t) {\n\t\tsuper();\n\t\tthis._register(toDisposable(() => {\n\t\t\tthis._clearActivationTimeout();\n\t\t\tthis._disposeCommonProtocol();\n\t\t}));\n\t}\n\n\tprivate _disposeCommonProtocol(): void {\n\t\tdispose(this._commonProtocolDisposables);\n\t\tthis._commonProtocolDisposables.length = 0;\n\t}\n\n\tactivate(xterm: Terminal) {\n\t\tthis._terminal = xterm;\n\t\tthis.capabilities.add(TerminalCapability.PartialCommandDetection, this._register(new PartialCommandDetectionCapability(this._terminal)));\n\t\tthis._register(xterm.parser.registerOscHandler(ShellIntegrationOscPs.VSCode, data => this._handleVSCodeSequence(data)));\n\t\tthis._register(xterm.parser.registerOscHandler(ShellIntegrationOscPs.ITerm, data => this._doHandleITermSequence(data)));\n\t\tthis._commonProtocolDisposables.push(\n\t\t\txterm.parser.registerOscHandler(ShellIntegrationOscPs.FinalTerm, data => this._handleFinalTermSequence(data))\n\t\t);\n\t\tthis._register(xterm.parser.registerOscHandler(ShellIntegrationOscPs.SetCwd, data => this._doHandleSetCwd(data)));\n\t\tthis._register(xterm.parser.registerOscHandler(ShellIntegrationOscPs.SetWindowsFriendlyCwd, data => this._doHandleSetWindowsFriendlyCwd(data)));\n\t\tthis._ensureCapabilitiesOrAddFailureTelemetry();\n\t}\n\n\tgetMarkerId(terminal: Terminal, vscodeMarkerId: string) {\n\t\tthis._createOrGetBufferMarkDetection(terminal).getMark(vscodeMarkerId);\n\t}\n\n\tprivate _handleFinalTermSequence(data: string): boolean {\n\t\tconst didHandle = this._doHandleFinalTermSequence(data);\n\t\tif (this._status === ShellIntegrationStatus.Off) {\n\t\t\tthis._status = ShellIntegrationStatus.FinalTerm;\n\t\t\tthis._onDidChangeStatus.fire(this._status);\n\t\t}\n\t\treturn didHandle;\n\t}\n\n\tprivate _doHandleFinalTermSequence(data: string): boolean {\n\t\tif (!this._terminal) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Pass the sequence along to the capability\n\t\t// It was considered to disable the common protocol in order to not confuse the VS Code\n\t\t// shell integration if both happen for some reason. This doesn't work for powerlevel10k\n\t\t// when instant prompt is enabled though. If this does end up being a problem we could pass\n\t\t// a type flag through the capability calls\n\t\tconst [command, ...args] = data.split(';');\n\t\tswitch (command) {\n\t\t\tcase 'A':\n\t\t\t\tthis._createOrGetCommandDetection(this._terminal).handlePromptStart();\n\t\t\t\treturn true;\n\t\t\tcase 'B':\n\t\t\t\t// Ignore the command line for these sequences as it's unreliable for example in powerlevel10k\n\t\t\t\tthis._createOrGetCommandDetection(this._terminal).handleCommandStart({ ignoreCommandLine: true });\n\t\t\t\treturn true;\n\t\t\tcase 'C':\n\t\t\t\tthis._createOrGetCommandDetection(this._terminal).handleCommandExecuted();\n\t\t\t\treturn true;\n\t\t\tcase 'D': {\n\t\t\t\tconst exitCode = args.length === 1 ? parseInt(args[0]) : undefined;\n\t\t\t\tthis._createOrGetCommandDetection(this._terminal).handleCommandFinished(exitCode);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate _handleVSCodeSequence(data: string): boolean {\n\t\tconst didHandle = this._doHandleVSCodeSequence(data);\n\t\tif (!this._hasUpdatedTelemetry && didHandle) {\n\t\t\tthis._telemetryService?.publicLog2<{}, { owner: 'meganrogge'; comment: 'Indicates shell integration was activated' }>('terminal/shellIntegrationActivationSucceeded');\n\t\t\tthis._hasUpdatedTelemetry = true;\n\t\t\tthis._clearActivationTimeout();\n\t\t}\n\t\tif (this._status !== ShellIntegrationStatus.VSCode) {\n\t\t\tthis._status = ShellIntegrationStatus.VSCode;\n\t\t\tthis._onDidChangeStatus.fire(this._status);\n\t\t}\n\t\treturn didHandle;\n\t}\n\n\tprivate async _ensureCapabilitiesOrAddFailureTelemetry(): Promise {\n\t\tif (!this._telemetryService || this._disableTelemetry) {\n\t\t\treturn;\n\t\t}\n\t\tthis._activationTimeout = setTimeout(() => {\n\t\t\tif (!this.capabilities.get(TerminalCapability.CommandDetection) && !this.capabilities.get(TerminalCapability.CwdDetection)) {\n\t\t\t\tthis._telemetryService?.publicLog2<{ classification: 'SystemMetaData'; purpose: 'FeatureInsight' }>('terminal/shellIntegrationActivationTimeout');\n\t\t\t\tthis._logService.warn('Shell integration failed to add capabilities within 10 seconds');\n\t\t\t}\n\t\t\tthis._hasUpdatedTelemetry = true;\n\t\t}, 10000);\n\t}\n\n\tprivate _clearActivationTimeout(): void {\n\t\tif (this._activationTimeout !== undefined) {\n\t\t\tclearTimeout(this._activationTimeout);\n\t\t\tthis._activationTimeout = undefined;\n\t\t}\n\t}\n\n\tprivate _doHandleVSCodeSequence(data: string): boolean {\n\t\tif (!this._terminal) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Pass the sequence along to the capability\n\t\tconst argsIndex = data.indexOf(';');\n\t\tconst sequenceCommand = argsIndex === -1 ? data : data.substring(0, argsIndex);\n\t\t// Cast to strict checked index access\n\t\tconst args: (string | undefined)[] = argsIndex === -1 ? [] : data.substring(argsIndex + 1).split(';');\n\t\tswitch (sequenceCommand) {\n\t\t\tcase VSCodeOscPt.PromptStart:\n\t\t\t\tthis._createOrGetCommandDetection(this._terminal).handlePromptStart();\n\t\t\t\treturn true;\n\t\t\tcase VSCodeOscPt.CommandStart:\n\t\t\t\tthis._createOrGetCommandDetection(this._terminal).handleCommandStart();\n\t\t\t\treturn true;\n\t\t\tcase VSCodeOscPt.CommandExecuted:\n\t\t\t\tthis._createOrGetCommandDetection(this._terminal).handleCommandExecuted();\n\t\t\t\treturn true;\n\t\t\tcase VSCodeOscPt.CommandFinished: {\n\t\t\t\tconst arg0 = args[0];\n\t\t\t\tconst exitCode = arg0 !== undefined ? parseInt(arg0) : undefined;\n\t\t\t\tthis._createOrGetCommandDetection(this._terminal).handleCommandFinished(exitCode);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tcase VSCodeOscPt.CommandLine: {\n\t\t\t\tconst arg0 = args[0];\n\t\t\t\tconst arg1 = args[1];\n\t\t\t\tlet commandLine: string;\n\t\t\t\tif (arg0 !== undefined) {\n\t\t\t\t\tcommandLine = deserializeMessage(arg0);\n\t\t\t\t} else {\n\t\t\t\t\tcommandLine = '';\n\t\t\t\t}\n\t\t\t\tthis._createOrGetCommandDetection(this._terminal).setCommandLine(commandLine, arg1 === this._nonce);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tcase VSCodeOscPt.ContinuationStart: {\n\t\t\t\tthis._createOrGetCommandDetection(this._terminal).handleContinuationStart();\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tcase VSCodeOscPt.ContinuationEnd: {\n\t\t\t\tthis._createOrGetCommandDetection(this._terminal).handleContinuationEnd();\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tcase VSCodeOscPt.RightPromptStart: {\n\t\t\t\tthis._createOrGetCommandDetection(this._terminal).handleRightPromptStart();\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tcase VSCodeOscPt.RightPromptEnd: {\n\t\t\t\tthis._createOrGetCommandDetection(this._terminal).handleRightPromptEnd();\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tcase VSCodeOscPt.Property: {\n\t\t\t\tconst arg0 = args[0];\n\t\t\t\tconst deserialized = arg0 !== undefined ? deserializeMessage(arg0) : '';\n\t\t\t\tconst { key, value } = parseKeyValueAssignment(deserialized);\n\t\t\t\tif (value === undefined) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tswitch (key) {\n\t\t\t\t\tcase 'Cwd': {\n\t\t\t\t\t\tthis._updateCwd(value);\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t\tcase 'IsWindows': {\n\t\t\t\t\t\tthis._createOrGetCommandDetection(this._terminal).setIsWindowsPty(value === 'True' ? true : false);\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t\tcase 'Task': {\n\t\t\t\t\t\tthis._createOrGetBufferMarkDetection(this._terminal);\n\t\t\t\t\t\tthis.capabilities.get(TerminalCapability.CommandDetection)?.setIsCommandStorageDisabled();\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcase VSCodeOscPt.SetMark: {\n\t\t\t\tthis._createOrGetBufferMarkDetection(this._terminal).addMark(parseMarkSequence(args));\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\t// Unrecognized sequence\n\t\treturn false;\n\t}\n\n\tprivate _updateCwd(value: string) {\n\t\tvalue = sanitizeCwd(value);\n\t\tthis._createOrGetCwdDetection().updateCwd(value);\n\t\tconst commandDetection = this.capabilities.get(TerminalCapability.CommandDetection);\n\t\tcommandDetection?.setCwd(value);\n\t}\n\n\tprivate _doHandleITermSequence(data: string): boolean {\n\t\tif (!this._terminal) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst [command] = data.split(';');\n\t\tswitch (command) {\n\t\t\tcase ITermOscPt.SetMark: {\n\t\t\t\tthis._createOrGetBufferMarkDetection(this._terminal).addMark();\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\t// Checking for known `=` pairs.\n\t\t\t\t// Note that unlike `VSCodeOscPt.Property`, iTerm2 does not interpret backslash or hex-escape sequences.\n\t\t\t\t// See: https://github.com/gnachman/iTerm2/blob/bb0882332cec5196e4de4a4225978d746e935279/sources/VT100Terminal.m#L2089-L2105\n\t\t\t\tconst { key, value } = parseKeyValueAssignment(command);\n\n\t\t\t\tif (value === undefined) {\n\t\t\t\t\t// No '=' was found, so it's not a property assignment.\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tswitch (key) {\n\t\t\t\t\tcase ITermOscPt.CurrentDir:\n\t\t\t\t\t\t// Encountered: `OSC 1337 ; CurrentDir= ST`\n\t\t\t\t\t\tthis._updateCwd(value);\n\t\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Unrecognized sequence\n\t\treturn false;\n\t}\n\n\tprivate _doHandleSetWindowsFriendlyCwd(data: string): boolean {\n\t\tif (!this._terminal) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst [command, ...args] = data.split(';');\n\t\tswitch (command) {\n\t\t\tcase '9':\n\t\t\t\t// Encountered `OSC 9 ; 9 ; ST`\n\t\t\t\tif (args.length) {\n\t\t\t\t\tthis._updateCwd(args[0]);\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t}\n\n\t\t// Unrecognized sequence\n\t\treturn false;\n\t}\n\n\t/**\n\t * Handles the sequence: `OSC 7 ; scheme://cwd ST`\n\t */\n\tprivate _doHandleSetCwd(data: string): boolean {\n\t\tif (!this._terminal) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst [command] = data.split(';');\n\n\t\tif (command.match(/^file:\\/\\/.*\\//)) {\n\t\t\tconst uri = URI.parse(command);\n\t\t\tif (uri.path && uri.path.length > 0) {\n\t\t\t\tthis._updateCwd(uri.path);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\t// Unrecognized sequence\n\t\treturn false;\n\t}\n\n\tserialize(): ISerializedCommandDetectionCapability {\n\t\tif (!this._terminal || !this.capabilities.has(TerminalCapability.CommandDetection)) {\n\t\t\treturn {\n\t\t\t\tisWindowsPty: false,\n\t\t\t\tcommands: []\n\t\t\t};\n\t\t}\n\t\tconst result = this._createOrGetCommandDetection(this._terminal).serialize();\n\t\treturn result;\n\t}\n\n\tdeserialize(serialized: ISerializedCommandDetectionCapability): void {\n\t\tif (!this._terminal) {\n\t\t\tthrow new Error('Cannot restore commands before addon is activated');\n\t\t}\n\t\tthis._createOrGetCommandDetection(this._terminal).deserialize(serialized);\n\t}\n\n\tprotected _createOrGetCwdDetection(): ICwdDetectionCapability {\n\t\tlet cwdDetection = this.capabilities.get(TerminalCapability.CwdDetection);\n\t\tif (!cwdDetection) {\n\t\t\tcwdDetection = this._register(new CwdDetectionCapability());\n\t\t\tthis.capabilities.add(TerminalCapability.CwdDetection, cwdDetection);\n\t\t}\n\t\treturn cwdDetection;\n\t}\n\n\tprotected _createOrGetCommandDetection(terminal: Terminal): ICommandDetectionCapability {\n\t\tlet commandDetection = this.capabilities.get(TerminalCapability.CommandDetection);\n\t\tif (!commandDetection) {\n\t\t\tcommandDetection = this._register(new CommandDetectionCapability(terminal, this._logService));\n\t\t\tthis.capabilities.add(TerminalCapability.CommandDetection, commandDetection);\n\t\t}\n\t\treturn commandDetection;\n\t}\n\n\tprotected _createOrGetBufferMarkDetection(terminal: Terminal): IBufferMarkCapability {\n\t\tlet bufferMarkDetection = this.capabilities.get(TerminalCapability.BufferMarkDetection);\n\t\tif (!bufferMarkDetection) {\n\t\t\tbufferMarkDetection = this._register(new BufferMarkCapability(terminal));\n\t\t\tthis.capabilities.add(TerminalCapability.BufferMarkDetection, bufferMarkDetection);\n\t\t}\n\t\treturn bufferMarkDetection;\n\t}\n}\n\nexport function deserializeMessage(message: string): string {\n\treturn message.replaceAll(\n\t\t// Backslash ('\\') followed by an escape operator: either another '\\', or 'x' and two hex chars.\n\t\t/\\\\(\\\\|x([0-9a-f]{2}))/gi,\n\t\t// If it's a hex value, parse it to a character.\n\t\t// Otherwise the operator is '\\', which we return literally, now unescaped.\n\t\t(_match: string, op: string, hex?: string) => hex ? String.fromCharCode(parseInt(hex, 16)) : op);\n}\n\nexport function parseKeyValueAssignment(message: string): { key: string; value: string | undefined } {\n\tconst separatorIndex = message.indexOf('=');\n\tif (separatorIndex === -1) {\n\t\treturn { key: message, value: undefined }; // No '=' was found.\n\t}\n\treturn {\n\t\tkey: message.substring(0, separatorIndex),\n\t\tvalue: message.substring(1 + separatorIndex)\n\t};\n}\n\n\nexport function parseMarkSequence(sequence: (string | undefined)[]): { id?: string; hidden?: boolean } {\n\tlet id = undefined;\n\tlet hidden = false;\n\tfor (const property of sequence) {\n\t\t// Sanity check, this shouldn't happen in practice\n\t\tif (property === undefined) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (property === 'Hidden') {\n\t\t\thidden = true;\n\t\t}\n\t\tif (property.startsWith('Id=')) {\n\t\t\tid = property.substring(3);\n\t\t}\n\t}\n\treturn { id, hidden };\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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, RGBA } from 'vs/base/common/color';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { IJSONSchema, IJSONSchemaMap } from 'vs/base/common/jsonSchema';\nimport * as nls from 'vs/nls';\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\treadonly onDidChangeSchema: Event;\n\n\t/**\n\t * Register a color to the registry.\n\t * @param id The color id as used in theme description files\n\t * @param defaults The default values\n\t * @param needsTransparency Whether the color requires transparency\n\t * @description the description\n\t */\n\tregisterColor(id: string, defaults: ColorDefaults, description: string, needsTransparency?: boolean): ColorIdentifier;\n\n\t/**\n\t * Register a color to the registry.\n\t */\n\tderegisterColor(id: string): void;\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\t/**\n\t * JSON schema for an object to assign color values to one of the color contributions.\n\t */\n\tgetColorSchema(): IJSONSchema;\n\n\t/**\n\t * JSON schema to for a reference to a color contribution.\n\t */\n\tgetColorReferenceSchema(): IJSONSchema;\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\n\tpublic deregisterColor(id: string): void {\n\t\tdelete this.colorsById[id];\n\t\tdelete this.colorSchema.properties[id];\n\t\tconst index = this.colorReferenceSchema.enum.indexOf(id);\n\t\tif (index !== -1) {\n\t\t\tthis.colorReferenceSchema.enum.splice(index, 1);\n\t\t\tthis.colorReferenceSchema.enumDescriptions.splice(index, 1);\n\t\t}\n\t\tthis._onDidChangeSchema.fire();\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 getColorReferenceSchema(): IJSONSchema {\n\t\treturn this.colorReferenceSchema;\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\nexport function getColorRegistry(): IColorRegistry {\n\treturn colorRegistry;\n}\n\n// ----- base colors\n\nexport const foreground = registerColor('foreground', { dark: '#CCCCCC', light: '#616161', hcDark: '#FFFFFF', hcLight: '#292929' }, nls.localize('foreground', \"Overall foreground color. This color is only used if not overridden by a component.\"));\nexport const disabledForeground = registerColor('disabledForeground', { dark: '#CCCCCC80', light: '#61616180', hcDark: '#A5A5A5', hcLight: '#7F7F7F' }, nls.localize('disabledForeground', \"Overall foreground for disabled elements. This color is only used if not overridden by a component.\"));\nexport const errorForeground = registerColor('errorForeground', { dark: '#F48771', light: '#A1260D', hcDark: '#F48771', hcLight: '#B5200D' }, nls.localize('errorForeground', \"Overall foreground color for error messages. This color is only used if not overridden by a component.\"));\nexport const descriptionForeground = registerColor('descriptionForeground', { light: '#717171', dark: transparent(foreground, 0.7), hcDark: transparent(foreground, 0.7), hcLight: transparent(foreground, 0.7) }, nls.localize('descriptionForeground', \"Foreground color for description text providing additional information, for example for a label.\"));\nexport const iconForeground = registerColor('icon.foreground', { dark: '#C5C5C5', light: '#424242', hcDark: '#FFFFFF', hcLight: '#292929' }, nls.localize('iconForeground', \"The default color for icons in the workbench.\"));\n\nexport const focusBorder = registerColor('focusBorder', { dark: '#007FD4', light: '#0090F1', hcDark: '#F38518', hcLight: '#006BBD' }, nls.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', { light: null, dark: null, hcDark: '#6FC3DF', hcLight: '#0F4A85' }, nls.localize('contrastBorder', \"An extra border around elements to separate them from others for greater contrast.\"));\nexport const activeContrastBorder = registerColor('contrastActiveBorder', { light: null, dark: null, hcDark: focusBorder, hcLight: focusBorder }, nls.localize('activeContrastBorder', \"An extra border around active elements to separate them from others for greater contrast.\"));\n\nexport const selectionBackground = registerColor('selection.background', { light: null, dark: null, hcDark: null, hcLight: null }, nls.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// ------ text colors\n\nexport const textSeparatorForeground = registerColor('textSeparator.foreground', { light: '#0000002e', dark: '#ffffff2e', hcDark: Color.black, hcLight: '#292929' }, nls.localize('textSeparatorForeground', \"Color for text separators.\"));\n\nexport const textLinkForeground = registerColor('textLink.foreground', { light: '#006AB1', dark: '#3794FF', hcDark: '#21A6FF', hcLight: '#0F4A85' }, nls.localize('textLinkForeground', \"Foreground color for links in text.\"));\nexport const textLinkActiveForeground = registerColor('textLink.activeForeground', { light: '#006AB1', dark: '#3794FF', hcDark: '#21A6FF', hcLight: '#0F4A85' }, nls.localize('textLinkActiveForeground', \"Foreground color for links in text when clicked on and on mouse hover.\"));\n\nexport const textPreformatForeground = registerColor('textPreformat.foreground', { light: '#A31515', dark: '#D7BA7D', hcDark: '#000000', hcLight: '#FFFFFF' }, nls.localize('textPreformatForeground', \"Foreground color for preformatted text segments.\"));\nexport const textPreformatBackground = registerColor('textPreformat.background', { light: '#0000001A', dark: '#FFFFFF1A', hcDark: '#FFFFFF', hcLight: '#09345f' }, nls.localize('textPreformatBackground', \"Background color for preformatted text segments.\"));\nexport const textBlockQuoteBackground = registerColor('textBlockQuote.background', { light: '#f2f2f2', dark: '#222222', hcDark: null, hcLight: '#F2F2F2' }, nls.localize('textBlockQuoteBackground', \"Background color for block quotes in text.\"));\nexport const textBlockQuoteBorder = registerColor('textBlockQuote.border', { light: '#007acc80', dark: '#007acc80', hcDark: Color.white, hcLight: '#292929' }, nls.localize('textBlockQuoteBorder', \"Border color for block quotes in text.\"));\nexport const textCodeBlockBackground = registerColor('textCodeBlock.background', { light: '#dcdcdc66', dark: '#0a0a0a66', hcDark: Color.black, hcLight: '#F2F2F2' }, nls.localize('textCodeBlockBackground', \"Background color for code blocks in text.\"));\n\n// ----- widgets\nexport const widgetShadow = registerColor('widget.shadow', { dark: transparent(Color.black, .36), light: transparent(Color.black, .16), hcDark: null, hcLight: null }, nls.localize('widgetShadow', 'Shadow color of widgets such as find/replace inside the editor.'));\nexport const widgetBorder = registerColor('widget.border', { dark: null, light: null, hcDark: contrastBorder, hcLight: contrastBorder }, nls.localize('widgetBorder', 'Border color of widgets such as find/replace inside the editor.'));\n\nexport const inputBackground = registerColor('input.background', { dark: '#3C3C3C', light: Color.white, hcDark: Color.black, hcLight: Color.white }, nls.localize('inputBoxBackground', \"Input box background.\"));\nexport const inputForeground = registerColor('input.foreground', { dark: foreground, light: foreground, hcDark: foreground, hcLight: foreground }, nls.localize('inputBoxForeground', \"Input box foreground.\"));\nexport const inputBorder = registerColor('input.border', { dark: null, light: null, hcDark: contrastBorder, hcLight: contrastBorder }, nls.localize('inputBoxBorder', \"Input box border.\"));\nexport const inputActiveOptionBorder = registerColor('inputOption.activeBorder', { dark: '#007ACC', light: '#007ACC', hcDark: contrastBorder, hcLight: contrastBorder }, nls.localize('inputBoxActiveOptionBorder', \"Border color of activated options in input fields.\"));\nexport const inputActiveOptionHoverBackground = registerColor('inputOption.hoverBackground', { dark: '#5a5d5e80', light: '#b8b8b850', hcDark: null, hcLight: null }, nls.localize('inputOption.hoverBackground', \"Background color of activated options in input fields.\"));\nexport const inputActiveOptionBackground = registerColor('inputOption.activeBackground', { dark: transparent(focusBorder, 0.4), light: transparent(focusBorder, 0.2), hcDark: Color.transparent, hcLight: Color.transparent }, nls.localize('inputOption.activeBackground', \"Background hover color of options in input fields.\"));\nexport const inputActiveOptionForeground = registerColor('inputOption.activeForeground', { dark: Color.white, light: Color.black, hcDark: foreground, hcLight: foreground }, nls.localize('inputOption.activeForeground', \"Foreground color of activated options in input fields.\"));\nexport const inputPlaceholderForeground = registerColor('input.placeholderForeground', { light: transparent(foreground, 0.5), dark: transparent(foreground, 0.5), hcDark: transparent(foreground, 0.7), hcLight: transparent(foreground, 0.7) }, nls.localize('inputPlaceholderForeground', \"Input box foreground color for placeholder text.\"));\n\nexport const inputValidationInfoBackground = registerColor('inputValidation.infoBackground', { dark: '#063B49', light: '#D6ECF2', hcDark: Color.black, hcLight: Color.white }, nls.localize('inputValidationInfoBackground', \"Input validation background color for information severity.\"));\nexport const inputValidationInfoForeground = registerColor('inputValidation.infoForeground', { dark: null, light: null, hcDark: null, hcLight: foreground }, nls.localize('inputValidationInfoForeground', \"Input validation foreground color for information severity.\"));\nexport const inputValidationInfoBorder = registerColor('inputValidation.infoBorder', { dark: '#007acc', light: '#007acc', hcDark: contrastBorder, hcLight: contrastBorder }, nls.localize('inputValidationInfoBorder', \"Input validation border color for information severity.\"));\nexport const inputValidationWarningBackground = registerColor('inputValidation.warningBackground', { dark: '#352A05', light: '#F6F5D2', hcDark: Color.black, hcLight: Color.white }, nls.localize('inputValidationWarningBackground', \"Input validation background color for warning severity.\"));\nexport const inputValidationWarningForeground = registerColor('inputValidation.warningForeground', { dark: null, light: null, hcDark: null, hcLight: foreground }, nls.localize('inputValidationWarningForeground', \"Input validation foreground color for warning severity.\"));\nexport const inputValidationWarningBorder = registerColor('inputValidation.warningBorder', { dark: '#B89500', light: '#B89500', hcDark: contrastBorder, hcLight: contrastBorder }, nls.localize('inputValidationWarningBorder', \"Input validation border color for warning severity.\"));\nexport const inputValidationErrorBackground = registerColor('inputValidation.errorBackground', { dark: '#5A1D1D', light: '#F2DEDE', hcDark: Color.black, hcLight: Color.white }, nls.localize('inputValidationErrorBackground', \"Input validation background color for error severity.\"));\nexport const inputValidationErrorForeground = registerColor('inputValidation.errorForeground', { dark: null, light: null, hcDark: null, hcLight: foreground }, nls.localize('inputValidationErrorForeground', \"Input validation foreground color for error severity.\"));\nexport const inputValidationErrorBorder = registerColor('inputValidation.errorBorder', { dark: '#BE1100', light: '#BE1100', hcDark: contrastBorder, hcLight: contrastBorder }, nls.localize('inputValidationErrorBorder', \"Input validation border color for error severity.\"));\n\nexport const selectBackground = registerColor('dropdown.background', { dark: '#3C3C3C', light: Color.white, hcDark: Color.black, hcLight: Color.white }, nls.localize('dropdownBackground', \"Dropdown background.\"));\nexport const selectListBackground = registerColor('dropdown.listBackground', { dark: null, light: null, hcDark: Color.black, hcLight: Color.white }, nls.localize('dropdownListBackground', \"Dropdown list background.\"));\nexport const selectForeground = registerColor('dropdown.foreground', { dark: '#F0F0F0', light: foreground, hcDark: Color.white, hcLight: foreground }, nls.localize('dropdownForeground', \"Dropdown foreground.\"));\nexport const selectBorder = registerColor('dropdown.border', { dark: selectBackground, light: '#CECECE', hcDark: contrastBorder, hcLight: contrastBorder }, nls.localize('dropdownBorder', \"Dropdown border.\"));\n\nexport const buttonForeground = registerColor('button.foreground', { dark: Color.white, light: Color.white, hcDark: Color.white, hcLight: Color.white }, nls.localize('buttonForeground', \"Button foreground color.\"));\nexport const buttonSeparator = registerColor('button.separator', { dark: transparent(buttonForeground, .4), light: transparent(buttonForeground, .4), hcDark: transparent(buttonForeground, .4), hcLight: transparent(buttonForeground, .4) }, nls.localize('buttonSeparator', \"Button separator color.\"));\nexport const buttonBackground = registerColor('button.background', { dark: '#0E639C', light: '#007ACC', hcDark: null, hcLight: '#0F4A85' }, nls.localize('buttonBackground', \"Button background color.\"));\nexport const buttonHoverBackground = registerColor('button.hoverBackground', { dark: lighten(buttonBackground, 0.2), light: darken(buttonBackground, 0.2), hcDark: buttonBackground, hcLight: buttonBackground }, nls.localize('buttonHoverBackground', \"Button background color when hovering.\"));\nexport const buttonBorder = registerColor('button.border', { dark: contrastBorder, light: contrastBorder, hcDark: contrastBorder, hcLight: contrastBorder }, nls.localize('buttonBorder', \"Button border color.\"));\n\nexport const buttonSecondaryForeground = registerColor('button.secondaryForeground', { dark: Color.white, light: Color.white, hcDark: Color.white, hcLight: foreground }, nls.localize('buttonSecondaryForeground', \"Secondary button foreground color.\"));\nexport const buttonSecondaryBackground = registerColor('button.secondaryBackground', { dark: '#3A3D41', light: '#5F6A79', hcDark: null, hcLight: Color.white }, nls.localize('buttonSecondaryBackground', \"Secondary button background color.\"));\nexport const buttonSecondaryHoverBackground = registerColor('button.secondaryHoverBackground', { dark: lighten(buttonSecondaryBackground, 0.2), light: darken(buttonSecondaryBackground, 0.2), hcDark: null, hcLight: null }, nls.localize('buttonSecondaryHoverBackground', \"Secondary button background color when hovering.\"));\n\nexport const badgeBackground = registerColor('badge.background', { dark: '#4D4D4D', light: '#C4C4C4', hcDark: Color.black, hcLight: '#0F4A85' }, nls.localize('badgeBackground', \"Badge background color. Badges are small information labels, e.g. for search results count.\"));\nexport const badgeForeground = registerColor('badge.foreground', { dark: Color.white, light: '#333', hcDark: Color.white, hcLight: Color.white }, nls.localize('badgeForeground', \"Badge foreground color. Badges are small information labels, e.g. for search results count.\"));\n\nexport const scrollbarShadow = registerColor('scrollbar.shadow', { dark: '#000000', light: '#DDDDDD', hcDark: null, hcLight: null }, nls.localize('scrollbarShadow', \"Scrollbar shadow to indicate that the view is scrolled.\"));\nexport const scrollbarSliderBackground = registerColor('scrollbarSlider.background', { dark: Color.fromHex('#797979').transparent(0.4), light: Color.fromHex('#646464').transparent(0.4), hcDark: transparent(contrastBorder, 0.6), hcLight: transparent(contrastBorder, 0.4) }, nls.localize('scrollbarSliderBackground', \"Scrollbar slider background color.\"));\nexport const scrollbarSliderHoverBackground = registerColor('scrollbarSlider.hoverBackground', { dark: Color.fromHex('#646464').transparent(0.7), light: Color.fromHex('#646464').transparent(0.7), hcDark: transparent(contrastBorder, 0.8), hcLight: transparent(contrastBorder, 0.8) }, nls.localize('scrollbarSliderHoverBackground', \"Scrollbar slider background color when hovering.\"));\nexport const scrollbarSliderActiveBackground = registerColor('scrollbarSlider.activeBackground', { dark: Color.fromHex('#BFBFBF').transparent(0.4), light: Color.fromHex('#000000').transparent(0.6), hcDark: contrastBorder, hcLight: contrastBorder }, nls.localize('scrollbarSliderActiveBackground', \"Scrollbar slider background color when clicked on.\"));\n\nexport const progressBarBackground = registerColor('progressBar.background', { dark: Color.fromHex('#0E70C0'), light: Color.fromHex('#0E70C0'), hcDark: contrastBorder, hcLight: contrastBorder }, nls.localize('progressBarBackground', \"Background color of the progress bar that can show for long running operations.\"));\n\nexport const editorErrorBackground = registerColor('editorError.background', { dark: null, light: null, hcDark: null, hcLight: null }, nls.localize('editorError.background', 'Background color of error text in the editor. The color must not be opaque so as not to hide underlying decorations.'), true);\nexport const editorErrorForeground = registerColor('editorError.foreground', { dark: '#F14C4C', light: '#E51400', hcDark: '#F48771', hcLight: '#B5200D' }, nls.localize('editorError.foreground', 'Foreground color of error squigglies in the editor.'));\nexport const editorErrorBorder = registerColor('editorError.border', { dark: null, light: null, hcDark: Color.fromHex('#E47777').transparent(0.8), hcLight: '#B5200D' }, nls.localize('errorBorder', 'If set, color of double underlines for errors in the editor.'));\n\nexport const editorWarningBackground = registerColor('editorWarning.background', { dark: null, light: null, hcDark: null, hcLight: null }, nls.localize('editorWarning.background', 'Background color of warning text in the editor. The color must not be opaque so as not to hide underlying decorations.'), true);\nexport const editorWarningForeground = registerColor('editorWarning.foreground', { dark: '#CCA700', light: '#BF8803', hcDark: '#FFD370', hcLight: '#895503' }, nls.localize('editorWarning.foreground', 'Foreground color of warning squigglies in the editor.'));\nexport const editorWarningBorder = registerColor('editorWarning.border', { dark: null, light: null, hcDark: Color.fromHex('#FFCC00').transparent(0.8), hcLight: Color.fromHex('#FFCC00').transparent(0.8) }, nls.localize('warningBorder', 'If set, color of double underlines for warnings in the editor.'));\n\nexport const editorInfoBackground = registerColor('editorInfo.background', { dark: null, light: null, hcDark: null, hcLight: null }, nls.localize('editorInfo.background', 'Background color of info text in the editor. The color must not be opaque so as not to hide underlying decorations.'), true);\nexport const editorInfoForeground = registerColor('editorInfo.foreground', { dark: '#3794FF', light: '#1a85ff', hcDark: '#3794FF', hcLight: '#1a85ff' }, nls.localize('editorInfo.foreground', 'Foreground color of info squigglies in the editor.'));\nexport const editorInfoBorder = registerColor('editorInfo.border', { dark: null, light: null, hcDark: Color.fromHex('#3794FF').transparent(0.8), hcLight: '#292929' }, nls.localize('infoBorder', 'If set, color of double underlines for infos in the editor.'));\n\nexport const editorHintForeground = registerColor('editorHint.foreground', { dark: Color.fromHex('#eeeeee').transparent(0.7), light: '#6c6c6c', hcDark: null, hcLight: null }, nls.localize('editorHint.foreground', 'Foreground color of hint squigglies in the editor.'));\nexport const editorHintBorder = registerColor('editorHint.border', { dark: null, light: null, hcDark: Color.fromHex('#eeeeee').transparent(0.8), hcLight: '#292929' }, nls.localize('hintBorder', 'If set, color of double underlines for hints in the editor.'));\n\nexport const sashHoverBorder = registerColor('sash.hoverBorder', { dark: focusBorder, light: focusBorder, hcDark: focusBorder, hcLight: focusBorder }, nls.localize('sashActiveBorder', \"Border color of active sashes.\"));\n\n/**\n * Editor background color.\n */\nexport const editorBackground = registerColor('editor.background', { light: '#ffffff', dark: '#1E1E1E', hcDark: Color.black, hcLight: Color.white }, nls.localize('editorBackground', \"Editor background color.\"));\n\n/**\n * Editor foreground color.\n */\nexport const editorForeground = registerColor('editor.foreground', { light: '#333333', dark: '#BBBBBB', hcDark: Color.white, hcLight: foreground }, nls.localize('editorForeground', \"Editor default foreground color.\"));\n\n/**\n * Sticky scroll\n */\nexport const editorStickyScrollBackground = registerColor('editorStickyScroll.background', { light: editorBackground, dark: editorBackground, hcDark: editorBackground, hcLight: editorBackground }, nls.localize('editorStickyScrollBackground', \"Background color of sticky scroll in the editor\"));\nexport const editorStickyScrollHoverBackground = registerColor('editorStickyScrollHover.background', { dark: '#2A2D2E', light: '#F0F0F0', hcDark: null, hcLight: Color.fromHex('#0F4A85').transparent(0.1) }, nls.localize('editorStickyScrollHoverBackground', \"Background color of sticky scroll on hover in the editor\"));\nexport const editorStickyScrollBorder = registerColor('editorStickyScroll.border', { dark: null, light: null, hcDark: contrastBorder, hcLight: contrastBorder }, nls.localize('editorStickyScrollBorder', \"Border color of sticky scroll in the editor\"));\nexport const editorStickyScrollShadow = registerColor('editorStickyScroll.shadow', { dark: scrollbarShadow, light: scrollbarShadow, hcDark: scrollbarShadow, hcLight: scrollbarShadow }, nls.localize('editorStickyScrollShadow', \" Shadow color of sticky scroll in the editor\"));\n\n/**\n * Editor widgets\n */\nexport const editorWidgetBackground = registerColor('editorWidget.background', { dark: '#252526', light: '#F3F3F3', hcDark: '#0C141F', hcLight: Color.white }, nls.localize('editorWidgetBackground', 'Background color of editor widgets, such as find/replace.'));\nexport const editorWidgetForeground = registerColor('editorWidget.foreground', { dark: foreground, light: foreground, hcDark: foreground, hcLight: foreground }, nls.localize('editorWidgetForeground', 'Foreground color of editor widgets, such as find/replace.'));\nexport const editorWidgetBorder = registerColor('editorWidget.border', { dark: '#454545', light: '#C8C8C8', hcDark: contrastBorder, hcLight: contrastBorder }, nls.localize('editorWidgetBorder', 'Border color of editor widgets. The color is only used if the widget chooses to have a border and if the color is not overridden by a widget.'));\nexport const editorWidgetResizeBorder = registerColor('editorWidget.resizeBorder', { light: null, dark: null, hcDark: null, hcLight: null }, nls.localize('editorWidgetResizeBorder', \"Border color of the resize bar of editor widgets. The color is only used if the widget chooses to have a resize border and if the color is not overridden by a widget.\"));\n\n/**\n * Quick pick widget\n */\nexport const quickInputBackground = registerColor('quickInput.background', { dark: editorWidgetBackground, light: editorWidgetBackground, hcDark: editorWidgetBackground, hcLight: editorWidgetBackground }, nls.localize('pickerBackground', \"Quick picker background color. The quick picker widget is the container for pickers like the command palette.\"));\nexport const quickInputForeground = registerColor('quickInput.foreground', { dark: editorWidgetForeground, light: editorWidgetForeground, hcDark: editorWidgetForeground, hcLight: editorWidgetForeground }, nls.localize('pickerForeground', \"Quick picker foreground color. The quick picker widget is the container for pickers like the command palette.\"));\nexport const quickInputTitleBackground = registerColor('quickInputTitle.background', { dark: new Color(new RGBA(255, 255, 255, 0.105)), light: new Color(new RGBA(0, 0, 0, 0.06)), hcDark: '#000000', hcLight: Color.white }, nls.localize('pickerTitleBackground', \"Quick picker title background color. The quick picker widget is the container for pickers like the command palette.\"));\nexport const pickerGroupForeground = registerColor('pickerGroup.foreground', { dark: '#3794FF', light: '#0066BF', hcDark: Color.white, hcLight: '#0F4A85' }, nls.localize('pickerGroupForeground', \"Quick picker color for grouping labels.\"));\nexport const pickerGroupBorder = registerColor('pickerGroup.border', { dark: '#3F3F46', light: '#CCCEDB', hcDark: Color.white, hcLight: '#0F4A85' }, nls.localize('pickerGroupBorder', \"Quick picker color for grouping borders.\"));\n\n/**\n * Keybinding label\n */\nexport const keybindingLabelBackground = registerColor('keybindingLabel.background', { 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 }, nls.localize('keybindingLabelBackground', \"Keybinding label background color. The keybinding label is used to represent a keyboard shortcut.\"));\nexport const keybindingLabelForeground = registerColor('keybindingLabel.foreground', { dark: Color.fromHex('#CCCCCC'), light: Color.fromHex('#555555'), hcDark: Color.white, hcLight: foreground }, nls.localize('keybindingLabelForeground', \"Keybinding label foreground color. The keybinding label is used to represent a keyboard shortcut.\"));\nexport const keybindingLabelBorder = registerColor('keybindingLabel.border', { 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 }, nls.localize('keybindingLabelBorder', \"Keybinding label border color. The keybinding label is used to represent a keyboard shortcut.\"));\nexport const keybindingLabelBottomBorder = registerColor('keybindingLabel.bottomBorder', { 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 }, nls.localize('keybindingLabelBottomBorder', \"Keybinding label border bottom color. The keybinding label is used to represent a keyboard shortcut.\"));\n\n/**\n * Editor selection colors.\n */\nexport const editorSelectionBackground = registerColor('editor.selectionBackground', { light: '#ADD6FF', dark: '#264F78', hcDark: '#f3f518', hcLight: '#0F4A85' }, nls.localize('editorSelectionBackground', \"Color of the editor selection.\"));\nexport const editorSelectionForeground = registerColor('editor.selectionForeground', { light: null, dark: null, hcDark: '#000000', hcLight: Color.white }, nls.localize('editorSelectionForeground', \"Color of the selected text for high contrast.\"));\nexport const editorInactiveSelection = registerColor('editor.inactiveSelectionBackground', { light: transparent(editorSelectionBackground, 0.5), dark: transparent(editorSelectionBackground, 0.5), hcDark: transparent(editorSelectionBackground, 0.7), hcLight: transparent(editorSelectionBackground, 0.5) }, nls.localize('editorInactiveSelection', \"Color of the selection in an inactive editor. The color must not be opaque so as not to hide underlying decorations.\"), true);\nexport const editorSelectionHighlight = registerColor('editor.selectionHighlightBackground', { light: lessProminent(editorSelectionBackground, editorBackground, 0.3, 0.6), dark: lessProminent(editorSelectionBackground, editorBackground, 0.3, 0.6), hcDark: null, hcLight: null }, nls.localize('editorSelectionHighlight', 'Color for regions with the same content as the selection. The color must not be opaque so as not to hide underlying decorations.'), true);\nexport const editorSelectionHighlightBorder = registerColor('editor.selectionHighlightBorder', { light: null, dark: null, hcDark: activeContrastBorder, hcLight: activeContrastBorder }, nls.localize('editorSelectionHighlightBorder', \"Border color for regions with the same content as the selection.\"));\n\n\n/**\n * Editor find match colors.\n */\nexport const editorFindMatch = registerColor('editor.findMatchBackground', { light: '#A8AC94', dark: '#515C6A', hcDark: null, hcLight: null }, nls.localize('editorFindMatch', \"Color of the current search match.\"));\nexport const editorFindMatchHighlight = registerColor('editor.findMatchHighlightBackground', { light: '#EA5C0055', dark: '#EA5C0055', hcDark: null, hcLight: null }, nls.localize('findMatchHighlight', \"Color of the other search matches. The color must not be opaque so as not to hide underlying decorations.\"), true);\nexport const editorFindRangeHighlight = registerColor('editor.findRangeHighlightBackground', { dark: '#3a3d4166', light: '#b4b4b44d', hcDark: null, hcLight: null }, nls.localize('findRangeHighlight', \"Color of the range limiting the search. The color must not be opaque so as not to hide underlying decorations.\"), true);\nexport const editorFindMatchBorder = registerColor('editor.findMatchBorder', { light: null, dark: null, hcDark: activeContrastBorder, hcLight: activeContrastBorder }, nls.localize('editorFindMatchBorder', \"Border color of the current search match.\"));\nexport const editorFindMatchHighlightBorder = registerColor('editor.findMatchHighlightBorder', { light: null, dark: null, hcDark: activeContrastBorder, hcLight: activeContrastBorder }, nls.localize('findMatchHighlightBorder', \"Border color of the other search matches.\"));\nexport const editorFindRangeHighlightBorder = registerColor('editor.findRangeHighlightBorder', { dark: null, light: null, hcDark: transparent(activeContrastBorder, 0.4), hcLight: transparent(activeContrastBorder, 0.4) }, nls.localize('findRangeHighlightBorder', \"Border color of the range limiting the search. The color must not be opaque so as not to hide underlying decorations.\"), true);\n\n/**\n * Search Editor query match colors.\n *\n * Distinct from normal editor find match to allow for better differentiation\n */\nexport const searchEditorFindMatch = registerColor('searchEditor.findMatchBackground', { light: transparent(editorFindMatchHighlight, 0.66), dark: transparent(editorFindMatchHighlight, 0.66), hcDark: editorFindMatchHighlight, hcLight: editorFindMatchHighlight }, nls.localize('searchEditor.queryMatch', \"Color of the Search Editor query matches.\"));\nexport const searchEditorFindMatchBorder = registerColor('searchEditor.findMatchBorder', { light: transparent(editorFindMatchHighlightBorder, 0.66), dark: transparent(editorFindMatchHighlightBorder, 0.66), hcDark: editorFindMatchHighlightBorder, hcLight: editorFindMatchHighlightBorder }, nls.localize('searchEditor.editorFindMatchBorder', \"Border color of the Search Editor query matches.\"));\n\n/**\n * Search Viewlet colors.\n */\nexport const searchResultsInfoForeground = registerColor('search.resultsInfoForeground', { light: foreground, dark: transparent(foreground, 0.65), hcDark: foreground, hcLight: foreground }, nls.localize('search.resultsInfoForeground', \"Color of the text in the search viewlet's completion message.\"));\n\n/**\n * Editor hover\n */\nexport const editorHoverHighlight = registerColor('editor.hoverHighlightBackground', { light: '#ADD6FF26', dark: '#264f7840', hcDark: '#ADD6FF26', hcLight: null }, nls.localize('hoverHighlight', 'Highlight below the word for which a hover is shown. The color must not be opaque so as not to hide underlying decorations.'), true);\nexport const editorHoverBackground = registerColor('editorHoverWidget.background', { light: editorWidgetBackground, dark: editorWidgetBackground, hcDark: editorWidgetBackground, hcLight: editorWidgetBackground }, nls.localize('hoverBackground', 'Background color of the editor hover.'));\nexport const editorHoverForeground = registerColor('editorHoverWidget.foreground', { light: editorWidgetForeground, dark: editorWidgetForeground, hcDark: editorWidgetForeground, hcLight: editorWidgetForeground }, nls.localize('hoverForeground', 'Foreground color of the editor hover.'));\nexport const editorHoverBorder = registerColor('editorHoverWidget.border', { light: editorWidgetBorder, dark: editorWidgetBorder, hcDark: editorWidgetBorder, hcLight: editorWidgetBorder }, nls.localize('hoverBorder', 'Border color of the editor hover.'));\nexport const editorHoverStatusBarBackground = registerColor('editorHoverWidget.statusBarBackground', { dark: lighten(editorHoverBackground, 0.2), light: darken(editorHoverBackground, 0.05), hcDark: editorWidgetBackground, hcLight: editorWidgetBackground }, nls.localize('statusBarBackground', \"Background color of the editor hover status bar.\"));\n/**\n * Editor link colors\n */\nexport const editorActiveLinkForeground = registerColor('editorLink.activeForeground', { dark: '#4E94CE', light: Color.blue, hcDark: Color.cyan, hcLight: '#292929' }, nls.localize('activeLinkForeground', 'Color of active links.'));\n\n/**\n * Inline hints\n */\nexport const editorInlayHintForeground = registerColor('editorInlayHint.foreground', { dark: '#969696', light: '#969696', hcDark: Color.white, hcLight: Color.black }, nls.localize('editorInlayHintForeground', 'Foreground color of inline hints'));\nexport const editorInlayHintBackground = registerColor('editorInlayHint.background', { dark: transparent(badgeBackground, .10), light: transparent(badgeBackground, .10), hcDark: transparent(Color.white, .10), hcLight: transparent(badgeBackground, .10) }, nls.localize('editorInlayHintBackground', 'Background color of inline hints'));\nexport const editorInlayHintTypeForeground = registerColor('editorInlayHint.typeForeground', { dark: editorInlayHintForeground, light: editorInlayHintForeground, hcDark: editorInlayHintForeground, hcLight: editorInlayHintForeground }, nls.localize('editorInlayHintForegroundTypes', 'Foreground color of inline hints for types'));\nexport const editorInlayHintTypeBackground = registerColor('editorInlayHint.typeBackground', { dark: editorInlayHintBackground, light: editorInlayHintBackground, hcDark: editorInlayHintBackground, hcLight: editorInlayHintBackground }, nls.localize('editorInlayHintBackgroundTypes', 'Background color of inline hints for types'));\nexport const editorInlayHintParameterForeground = registerColor('editorInlayHint.parameterForeground', { dark: editorInlayHintForeground, light: editorInlayHintForeground, hcDark: editorInlayHintForeground, hcLight: editorInlayHintForeground }, nls.localize('editorInlayHintForegroundParameter', 'Foreground color of inline hints for parameters'));\nexport const editorInlayHintParameterBackground = registerColor('editorInlayHint.parameterBackground', { dark: editorInlayHintBackground, light: editorInlayHintBackground, hcDark: editorInlayHintBackground, hcLight: editorInlayHintBackground }, nls.localize('editorInlayHintBackgroundParameter', 'Background color of inline hints for parameters'));\n\n/**\n * Editor lightbulb icon colors\n */\nexport const editorLightBulbForeground = registerColor('editorLightBulb.foreground', { dark: '#FFCC00', light: '#DDB100', hcDark: '#FFCC00', hcLight: '#007ACC' }, nls.localize('editorLightBulbForeground', \"The color used for the lightbulb actions icon.\"));\nexport const editorLightBulbAutoFixForeground = registerColor('editorLightBulbAutoFix.foreground', { dark: '#75BEFF', light: '#007ACC', hcDark: '#75BEFF', hcLight: '#007ACC' }, nls.localize('editorLightBulbAutoFixForeground', \"The color used for the lightbulb auto fix actions icon.\"));\nexport const editorLightBulbAiForeground = registerColor('editorLightBulbAi.foreground', { dark: editorLightBulbForeground, light: editorLightBulbForeground, hcDark: editorLightBulbForeground, hcLight: editorLightBulbForeground }, nls.localize('editorLightBulbAiForeground', \"The color used for the lightbulb AI icon.\"));\n\n/**\n * Diff Editor Colors\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', { dark: '#9ccc2c33', light: '#9ccc2c40', hcDark: null, hcLight: null }, nls.localize('diffEditorInserted', 'Background color for text that got inserted. The color must not be opaque so as not to hide underlying decorations.'), true);\nexport const diffRemoved = registerColor('diffEditor.removedTextBackground', { dark: '#ff000033', light: '#ff000033', hcDark: null, hcLight: null }, nls.localize('diffEditorRemoved', 'Background color for text that got removed. The color must not be opaque so as not to hide underlying decorations.'), true);\n\nexport const diffInsertedLine = registerColor('diffEditor.insertedLineBackground', { dark: defaultInsertColor, light: defaultInsertColor, hcDark: null, hcLight: null }, nls.localize('diffEditorInsertedLines', 'Background color for lines that got inserted. The color must not be opaque so as not to hide underlying decorations.'), true);\nexport const diffRemovedLine = registerColor('diffEditor.removedLineBackground', { dark: defaultRemoveColor, light: defaultRemoveColor, hcDark: null, hcLight: null }, nls.localize('diffEditorRemovedLines', 'Background color for lines that got removed. The color must not be opaque so as not to hide underlying decorations.'), true);\n\nexport const diffInsertedLineGutter = registerColor('diffEditorGutter.insertedLineBackground', { dark: null, light: null, hcDark: null, hcLight: null }, nls.localize('diffEditorInsertedLineGutter', 'Background color for the margin where lines got inserted.'));\nexport const diffRemovedLineGutter = registerColor('diffEditorGutter.removedLineBackground', { dark: null, light: null, hcDark: null, hcLight: null }, nls.localize('diffEditorRemovedLineGutter', 'Background color for the margin where lines got removed.'));\n\nexport const diffOverviewRulerInserted = registerColor('diffEditorOverview.insertedForeground', { dark: null, light: null, hcDark: null, hcLight: null }, nls.localize('diffEditorOverviewInserted', 'Diff overview ruler foreground for inserted content.'));\nexport const diffOverviewRulerRemoved = registerColor('diffEditorOverview.removedForeground', { dark: null, light: null, hcDark: null, hcLight: null }, nls.localize('diffEditorOverviewRemoved', 'Diff overview ruler foreground for removed content.'));\n\nexport const diffInsertedOutline = registerColor('diffEditor.insertedTextBorder', { dark: null, light: null, hcDark: '#33ff2eff', hcLight: '#374E06' }, nls.localize('diffEditorInsertedOutline', 'Outline color for the text that got inserted.'));\nexport const diffRemovedOutline = registerColor('diffEditor.removedTextBorder', { dark: null, light: null, hcDark: '#FF008F', hcLight: '#AD0707' }, nls.localize('diffEditorRemovedOutline', 'Outline color for text that got removed.'));\n\nexport const diffBorder = registerColor('diffEditor.border', { dark: null, light: null, hcDark: contrastBorder, hcLight: contrastBorder }, nls.localize('diffEditorBorder', 'Border color between the two text editors.'));\nexport const diffDiagonalFill = registerColor('diffEditor.diagonalFill', { dark: '#cccccc33', light: '#22222233', hcDark: null, hcLight: null }, nls.localize('diffDiagonalFill', \"Color of the diff editor's diagonal fill. The diagonal fill is used in side-by-side diff views.\"));\n\nexport const diffUnchangedRegionBackground = registerColor('diffEditor.unchangedRegionBackground', { dark: 'sideBar.background', light: 'sideBar.background', hcDark: 'sideBar.background', hcLight: 'sideBar.background' }, nls.localize('diffEditor.unchangedRegionBackground', \"The background color of unchanged blocks in the diff editor.\"));\nexport const diffUnchangedRegionForeground = registerColor('diffEditor.unchangedRegionForeground', { dark: 'foreground', light: 'foreground', hcDark: 'foreground', hcLight: 'foreground' }, nls.localize('diffEditor.unchangedRegionForeground', \"The foreground color of unchanged blocks in the diff editor.\"));\nexport const diffUnchangedTextBackground = registerColor('diffEditor.unchangedCodeBackground', { dark: '#74747429', light: '#b8b8b829', hcDark: null, hcLight: null }, nls.localize('diffEditor.unchangedCodeBackground', \"The background color of unchanged code in the diff editor.\"));\n\n/**\n * List and tree colors\n */\nexport const listFocusBackground = registerColor('list.focusBackground', { dark: null, light: null, hcDark: null, hcLight: null }, nls.localize('listFocusBackground', \"List/Tree background color for the focused item when the list/tree is active. An active list/tree has keyboard focus, an inactive does not.\"));\nexport const listFocusForeground = registerColor('list.focusForeground', { dark: null, light: null, hcDark: null, hcLight: null }, nls.localize('listFocusForeground', \"List/Tree foreground color for the focused item when the list/tree is active. An active list/tree has keyboard focus, an inactive does not.\"));\nexport const listFocusOutline = registerColor('list.focusOutline', { dark: focusBorder, light: focusBorder, hcDark: activeContrastBorder, hcLight: activeContrastBorder }, nls.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.\"));\nexport const listFocusAndSelectionOutline = registerColor('list.focusAndSelectionOutline', { dark: null, light: null, hcDark: null, hcLight: null }, nls.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.\"));\nexport const listActiveSelectionBackground = registerColor('list.activeSelectionBackground', { dark: '#04395E', light: '#0060C0', hcDark: null, hcLight: Color.fromHex('#0F4A85').transparent(0.1) }, nls.localize('listActiveSelectionBackground', \"List/Tree background color for the selected item when the list/tree is active. An active list/tree has keyboard focus, an inactive does not.\"));\nexport const listActiveSelectionForeground = registerColor('list.activeSelectionForeground', { dark: Color.white, light: Color.white, hcDark: null, hcLight: null }, nls.localize('listActiveSelectionForeground', \"List/Tree foreground color for the selected item when the list/tree is active. An active list/tree has keyboard focus, an inactive does not.\"));\nexport const listActiveSelectionIconForeground = registerColor('list.activeSelectionIconForeground', { dark: null, light: null, hcDark: null, hcLight: null }, nls.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.\"));\nexport const listInactiveSelectionBackground = registerColor('list.inactiveSelectionBackground', { dark: '#37373D', light: '#E4E6F1', hcDark: null, hcLight: Color.fromHex('#0F4A85').transparent(0.1) }, nls.localize('listInactiveSelectionBackground', \"List/Tree background color for the selected item when the list/tree is inactive. An active list/tree has keyboard focus, an inactive does not.\"));\nexport const listInactiveSelectionForeground = registerColor('list.inactiveSelectionForeground', { dark: null, light: null, hcDark: null, hcLight: null }, nls.localize('listInactiveSelectionForeground', \"List/Tree foreground color for the selected item when the list/tree is inactive. An active list/tree has keyboard focus, an inactive does not.\"));\nexport const listInactiveSelectionIconForeground = registerColor('list.inactiveSelectionIconForeground', { dark: null, light: null, hcDark: null, hcLight: null }, nls.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.\"));\nexport const listInactiveFocusBackground = registerColor('list.inactiveFocusBackground', { dark: null, light: null, hcDark: null, hcLight: null }, nls.localize('listInactiveFocusBackground', \"List/Tree background color for the focused item when the list/tree is inactive. An active list/tree has keyboard focus, an inactive does not.\"));\nexport const listInactiveFocusOutline = registerColor('list.inactiveFocusOutline', { dark: null, light: null, hcDark: null, hcLight: null }, nls.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.\"));\nexport const listHoverBackground = registerColor('list.hoverBackground', { dark: '#2A2D2E', light: '#F0F0F0', hcDark: Color.white.transparent(0.1), hcLight: Color.fromHex('#0F4A85').transparent(0.1) }, nls.localize('listHoverBackground', \"List/Tree background when hovering over items using the mouse.\"));\nexport const listHoverForeground = registerColor('list.hoverForeground', { dark: null, light: null, hcDark: null, hcLight: null }, nls.localize('listHoverForeground', \"List/Tree foreground when hovering over items using the mouse.\"));\nexport const listDropOverBackground = registerColor('list.dropBackground', { dark: '#062F4A', light: '#D6EBFF', hcDark: null, hcLight: null }, nls.localize('listDropBackground', \"List/Tree drag and drop background when moving items over other items when using the mouse.\"));\nexport const listDropBetweenBackground = registerColor('list.dropBetweenBackground', { dark: iconForeground, light: iconForeground, hcDark: null, hcLight: null }, nls.localize('listDropBetweenBackground', \"List/Tree drag and drop border color when moving items between items when using the mouse.\"));\nexport const listHighlightForeground = registerColor('list.highlightForeground', { dark: '#2AAAFF', light: '#0066BF', hcDark: focusBorder, hcLight: focusBorder }, nls.localize('highlight', 'List/Tree foreground color of the match highlights when searching inside the list/tree.'));\nexport const listFocusHighlightForeground = registerColor('list.focusHighlightForeground', { dark: listHighlightForeground, light: ifDefinedThenElse(listActiveSelectionBackground, listHighlightForeground, '#BBE7FF'), hcDark: listHighlightForeground, hcLight: listHighlightForeground }, nls.localize('listFocusHighlightForeground', 'List/Tree foreground color of the match highlights on actively focused items when searching inside the list/tree.'));\nexport const listInvalidItemForeground = registerColor('list.invalidItemForeground', { dark: '#B89500', light: '#B89500', hcDark: '#B89500', hcLight: '#B5200D' }, nls.localize('invalidItemForeground', 'List/Tree foreground color for invalid items, for example an unresolved root in explorer.'));\nexport const listErrorForeground = registerColor('list.errorForeground', { dark: '#F88070', light: '#B01011', hcDark: null, hcLight: null }, nls.localize('listErrorForeground', 'Foreground color of list items containing errors.'));\nexport const listWarningForeground = registerColor('list.warningForeground', { dark: '#CCA700', light: '#855F00', hcDark: null, hcLight: null }, nls.localize('listWarningForeground', 'Foreground color of list items containing warnings.'));\nexport const listFilterWidgetBackground = registerColor('listFilterWidget.background', { light: darken(editorWidgetBackground, 0), dark: lighten(editorWidgetBackground, 0), hcDark: editorWidgetBackground, hcLight: editorWidgetBackground }, nls.localize('listFilterWidgetBackground', 'Background color of the type filter widget in lists and trees.'));\nexport const listFilterWidgetOutline = registerColor('listFilterWidget.outline', { dark: Color.transparent, light: Color.transparent, hcDark: '#f38518', hcLight: '#007ACC' }, nls.localize('listFilterWidgetOutline', 'Outline color of the type filter widget in lists and trees.'));\nexport const listFilterWidgetNoMatchesOutline = registerColor('listFilterWidget.noMatchesOutline', { dark: '#BE1100', light: '#BE1100', hcDark: contrastBorder, hcLight: contrastBorder }, nls.localize('listFilterWidgetNoMatchesOutline', 'Outline color of the type filter widget in lists and trees, when there are no matches.'));\nexport const listFilterWidgetShadow = registerColor('listFilterWidget.shadow', { dark: widgetShadow, light: widgetShadow, hcDark: widgetShadow, hcLight: widgetShadow }, nls.localize('listFilterWidgetShadow', 'Shadow color of the type filter widget in lists and trees.'));\nexport const listFilterMatchHighlight = registerColor('list.filterMatchBackground', { dark: editorFindMatchHighlight, light: editorFindMatchHighlight, hcDark: null, hcLight: null }, nls.localize('listFilterMatchHighlight', 'Background color of the filtered match.'));\nexport const listFilterMatchHighlightBorder = registerColor('list.filterMatchBorder', { dark: editorFindMatchHighlightBorder, light: editorFindMatchHighlightBorder, hcDark: contrastBorder, hcLight: activeContrastBorder }, nls.localize('listFilterMatchHighlightBorder', 'Border color of the filtered match.'));\nexport const treeIndentGuidesStroke = registerColor('tree.indentGuidesStroke', { dark: '#585858', light: '#a9a9a9', hcDark: '#a9a9a9', hcLight: '#a5a5a5' }, nls.localize('treeIndentGuidesStroke', \"Tree stroke color for the indentation guides.\"));\nexport const treeInactiveIndentGuidesStroke = registerColor('tree.inactiveIndentGuidesStroke', { dark: transparent(treeIndentGuidesStroke, 0.4), light: transparent(treeIndentGuidesStroke, 0.4), hcDark: transparent(treeIndentGuidesStroke, 0.4), hcLight: transparent(treeIndentGuidesStroke, 0.4) }, nls.localize('treeInactiveIndentGuidesStroke', \"Tree stroke color for the indentation guides that are not active.\"));\nexport const tableColumnsBorder = registerColor('tree.tableColumnsBorder', { dark: '#CCCCCC20', light: '#61616120', hcDark: null, hcLight: null }, nls.localize('tableColumnsBorder', \"Table border color between columns.\"));\nexport const tableOddRowsBackgroundColor = registerColor('tree.tableOddRowsBackground', { dark: transparent(foreground, 0.04), light: transparent(foreground, 0.04), hcDark: null, hcLight: null }, nls.localize('tableOddRowsBackgroundColor', \"Background color for odd table rows.\"));\nexport const listDeemphasizedForeground = registerColor('list.deemphasizedForeground', { dark: '#8C8C8C', light: '#8E8E90', hcDark: '#A7A8A9', hcLight: '#666666' }, nls.localize('listDeemphasizedForeground', \"List/Tree foreground color for items that are deemphasized. \"));\n\n/**\n * Checkboxes\n */\nexport const checkboxBackground = registerColor('checkbox.background', { dark: selectBackground, light: selectBackground, hcDark: selectBackground, hcLight: selectBackground }, nls.localize('checkbox.background', \"Background color of checkbox widget.\"));\nexport const checkboxSelectBackground = registerColor('checkbox.selectBackground', { dark: editorWidgetBackground, light: editorWidgetBackground, hcDark: editorWidgetBackground, hcLight: editorWidgetBackground }, nls.localize('checkbox.select.background', \"Background color of checkbox widget when the element it's in is selected.\"));\nexport const checkboxForeground = registerColor('checkbox.foreground', { dark: selectForeground, light: selectForeground, hcDark: selectForeground, hcLight: selectForeground }, nls.localize('checkbox.foreground', \"Foreground color of checkbox widget.\"));\nexport const checkboxBorder = registerColor('checkbox.border', { dark: selectBorder, light: selectBorder, hcDark: selectBorder, hcLight: selectBorder }, nls.localize('checkbox.border', \"Border color of checkbox widget.\"));\nexport const checkboxSelectBorder = registerColor('checkbox.selectBorder', { dark: iconForeground, light: iconForeground, hcDark: iconForeground, hcLight: iconForeground }, nls.localize('checkbox.select.border', \"Border color of checkbox widget when the element it's in is selected.\"));\n\n/**\n * Quick pick widget (dependent on List and tree colors)\n */\nexport const _deprecatedQuickInputListFocusBackground = registerColor('quickInput.list.focusBackground', { dark: null, light: null, hcDark: null, hcLight: null }, '', undefined, nls.localize('quickInput.list.focusBackground deprecation', \"Please use quickInputList.focusBackground instead\"));\nexport const quickInputListFocusForeground = registerColor('quickInputList.focusForeground', { dark: listActiveSelectionForeground, light: listActiveSelectionForeground, hcDark: listActiveSelectionForeground, hcLight: listActiveSelectionForeground }, nls.localize('quickInput.listFocusForeground', \"Quick picker foreground color for the focused item.\"));\nexport const quickInputListFocusIconForeground = registerColor('quickInputList.focusIconForeground', { dark: listActiveSelectionIconForeground, light: listActiveSelectionIconForeground, hcDark: listActiveSelectionIconForeground, hcLight: listActiveSelectionIconForeground }, nls.localize('quickInput.listFocusIconForeground', \"Quick picker icon foreground color for the focused item.\"));\nexport const quickInputListFocusBackground = registerColor('quickInputList.focusBackground', { dark: oneOf(_deprecatedQuickInputListFocusBackground, listActiveSelectionBackground), light: oneOf(_deprecatedQuickInputListFocusBackground, listActiveSelectionBackground), hcDark: null, hcLight: null }, nls.localize('quickInput.listFocusBackground', \"Quick picker background color for the focused item.\"));\n\n/**\n * Menu colors\n */\nexport const menuBorder = registerColor('menu.border', { dark: null, light: null, hcDark: contrastBorder, hcLight: contrastBorder }, nls.localize('menuBorder', \"Border color of menus.\"));\nexport const menuForeground = registerColor('menu.foreground', { dark: selectForeground, light: selectForeground, hcDark: selectForeground, hcLight: selectForeground }, nls.localize('menuForeground', \"Foreground color of menu items.\"));\nexport const menuBackground = registerColor('menu.background', { dark: selectBackground, light: selectBackground, hcDark: selectBackground, hcLight: selectBackground }, nls.localize('menuBackground', \"Background color of menu items.\"));\nexport const menuSelectionForeground = registerColor('menu.selectionForeground', { dark: listActiveSelectionForeground, light: listActiveSelectionForeground, hcDark: listActiveSelectionForeground, hcLight: listActiveSelectionForeground }, nls.localize('menuSelectionForeground', \"Foreground color of the selected menu item in menus.\"));\nexport const menuSelectionBackground = registerColor('menu.selectionBackground', { dark: listActiveSelectionBackground, light: listActiveSelectionBackground, hcDark: listActiveSelectionBackground, hcLight: listActiveSelectionBackground }, nls.localize('menuSelectionBackground', \"Background color of the selected menu item in menus.\"));\nexport const menuSelectionBorder = registerColor('menu.selectionBorder', { dark: null, light: null, hcDark: activeContrastBorder, hcLight: activeContrastBorder }, nls.localize('menuSelectionBorder', \"Border color of the selected menu item in menus.\"));\nexport const menuSeparatorBackground = registerColor('menu.separatorBackground', { dark: '#606060', light: '#D4D4D4', hcDark: contrastBorder, hcLight: contrastBorder }, nls.localize('menuSeparatorBackground', \"Color of a separator menu item in menus.\"));\n\n/**\n * Toolbar colors\n */\nexport const toolbarHoverBackground = registerColor('toolbar.hoverBackground', { dark: '#5a5d5e50', light: '#b8b8b850', hcDark: null, hcLight: null }, nls.localize('toolbarHoverBackground', \"Toolbar background when hovering over actions using the mouse\"));\nexport const toolbarHoverOutline = registerColor('toolbar.hoverOutline', { dark: null, light: null, hcDark: activeContrastBorder, hcLight: activeContrastBorder }, nls.localize('toolbarHoverOutline', \"Toolbar outline when hovering over actions using the mouse\"));\nexport const toolbarActiveBackground = registerColor('toolbar.activeBackground', { dark: lighten(toolbarHoverBackground, 0.1), light: darken(toolbarHoverBackground, 0.1), hcDark: null, hcLight: null }, nls.localize('toolbarActiveBackground', \"Toolbar background when holding the mouse over actions\"));\n\n/**\n * Snippet placeholder colors\n */\nexport const snippetTabstopHighlightBackground = registerColor('editor.snippetTabstopHighlightBackground', { dark: new Color(new RGBA(124, 124, 124, 0.3)), light: new Color(new RGBA(10, 50, 100, 0.2)), hcDark: new Color(new RGBA(124, 124, 124, 0.3)), hcLight: new Color(new RGBA(10, 50, 100, 0.2)) }, nls.localize('snippetTabstopHighlightBackground', \"Highlight background color of a snippet tabstop.\"));\nexport const snippetTabstopHighlightBorder = registerColor('editor.snippetTabstopHighlightBorder', { dark: null, light: null, hcDark: null, hcLight: null }, nls.localize('snippetTabstopHighlightBorder', \"Highlight border color of a snippet tabstop.\"));\nexport const snippetFinalTabstopHighlightBackground = registerColor('editor.snippetFinalTabstopHighlightBackground', { dark: null, light: null, hcDark: null, hcLight: null }, nls.localize('snippetFinalTabstopHighlightBackground', \"Highlight background color of the final tabstop of a snippet.\"));\nexport const snippetFinalTabstopHighlightBorder = registerColor('editor.snippetFinalTabstopHighlightBorder', { dark: '#525252', light: new Color(new RGBA(10, 50, 100, 0.5)), hcDark: '#525252', hcLight: '#292929' }, nls.localize('snippetFinalTabstopHighlightBorder', \"Highlight border color of the final tabstop of a snippet.\"));\n\n/**\n * Breadcrumb colors\n */\nexport const breadcrumbsForeground = registerColor('breadcrumb.foreground', { light: transparent(foreground, 0.8), dark: transparent(foreground, 0.8), hcDark: transparent(foreground, 0.8), hcLight: transparent(foreground, 0.8) }, nls.localize('breadcrumbsFocusForeground', \"Color of focused breadcrumb items.\"));\nexport const breadcrumbsBackground = registerColor('breadcrumb.background', { light: editorBackground, dark: editorBackground, hcDark: editorBackground, hcLight: editorBackground }, nls.localize('breadcrumbsBackground', \"Background color of breadcrumb items.\"));\nexport const breadcrumbsFocusForeground = registerColor('breadcrumb.focusForeground', { light: darken(foreground, 0.2), dark: lighten(foreground, 0.1), hcDark: lighten(foreground, 0.1), hcLight: lighten(foreground, 0.1) }, nls.localize('breadcrumbsFocusForeground', \"Color of focused breadcrumb items.\"));\nexport const breadcrumbsActiveSelectionForeground = registerColor('breadcrumb.activeSelectionForeground', { light: darken(foreground, 0.2), dark: lighten(foreground, 0.1), hcDark: lighten(foreground, 0.1), hcLight: lighten(foreground, 0.1) }, nls.localize('breadcrumbsSelectedForeground', \"Color of selected breadcrumb items.\"));\nexport const breadcrumbsPickerBackground = registerColor('breadcrumbPicker.background', { light: editorWidgetBackground, dark: editorWidgetBackground, hcDark: editorWidgetBackground, hcLight: editorWidgetBackground }, nls.localize('breadcrumbsSelectedBackground', \"Background color of breadcrumb item picker.\"));\n\n/**\n * Merge-conflict colors\n */\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', { dark: currentBaseColor, light: currentBaseColor, hcDark: null, hcLight: null }, nls.localize('mergeCurrentHeaderBackground', 'Current header background in inline merge-conflicts. The color must not be opaque so as not to hide underlying decorations.'), true);\nexport const mergeCurrentContentBackground = registerColor('merge.currentContentBackground', { dark: transparent(mergeCurrentHeaderBackground, contentTransparency), light: transparent(mergeCurrentHeaderBackground, contentTransparency), hcDark: transparent(mergeCurrentHeaderBackground, contentTransparency), hcLight: transparent(mergeCurrentHeaderBackground, contentTransparency) }, nls.localize('mergeCurrentContentBackground', 'Current content background in inline merge-conflicts. The color must not be opaque so as not to hide underlying decorations.'), true);\nexport const mergeIncomingHeaderBackground = registerColor('merge.incomingHeaderBackground', { dark: incomingBaseColor, light: incomingBaseColor, hcDark: null, hcLight: null }, nls.localize('mergeIncomingHeaderBackground', 'Incoming header background in inline merge-conflicts. The color must not be opaque so as not to hide underlying decorations.'), true);\nexport const mergeIncomingContentBackground = registerColor('merge.incomingContentBackground', { dark: transparent(mergeIncomingHeaderBackground, contentTransparency), light: transparent(mergeIncomingHeaderBackground, contentTransparency), hcDark: transparent(mergeIncomingHeaderBackground, contentTransparency), hcLight: transparent(mergeIncomingHeaderBackground, contentTransparency) }, nls.localize('mergeIncomingContentBackground', 'Incoming content background in inline merge-conflicts. The color must not be opaque so as not to hide underlying decorations.'), true);\nexport const mergeCommonHeaderBackground = registerColor('merge.commonHeaderBackground', { dark: commonBaseColor, light: commonBaseColor, hcDark: null, hcLight: null }, nls.localize('mergeCommonHeaderBackground', 'Common ancestor header background in inline merge-conflicts. The color must not be opaque so as not to hide underlying decorations.'), true);\nexport const mergeCommonContentBackground = registerColor('merge.commonContentBackground', { dark: transparent(mergeCommonHeaderBackground, contentTransparency), light: transparent(mergeCommonHeaderBackground, contentTransparency), hcDark: transparent(mergeCommonHeaderBackground, contentTransparency), hcLight: transparent(mergeCommonHeaderBackground, contentTransparency) }, nls.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', { dark: null, light: null, hcDark: '#C3DF6F', hcLight: '#007ACC' }, nls.localize('mergeBorder', 'Border color on headers and the splitter in inline merge-conflicts.'));\n\nexport const overviewRulerCurrentContentForeground = registerColor('editorOverviewRuler.currentContentForeground', { dark: transparent(mergeCurrentHeaderBackground, rulerTransparency), light: transparent(mergeCurrentHeaderBackground, rulerTransparency), hcDark: mergeBorder, hcLight: mergeBorder }, nls.localize('overviewRulerCurrentContentForeground', 'Current overview ruler foreground for inline merge-conflicts.'));\nexport const overviewRulerIncomingContentForeground = registerColor('editorOverviewRuler.incomingContentForeground', { dark: transparent(mergeIncomingHeaderBackground, rulerTransparency), light: transparent(mergeIncomingHeaderBackground, rulerTransparency), hcDark: mergeBorder, hcLight: mergeBorder }, nls.localize('overviewRulerIncomingContentForeground', 'Incoming overview ruler foreground for inline merge-conflicts.'));\nexport const overviewRulerCommonContentForeground = registerColor('editorOverviewRuler.commonContentForeground', { dark: transparent(mergeCommonHeaderBackground, rulerTransparency), light: transparent(mergeCommonHeaderBackground, rulerTransparency), hcDark: mergeBorder, hcLight: mergeBorder }, nls.localize('overviewRulerCommonContentForeground', 'Common ancestor overview ruler foreground for inline merge-conflicts.'));\n\nexport const overviewRulerFindMatchForeground = registerColor('editorOverviewRuler.findMatchForeground', { dark: '#d186167e', light: '#d186167e', hcDark: '#AB5A00', hcLight: '' }, nls.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', { dark: '#A0A0A0CC', light: '#A0A0A0CC', hcDark: '#A0A0A0CC', hcLight: '#A0A0A0CC' }, nls.localize('overviewRulerSelectionHighlightForeground', 'Overview ruler marker color for selection highlights. The color must not be opaque so as not to hide underlying decorations.'), true);\n\n\nexport const minimapFindMatch = registerColor('minimap.findMatchHighlight', { light: '#d18616', dark: '#d18616', hcDark: '#AB5A00', hcLight: '#0F4A85' }, nls.localize('minimapFindMatchHighlight', 'Minimap marker color for find matches.'), true);\nexport const minimapSelectionOccurrenceHighlight = registerColor('minimap.selectionOccurrenceHighlight', { light: '#c9c9c9', dark: '#676767', hcDark: '#ffffff', hcLight: '#0F4A85' }, nls.localize('minimapSelectionOccurrenceHighlight', 'Minimap marker color for repeating editor selections.'), true);\nexport const minimapSelection = registerColor('minimap.selectionHighlight', { light: '#ADD6FF', dark: '#264F78', hcDark: '#ffffff', hcLight: '#0F4A85' }, nls.localize('minimapSelectionHighlight', 'Minimap marker color for the editor selection.'), true);\nexport const minimapInfo = registerColor('minimap.infoHighlight', { dark: editorInfoForeground, light: editorInfoForeground, hcDark: editorInfoBorder, hcLight: editorInfoBorder }, nls.localize('minimapInfo', 'Minimap marker color for infos.'));\nexport const minimapWarning = registerColor('minimap.warningHighlight', { dark: editorWarningForeground, light: editorWarningForeground, hcDark: editorWarningBorder, hcLight: editorWarningBorder }, nls.localize('overviewRuleWarning', 'Minimap marker color for warnings.'));\nexport const minimapError = registerColor('minimap.errorHighlight', { dark: new Color(new RGBA(255, 18, 18, 0.7)), light: new Color(new RGBA(255, 18, 18, 0.7)), hcDark: new Color(new RGBA(255, 50, 50, 1)), hcLight: '#B5200D' }, nls.localize('minimapError', 'Minimap marker color for errors.'));\nexport const minimapBackground = registerColor('minimap.background', { dark: null, light: null, hcDark: null, hcLight: null }, nls.localize('minimapBackground', \"Minimap background color.\"));\nexport const minimapForegroundOpacity = registerColor('minimap.foregroundOpacity', { dark: Color.fromHex('#000f'), light: Color.fromHex('#000f'), hcDark: Color.fromHex('#000f'), hcLight: Color.fromHex('#000f') }, nls.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', { light: transparent(scrollbarSliderBackground, 0.5), dark: transparent(scrollbarSliderBackground, 0.5), hcDark: transparent(scrollbarSliderBackground, 0.5), hcLight: transparent(scrollbarSliderBackground, 0.5) }, nls.localize('minimapSliderBackground', \"Minimap slider background color.\"));\nexport const minimapSliderHoverBackground = registerColor('minimapSlider.hoverBackground', { light: transparent(scrollbarSliderHoverBackground, 0.5), dark: transparent(scrollbarSliderHoverBackground, 0.5), hcDark: transparent(scrollbarSliderHoverBackground, 0.5), hcLight: transparent(scrollbarSliderHoverBackground, 0.5) }, nls.localize('minimapSliderHoverBackground', \"Minimap slider background color when hovering.\"));\nexport const minimapSliderActiveBackground = registerColor('minimapSlider.activeBackground', { light: transparent(scrollbarSliderActiveBackground, 0.5), dark: transparent(scrollbarSliderActiveBackground, 0.5), hcDark: transparent(scrollbarSliderActiveBackground, 0.5), hcLight: transparent(scrollbarSliderActiveBackground, 0.5) }, nls.localize('minimapSliderActiveBackground', \"Minimap slider background color when clicked on.\"));\n\nexport const problemsErrorIconForeground = registerColor('problemsErrorIcon.foreground', { dark: editorErrorForeground, light: editorErrorForeground, hcDark: editorErrorForeground, hcLight: editorErrorForeground }, nls.localize('problemsErrorIconForeground', \"The color used for the problems error icon.\"));\nexport const problemsWarningIconForeground = registerColor('problemsWarningIcon.foreground', { dark: editorWarningForeground, light: editorWarningForeground, hcDark: editorWarningForeground, hcLight: editorWarningForeground }, nls.localize('problemsWarningIconForeground', \"The color used for the problems warning icon.\"));\nexport const problemsInfoIconForeground = registerColor('problemsInfoIcon.foreground', { dark: editorInfoForeground, light: editorInfoForeground, hcDark: editorInfoForeground, hcLight: editorInfoForeground }, nls.localize('problemsInfoIconForeground', \"The color used for the problems info icon.\"));\n\n/**\n * Chart colors\n */\nexport const chartsForeground = registerColor('charts.foreground', { dark: foreground, light: foreground, hcDark: foreground, hcLight: foreground }, nls.localize('chartsForeground', \"The foreground color used in charts.\"));\nexport const chartsLines = registerColor('charts.lines', { dark: transparent(foreground, .5), light: transparent(foreground, .5), hcDark: transparent(foreground, .5), hcLight: transparent(foreground, .5) }, nls.localize('chartsLines', \"The color used for horizontal lines in charts.\"));\nexport const chartsRed = registerColor('charts.red', { dark: editorErrorForeground, light: editorErrorForeground, hcDark: editorErrorForeground, hcLight: editorErrorForeground }, nls.localize('chartsRed', \"The red color used in chart visualizations.\"));\nexport const chartsBlue = registerColor('charts.blue', { dark: editorInfoForeground, light: editorInfoForeground, hcDark: editorInfoForeground, hcLight: editorInfoForeground }, nls.localize('chartsBlue', \"The blue color used in chart visualizations.\"));\nexport const chartsYellow = registerColor('charts.yellow', { dark: editorWarningForeground, light: editorWarningForeground, hcDark: editorWarningForeground, hcLight: editorWarningForeground }, nls.localize('chartsYellow', \"The yellow color used in chart visualizations.\"));\nexport const chartsOrange = registerColor('charts.orange', { dark: minimapFindMatch, light: minimapFindMatch, hcDark: minimapFindMatch, hcLight: minimapFindMatch }, nls.localize('chartsOrange', \"The orange color used in chart visualizations.\"));\nexport const chartsGreen = registerColor('charts.green', { dark: '#89D185', light: '#388A34', hcDark: '#89D185', hcLight: '#374e06' }, nls.localize('chartsGreen', \"The green color used in chart visualizations.\"));\nexport const chartsPurple = registerColor('charts.purple', { dark: '#B180D7', light: '#652D90', hcDark: '#B180D7', hcLight: '#652D90' }, nls.localize('chartsPurple', \"The purple color used in chart visualizations.\"));\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 opaque(colorValue: ColorValue, background: ColorValue): ColorTransform {\n\treturn { op: ColorTransformType.Opaque, value: colorValue, background };\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\nfunction 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 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\tborder?: string;\n\tborderColor?: string | ThemeColor;\n\tborderRadius?: string;\n\tfontStyle?: string;\n\tfontWeight?: string;\n\tfontSize?: string;\n\tfontFamily?: string;\n\tunicodeBidi?: string;\n\ttextDecoration?: string;\n\tcolor?: string | ThemeColor;\n\tbackgroundColor?: string | ThemeColor;\n\topacity?: string;\n\tverticalAlign?: string;\n\tcursor?: string;\n\tmargin?: string;\n\tpadding?: string;\n\twidth?: string;\n\theight?: string;\n\tdisplay?: string;\n}\n\nclass RefCountedCssRule {\n\tprivate _referenceCount: number = 0;\n\tprivate _styleElement: HTMLStyleElement | undefined;\n\tprivate _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 } 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, TextModelResolvedOptions } from 'vs/editor/common/model';\nimport { createSingleCallFunction } from 'vs/base/common/functional';\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\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\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\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.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\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[]\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 _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\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\tconst decorations = this._context.viewModel.getMinimapDecorationsInRange(visibleRange);\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 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}\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 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';\n\ninterface ActionGroup {\n\treadonly kind: CodeActionKind;\n\treadonly title: string;\n\treadonly icon?: ThemeIcon;\n}\n\nconst uncategorizedCodeActionGroup = Object.freeze({ kind: CodeActionKind.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 CodeActionKind(action.action.kind) : CodeActionKind.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 = { ...styles } as { [P in keyof T]: string | undefined };\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};\n\nexport function getKeybindingLabelStyles(override: IStyleOverride): IKeybindingLabelStyles {\n\treturn overrideStyles(override, defaultKeybindingLabelStyles);\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 function getButtonStyles(override: IStyleOverride): IButtonStyles {\n\treturn overrideStyles(override, defaultButtonStyles);\n}\n\nexport const defaultProgressBarStyles: IProgressBarStyles = {\n\tprogressBarBackground: asCssVariable(progressBarBackground)\n};\n\nexport function getProgressBarStyles(override: IStyleOverride): IProgressBarStyles {\n\treturn overrideStyles(override, defaultProgressBarStyles);\n}\n\nexport const defaultToggleStyles: IToggleStyles = {\n\tinputActiveOptionBorder: asCssVariable(inputActiveOptionBorder),\n\tinputActiveOptionForeground: asCssVariable(inputActiveOptionForeground),\n\tinputActiveOptionBackground: asCssVariable(inputActiveOptionBackground)\n};\n\nexport function getToggleStyles(override: IStyleOverride): IToggleStyles {\n\treturn overrideStyles(override, defaultToggleStyles);\n}\n\nexport const defaultCheckboxStyles: ICheckboxStyles = {\n\tcheckboxBackground: asCssVariable(checkboxBackground),\n\tcheckboxBorder: asCssVariable(checkboxBorder),\n\tcheckboxForeground: asCssVariable(checkboxForeground)\n};\n\nexport function getCheckboxStyles(override: IStyleOverride): ICheckboxStyles {\n\treturn overrideStyles(override, defaultCheckboxStyles);\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 function getDialogStyle(override: IStyleOverride): IDialogStyles {\n\treturn overrideStyles(override, defaultDialogStyles);\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 function getInputBoxStyle(override: IStyleOverride): IInputBoxStyles {\n\treturn overrideStyles(override, defaultInputBoxStyles);\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 function getCountBadgeStyle(override: IStyleOverride): ICountBadgeStyles {\n\treturn overrideStyles(override, defaultCountBadgeStyles);\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 function getBreadcrumbsWidgetStyles(override: IStyleOverride): IBreadcrumbsWidgetStyles {\n\treturn overrideStyles(override, defaultBreadcrumbsWidgetStyles);\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\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};\n\nexport function getSelectBoxStyles(override: IStyleOverride): ISelectBoxStyles {\n\treturn overrideStyles(override, defaultSelectBoxStyles);\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\nexport function getMenuStyles(override: IStyleOverride): IMenuStyles {\n\treturn overrideStyles(override, defaultMenuStyles);\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) 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 { 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\tmightProducePrintableCharacter(event: IKeyboardEvent): boolean {\n\t\treturn this._keybindingService.mightProducePrintableCharacter(event);\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 {\n\n\treadonly label: HighlightedLabel;\n\n\tconstructor(container: HTMLElement) {\n\t\tthis.label = 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(): void {\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// noop\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(): 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() {\n\t\tthis._list.value?.hide();\n\t\tthis._list.clear();\n\t}\n\n\tclear() {\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()));\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();\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\tget onDidOpen(): Event> { return this.navigator.onDidOpen; }\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\tget useAltAsMultipleSelectionModifier(): boolean {\n\t\treturn this._useAltAsMultipleSelectionModifier;\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\tget onDidOpen(): Event> { return this.navigator.onDidOpen; }\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\tget useAltAsMultipleSelectionModifier(): boolean {\n\t\treturn this._useAltAsMultipleSelectionModifier;\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\tget onDidOpen(): Event> { return this.navigator.onDidOpen; }\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\tget useAltAsMultipleSelectionModifier(): boolean {\n\t\treturn this._useAltAsMultipleSelectionModifier;\n\t}\n\n\toverride dispose(): void {\n\t\tthis.disposables.dispose();\n\t\tsuper.dispose();\n\t}\n}\n\nexport interface IOpenResourceOptions {\n\teditorOptions: IEditorOptions;\n\tsideBySide: boolean;\n\telement: any;\n\tpayload: any;\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\nexport function getSelectionKeyboardEvent(typeArg = 'keydown', preserveFocus?: boolean, pinned?: boolean): SelectionKeyboardEvent {\n\tconst e = new KeyboardEvent(typeArg);\n\t(e).preserveFocus = preserveFocus;\n\t(e).pinned = pinned;\n\t(e).__forceEvent = true;\n\n\treturn e;\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\tget contextKeyService(): IContextKeyService { return this.internals.contextKeyService; }\n\tget useAltAsMultipleSelectionModifier(): boolean { return this.internals.useAltAsMultipleSelectionModifier; }\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\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 accessibilityProvider: IListAccessibilityProvider;\n\treadonly selectionNavigation?: boolean;\n}\n\nexport class WorkbenchCompressibleObjectTree, TFilterData = void> extends CompressibleObjectTree {\n\n\tprivate internals: WorkbenchTreeInternals;\n\tget contextKeyService(): IContextKeyService { return this.internals.contextKeyService; }\n\tget useAltAsMultipleSelectionModifier(): boolean { return this.internals.useAltAsMultipleSelectionModifier; }\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: 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 accessibilityProvider: IListAccessibilityProvider;\n\treadonly selectionNavigation?: boolean;\n}\n\nexport class WorkbenchDataTree extends DataTree {\n\n\tprivate internals: WorkbenchTreeInternals;\n\tget contextKeyService(): IContextKeyService { return this.internals.contextKeyService; }\n\tget useAltAsMultipleSelectionModifier(): boolean { return this.internals.useAltAsMultipleSelectionModifier; }\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: 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 contextKeyService(): IContextKeyService { return this.internals.contextKeyService; }\n\tget useAltAsMultipleSelectionModifier(): boolean { return this.internals.useAltAsMultipleSelectionModifier; }\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 accessibilityProvider: IListAccessibilityProvider;\n\treadonly overrideStyles?: IStyleOverride;\n\treadonly selectionNavigation?: boolean;\n}\n\nexport class WorkbenchCompressibleAsyncDataTree extends CompressibleAsyncDataTree {\n\n\tprivate internals: WorkbenchTreeInternals;\n\tget contextKeyService(): IContextKeyService { return this.internals.contextKeyService; }\n\tget useAltAsMultipleSelectionModifier(): boolean { return this.internals.useAltAsMultipleSelectionModifier; }\n\tget onDidOpen(): Event> { return this.internals.onDidOpen; }\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\tget useAltAsMultipleSelectionModifier(): boolean {\n\t\treturn this._useAltAsMultipleSelectionModifier;\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, getCodiconFontCharacters } from 'vs/base/common/codicons';\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 * Register a icon to the registry.\n\t * @param id The icon id\n\t * @param defaults The default values\n\t * @param description The description\n\t */\n\tregisterIcon(id: IconIdentifier, defaults: IconDefaults, description?: string): ThemeIcon;\n\n\t/**\n\t * Deregister a icon from the registry.\n\t */\n\tderegisterIcon(id: IconIdentifier): void;\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\t/**\n\t * JSON schema for an object to assign icon values to one of the icon contributions.\n\t */\n\tgetIconSchema(): IJSONSchema;\n\n\t/**\n\t * JSON schema to for a reference to a icon contribution.\n\t */\n\tgetIconReferenceSchema(): IJSONSchema;\n\n\t/**\n\t * Register a icon font to the registry.\n\t * @param id The icon font id\n\t * @param definition The icon font definition\n\t */\n\tregisterIconFont(id: string, definition: IconFontDefinition): IconFontDefinition;\n\n\t/**\n\t * Deregister an icon font to the registry.\n\t */\n\tderegisterIconFont(id: string): void;\n\n\t/**\n\t * Get the icon font for the given id\n\t */\n\tgetIconFont(id: string): IconFontDefinition | 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\n\tpublic deregisterIcon(id: string): void {\n\t\tdelete this.iconsById[id];\n\t\tdelete this.iconSchema.properties[id];\n\t\tconst index = this.iconReferenceSchema.enum.indexOf(id);\n\t\tif (index !== -1) {\n\t\t\tthis.iconReferenceSchema.enum.splice(index, 1);\n\t\t\tthis.iconReferenceSchema.enumDescriptions.splice(index, 1);\n\t\t}\n\t\tthis._onDidChange.fire();\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 getIconReferenceSchema(): IJSONSchema {\n\t\treturn this.iconReferenceSchema;\n\t}\n\n\tpublic registerIconFont(id: string, definition: IconFontDefinition): IconFontDefinition {\n\t\tconst existing = this.iconFontsById[id];\n\t\tif (existing) {\n\t\t\treturn existing;\n\t\t}\n\t\tthis.iconFontsById[id] = definition;\n\t\tthis._onDidChange.fire();\n\t\treturn definition;\n\t}\n\n\tpublic deregisterIconFont(id: string): void {\n\t\tdelete this.iconFontsById[id];\n\t}\n\n\tpublic getIconFont(id: string): IconFontDefinition | undefined {\n\t\treturn this.iconFontsById[id];\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 domNode(): HTMLElement {\n\t\treturn this._domNode;\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 opacityStrip() {\n\t\treturn this._opacityStrip;\n\t}\n\n\tget hueStrip() {\n\t\treturn this._hueStrip;\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\tpublic get canvas() {\n\t\treturn this._canvas;\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\tprivate static readonly ID = 'editor.contrib.colorPickerWidget';\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\tgetId(): string {\n\t\treturn ColorPickerWidget.ID;\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 * 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';\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) {\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 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\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\t\t\tconst formatIconRule = (contribution: IconContribution): string | undefined => {\n\t\t\t\tconst definition = productIconTheme.getIcon(contribution);\n\t\t\t\tif (!definition) {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t\tconst fontContribution = definition.font;\n\t\t\t\tif (fontContribution) {\n\t\t\t\t\tusedFontIds[fontContribution.id] = fontContribution.definition;\n\t\t\t\t\treturn `.codicon-${contribution.id}:before { content: '${definition.fontCharacter}'; font-family: ${asCSSPropertyValue(fontContribution.id)}; }`;\n\t\t\t\t}\n\t\t\t\t// default font (codicon)\n\t\t\t\treturn `.codicon-${contribution.id}:before { content: '${definition.fontCharacter}'; }`;\n\t\t\t};\n\n\t\t\tconst rules = [];\n\t\t\tfor (const contribution of iconRegistry.getIcons()) {\n\t\t\t\tconst rule = formatIconRule(contribution);\n\t\t\t\tif (rule) {\n\t\t\t\t\trules.push(rule);\n\t\t\t\t}\n\t\t\t}\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\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, 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): void {\n\t\tif (this._renderedViewLine && this._renderedViewLine.domNode) {\n\t\t\tthis._renderedViewLine.domNode.setTop(deltaTop);\n\t\t\tthis._renderedViewLine.domNode.setHeight(this._options.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';\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\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\tpublic readonly target: HTMLElement | null;\n\tpublic readonly targetPath: Uint8Array;\n\n\tconstructor(ctx: HitTestContext, editorPos: EditorPagePosition, pos: PageCoordinates, relativePos: CoordinatesRelativeToEditor, target: HTMLElement | null) {\n\t\tsuper(ctx, editorPos, pos, relativePos);\n\t\tthis._ctx = ctx;\n\n\t\tif (target) {\n\t\t\tthis.target = target;\n\t\t\tthis.targetPath = PartFingerprints.collect(target, ctx.viewDomNode);\n\t\t} else {\n\t\t\tthis.target = null;\n\t\t\tthis.targetPath = new Uint8Array(0);\n\t\t}\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\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\tpublic withTarget(target: HTMLElement | null): HitTestRequest {\n\t\treturn new HitTestRequest(this._ctx, this.editorPos, this.pos, this.relativePos, target);\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, false);\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, domHitTestExecuted: boolean): IMouseTarget {\n\n\t\t// console.log(`${domHitTestExecuted ? '=>' : ''}CAME IN REQUEST: ${request}`);\n\n\t\t// First ensure the request has a target\n\t\tif (request.target === null) {\n\t\t\tif (domHitTestExecuted) {\n\t\t\t\t// Still no target... and we have already executed hit test...\n\t\t\t\treturn request.fulfillUnknown();\n\t\t\t}\n\n\t\t\tconst hitTestResult = MouseTargetFactory._doHitTest(ctx, request);\n\n\t\t\tif (hitTestResult.type === HitTestResultType.Content) {\n\t\t\t\treturn MouseTargetFactory.createMouseTargetFromHitTestPosition(ctx, request, hitTestResult.spanNode, hitTestResult.position, hitTestResult.injectedText);\n\t\t\t}\n\n\t\t\treturn this._createMouseTarget(ctx, request.withTarget(hitTestResult.hitTarget), true);\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, domHitTestExecuted);\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, domHitTestExecuted: boolean): 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\tif (domHitTestExecuted) {\n\t\t\t// Check if we are hitting a view-line (can happen in the case of inline decorations on empty lines)\n\t\t\t// See https://github.com/microsoft/vscode/issues/46942\n\t\t\tif (ElementPath.isStrictChildOfViewLines(request.targetPath)) {\n\t\t\t\tconst lineNumber = ctx.getLineNumberAtVerticalOffset(request.mouseVerticalOffset);\n\t\t\t\tif (ctx.viewModel.getLineLength(lineNumber) === 0) {\n\t\t\t\t\tconst lineWidth = ctx.getLineWidth(lineNumber);\n\t\t\t\t\tconst detail = createEmptyContentDataInLines(request.mouseContentHorizontalOffset - lineWidth);\n\t\t\t\t\treturn request.fulfillContentEmpty(new Position(lineNumber, 1), detail);\n\t\t\t\t}\n\n\t\t\t\tconst lineWidth = ctx.getLineWidth(lineNumber);\n\t\t\t\tif (request.mouseContentHorizontalOffset >= lineWidth) {\n\t\t\t\t\tconst detail = createEmptyContentDataInLines(request.mouseContentHorizontalOffset - lineWidth);\n\t\t\t\t\tconst pos = new Position(lineNumber, ctx.viewModel.getLineMaxColumn(lineNumber));\n\t\t\t\t\treturn request.fulfillContentEmpty(pos, detail);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// We have already executed hit test...\n\t\t\treturn request.fulfillUnknown();\n\t\t}\n\n\t\tconst hitTestResult = MouseTargetFactory._doHitTest(ctx, request);\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\treturn this._createMouseTarget(ctx, request.withTarget(hitTestResult.hitTarget), true);\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\tprivate 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\tprotected _onMouseWheel(e: IMouseWheelEvent): void {\n\t\tthis.viewController.emitMouseWheel(e);\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