@lvce-editor/editor-worker 9.0.0 → 10.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/editorWorkerMain.js +1093 -1001
  2. package/package.json +2 -2
@@ -1774,53 +1774,480 @@ const setDeltaY$2 = (state, value) => {
1774
1774
  };
1775
1775
  };
1776
1776
 
1777
- const splitLines = lines => {
1778
- if (!lines) {
1779
- return [''];
1777
+ const Link$1 = 'Link';
1778
+ const Function = 'Function';
1779
+ const Parameter = 'Parameter';
1780
+ const Type = 'Type';
1781
+ const VariableName = 'VariableName';
1782
+ const Class = 'Class';
1783
+
1784
+ const Link = 1;
1785
+ const Ts2816 = 2816;
1786
+ const Ts2817 = 2817;
1787
+ const Ts2824 = 2824;
1788
+ const Ts2825 = 2825;
1789
+ const Ts2856 = 2956;
1790
+ const Ts2857 = 2857;
1791
+ const Ts3072 = 3072;
1792
+ const Ts3073 = 3073;
1793
+ const Ts3077 = 3077;
1794
+ const Ts3088 = 3088;
1795
+ const Ts1792 = 1792;
1796
+ const Ts1793 = 1793;
1797
+ const Ts512 = 512;
1798
+ const Ts513 = 513;
1799
+ const Ts769 = 769;
1800
+ const Ts1024 = 1024;
1801
+ const Ts1536 = 1536;
1802
+ const Ts1537 = 1537;
1803
+ const Ts1544 = 1544;
1804
+ const Ts1545 = 1545;
1805
+ const Ts2048 = 2048;
1806
+ const Ts2049 = 2049;
1807
+ const Ts2056 = 2056;
1808
+ const Ts2057 = 2057;
1809
+ const Ts2064 = 2064;
1810
+ const Ts2080 = 2080;
1811
+ const Ts2081 = 2081;
1812
+ const Ts2088 = 2088;
1813
+ const Ts2089 = 2089;
1814
+ const Ts2313 = 2313;
1815
+ const Ts2560 = 2560;
1816
+ const Ts2561 = 2561;
1817
+ const Ts2569 = 2569;
1818
+ const Ts2584 = 2584;
1819
+ const Ts256 = 256;
1820
+ const Ts257 = 257;
1821
+ const Ts272 = 272;
1822
+
1823
+ const getDecorationClassName = type => {
1824
+ switch (type) {
1825
+ case Link:
1826
+ return Link$1;
1827
+ case Ts2816:
1828
+ case Ts2817:
1829
+ case Ts2824:
1830
+ case Ts2825:
1831
+ case Ts2856:
1832
+ case Ts2857:
1833
+ case Ts3072:
1834
+ case Ts3073:
1835
+ case Ts3077:
1836
+ case Ts3088:
1837
+ return Function;
1838
+ case Ts1792:
1839
+ case Ts1793:
1840
+ return Parameter;
1841
+ case Ts512:
1842
+ case Ts513:
1843
+ case Ts769:
1844
+ case Ts1024:
1845
+ case Ts1536:
1846
+ case Ts1537:
1847
+ case Ts1544:
1848
+ case Ts1545:
1849
+ return Type;
1850
+ case Ts2048:
1851
+ case Ts2049:
1852
+ case Ts2056:
1853
+ case Ts2057:
1854
+ case Ts2064:
1855
+ case Ts2080:
1856
+ case Ts2081:
1857
+ case Ts2088:
1858
+ case Ts2089:
1859
+ case Ts2313:
1860
+ case Ts2560:
1861
+ case Ts2561:
1862
+ case Ts2569:
1863
+ case Ts2584:
1864
+ return VariableName;
1865
+ case Ts256:
1866
+ case Ts257:
1867
+ case Ts272:
1868
+ return Class;
1869
+ default:
1870
+ return `Unknown-${type}`;
1780
1871
  }
1781
- return lines.split('\n');
1782
1872
  };
1783
1873
 
1784
- // based on https://github.com/microsoft/vscode/blob/c0769274fa136b45799edeccc0d0a2f645b75caf/src/vs/base/common/arrays.ts#L625 (License MIT)
1874
+ const deepCopy = value => {
1875
+ return structuredClone(value);
1876
+ };
1785
1877
 
1786
- // @ts-ignore
1787
- const insertInto = (array, start, newItems) => {
1788
- const originalLength = array.length;
1789
- const newItemsLength = newItems.length;
1790
- array.length = originalLength + newItemsLength;
1791
- // Move the items after the start index, start from the end so that we don't overwrite any value.
1792
- for (let i = originalLength - 1; i >= start; i--) {
1793
- array[i + newItemsLength] = array[i];
1878
+ const getInitialLineState = initialLineState => {
1879
+ return deepCopy(initialLineState);
1880
+ };
1881
+
1882
+ const state$8 = {
1883
+ warned: []
1884
+ };
1885
+ const flattenTokensArray = tokens => {
1886
+ const flattened = [];
1887
+ for (const token of tokens) {
1888
+ object(token);
1889
+ flattened.push(token.type, token.length);
1794
1890
  }
1795
- for (let i = 0; i < newItemsLength; i++) {
1796
- array[i + start] = newItems[i];
1891
+ return flattened;
1892
+ };
1893
+ const warnDeprecatedArrayReturn = (languageId, fn) => {
1894
+ if (state$8.warned.includes(fn)) {
1895
+ return;
1896
+ }
1897
+ state$8.warned.push(fn);
1898
+ console.warn(`tokenizers without hasArrayReturn=false are deprecated (language ${languageId})`);
1899
+ };
1900
+ const safeTokenizeLine = (languageId, tokenizeLine, line, lineStateAtStart, hasArrayReturn) => {
1901
+ try {
1902
+ const lineState = tokenizeLine(line, lineStateAtStart);
1903
+ if (!lineState?.tokens || !lineState.state) {
1904
+ throw new Error('invalid tokenization result');
1905
+ }
1906
+ if (!hasArrayReturn) {
1907
+ warnDeprecatedArrayReturn(languageId, tokenizeLine);
1908
+ // workaround for old tokenizers
1909
+ lineState.tokens = flattenTokensArray(lineState.tokens);
1910
+ }
1911
+ return lineState;
1912
+ } catch (error) {
1913
+ console.error(error);
1914
+ return {
1915
+ tokens: [/* type */0, /* length */line.length],
1916
+ lineState: lineStateAtStart
1917
+ };
1797
1918
  }
1798
1919
  };
1799
1920
 
1800
1921
  /**
1801
- * Alternative to the native Array.splice method, it
1802
- * can only support limited number of items due to the maximum call stack size limit.
1922
+ * @enum number
1803
1923
  */
1804
- // @ts-ignore
1805
- const spliceLargeArray = (array, start, deleteCount, newItems) => {
1806
- const result = array.splice(start, deleteCount);
1807
- insertInto(array, start, newItems);
1808
- return result;
1924
+ const State = {
1925
+ TopLevelContent: 1
1809
1926
  };
1810
1927
 
1811
- const joinLines = lines => {
1812
- return lines.join('\n');
1928
+ /**
1929
+ * @enum number
1930
+ */
1931
+ const TokenType = {
1932
+ Text: 1
1933
+ };
1934
+ const TokenMap = {
1935
+ [TokenType.Text]: 'Text'
1936
+ };
1937
+ const initialLineState = {
1938
+ state: State.TopLevelContent
1939
+ };
1940
+ const hasArrayReturn = true;
1941
+ const tokenizeLine = (line, lineState) => {
1942
+ return {
1943
+ tokens: [TokenType.Text, line.length],
1944
+ state: lineState.state
1945
+ };
1813
1946
  };
1814
1947
 
1815
- const RE_WHITESPACE = /^\s+/;
1948
+ const TokenizePlainText = {
1949
+ __proto__: null,
1950
+ State,
1951
+ TokenMap,
1952
+ TokenType,
1953
+ hasArrayReturn,
1954
+ initialLineState,
1955
+ tokenizeLine
1956
+ };
1816
1957
 
1817
- // TODO this doesn't belong here
1818
- const getIndent = line => {
1819
- const whitespaceMatch = line.match(RE_WHITESPACE);
1820
- if (!whitespaceMatch) {
1821
- return '';
1958
+ let enabled$1 = false;
1959
+ const setEnabled$1 = value => {
1960
+ enabled$1 = value;
1961
+ };
1962
+ const getEnabled$1 = () => {
1963
+ return enabled$1;
1964
+ };
1965
+
1966
+ const {
1967
+ set: set$5,
1968
+ invoke: invoke$7} = SyntaxHighlightingWorker;
1969
+
1970
+ const state$7 = {
1971
+ tokenizers: Object.create(null),
1972
+ pending: Object.create(null)};
1973
+ const has = languageId => {
1974
+ return languageId in state$7.tokenizers;
1975
+ };
1976
+ const set$4 = (languageId, tokenizer) => {
1977
+ state$7.tokenizers[languageId] = tokenizer;
1978
+ };
1979
+ const get$3 = languageId => {
1980
+ return state$7.tokenizers[languageId];
1981
+ };
1982
+ const isPending = languageId => {
1983
+ return languageId in state$7.pending;
1984
+ };
1985
+
1986
+ const tokenMaps = Object.create(null);
1987
+ const set$3 = (languageId, tokenMap) => {
1988
+ tokenMaps[languageId] = tokenMap;
1989
+ };
1990
+ const get$2 = languageId => {
1991
+ return tokenMaps[languageId] || {};
1992
+ };
1993
+
1994
+ // TODO loadTokenizer should be invoked from renderer worker
1995
+ const loadTokenizer = async (languageId, tokenizePath) => {
1996
+ if (!tokenizePath) {
1997
+ return;
1822
1998
  }
1823
- return whitespaceMatch[0];
1999
+ if (getEnabled$1()) {
2000
+ // @ts-ignore
2001
+ const tokenMap = await invoke$7('Tokenizer.load', languageId, tokenizePath);
2002
+ set$3(languageId, tokenMap);
2003
+ return;
2004
+ }
2005
+ try {
2006
+ // TODO check that tokenizer is valid
2007
+ // 1. tokenizeLine should be of type function
2008
+ // 2. getTokenClass should be of type function
2009
+ const tokenizer = await import(tokenizePath);
2010
+ if (typeof tokenizer.tokenizeLine !== 'function') {
2011
+ console.warn(`tokenizer.tokenizeLine should be a function in "${tokenizePath}"`);
2012
+ return;
2013
+ }
2014
+ if (!tokenizer.TokenMap || typeof tokenizer.TokenMap !== 'object' || Array.isArray(tokenizer.TokenMap)) {
2015
+ console.warn(`tokenizer.TokenMap should be an object in "${tokenizePath}"`);
2016
+ return;
2017
+ }
2018
+ set$3(languageId, tokenizer.TokenMap);
2019
+ set$4(languageId, tokenizer);
2020
+ } catch (error) {
2021
+ // TODO better error handling
2022
+ console.error(error);
2023
+ }
2024
+ };
2025
+ const getTokenizer = languageId => {
2026
+ if (has(languageId)) {
2027
+ return get$3(languageId);
2028
+ }
2029
+ if (isPending(languageId)) {
2030
+ return TokenizePlainText;
2031
+ }
2032
+ return TokenizePlainText;
2033
+ };
2034
+
2035
+ const tokenizers = Object.create(null);
2036
+ const set$2 = (id, value) => {
2037
+ tokenizers[id] = value;
2038
+ };
2039
+ const get$1 = id => {
2040
+ return tokenizers[id] || TokenizePlainText;
2041
+ };
2042
+
2043
+ const getTokensViewportEmbedded = (langageId, lines, lineCache, linesWithEmbed) => {
2044
+ const tokenizersToLoad = [];
2045
+ const embeddedResults = [];
2046
+ let topContext;
2047
+ for (const index of linesWithEmbed) {
2048
+ const result = lineCache[index + 1];
2049
+ const line = lines[index];
2050
+ if (result.embeddedLanguage) {
2051
+ const {
2052
+ embeddedLanguage,
2053
+ embeddedLanguageStart,
2054
+ embeddedLanguageEnd
2055
+ } = result;
2056
+ const embeddedTokenizer = getTokenizer(embeddedLanguage);
2057
+ if (embeddedLanguageStart !== line.length && embeddedTokenizer && embeddedTokenizer !== TokenizePlainText) {
2058
+ const isFull = embeddedLanguageStart === 0 && embeddedLanguageEnd === line.length;
2059
+ const partialLine = line.slice(embeddedLanguageStart, embeddedLanguageEnd);
2060
+ const embedResult = safeTokenizeLine(langageId, embeddedTokenizer.tokenizeLine, partialLine, topContext || getInitialLineState(embeddedTokenizer.initialLineState), embeddedTokenizer.hasArrayReturn);
2061
+ topContext = embedResult;
2062
+ result.embeddedResultIndex = embeddedResults.length;
2063
+ embeddedResults.push({
2064
+ result: embedResult,
2065
+ TokenMap: embeddedTokenizer.TokenMap,
2066
+ isFull
2067
+ });
2068
+ } else if (line.length === 0) {
2069
+ const embedResult = {
2070
+ tokens: []
2071
+ };
2072
+ result.embeddedResultIndex = embeddedResults.length;
2073
+ embeddedResults.push({
2074
+ result: embedResult,
2075
+ isFull: true,
2076
+ TokenMap: []
2077
+ });
2078
+ } else {
2079
+ tokenizersToLoad.push(embeddedLanguage);
2080
+ embeddedResults.push({
2081
+ result: {},
2082
+ isFull: false,
2083
+ TokenMap: []
2084
+ });
2085
+ topContext = undefined;
2086
+ }
2087
+ } else {
2088
+ topContext = undefined;
2089
+ }
2090
+ }
2091
+ return {
2092
+ tokenizersToLoad,
2093
+ embeddedResults
2094
+ };
2095
+ };
2096
+ const getTokenizeEndIndex = (invalidStartIndex, endLineIndex, tokenizeStartIndex) => {
2097
+ return invalidStartIndex < endLineIndex ? endLineIndex : tokenizeStartIndex;
2098
+ };
2099
+
2100
+ // TODO only send changed lines to renderer process instead of all lines in viewport
2101
+ const getTokensViewport = (editor, startLineIndex, endLineIndex) => {
2102
+ const {
2103
+ invalidStartIndex,
2104
+ lineCache,
2105
+ tokenizerId,
2106
+ lines,
2107
+ languageId
2108
+ } = editor;
2109
+ const tokenizer = get$1(tokenizerId);
2110
+ const {
2111
+ hasArrayReturn,
2112
+ tokenizeLine,
2113
+ initialLineState
2114
+ } = tokenizer;
2115
+ const tokenizeStartIndex = invalidStartIndex;
2116
+ const tokenizeEndIndex = getTokenizeEndIndex(invalidStartIndex, endLineIndex, tokenizeStartIndex);
2117
+ const tokenizersToLoad = [];
2118
+ const embeddedResults = [];
2119
+ const linesWithEmbed = [];
2120
+ for (let i = tokenizeStartIndex; i < tokenizeEndIndex; i++) {
2121
+ const lineState = i === 0 ? getInitialLineState(initialLineState) : lineCache[i];
2122
+ const line = lines[i];
2123
+ const result = safeTokenizeLine(languageId, tokenizeLine, line, lineState, hasArrayReturn);
2124
+ // TODO if lineCacheEnd matches the one before, skip tokenizing lines after
2125
+ lineCache[i + 1] = result;
2126
+ if (result.embeddedLanguage) {
2127
+ result.embeddedResultIndex = linesWithEmbed.length;
2128
+ linesWithEmbed.push(i);
2129
+ }
2130
+ }
2131
+ const visibleLines = lineCache.slice(startLineIndex + 1, endLineIndex + 1);
2132
+ if (linesWithEmbed.length > 0) {
2133
+ const {
2134
+ tokenizersToLoad,
2135
+ embeddedResults
2136
+ } = getTokensViewportEmbedded(languageId, lines, lineCache, linesWithEmbed);
2137
+ // TODO support lineCache with embedded content
2138
+ editor.invalidStartIndex = 0;
2139
+ return {
2140
+ tokens: visibleLines,
2141
+ tokenizersToLoad,
2142
+ embeddedResults
2143
+ };
2144
+ }
2145
+ editor.invalidStartIndex = Math.max(invalidStartIndex, tokenizeEndIndex);
2146
+ return {
2147
+ tokens: visibleLines,
2148
+ tokenizersToLoad,
2149
+ embeddedResults
2150
+ };
2151
+ };
2152
+
2153
+ const sentLines = Object.create(null);
2154
+
2155
+ // TODO only send changed lines to renderer process instead of all lines in viewport
2156
+ const getTokensViewport2 = async (editor, startLineIndex, endLineIndex, syncIncremental) => {
2157
+ if (getEnabled$1()) {
2158
+ if (syncIncremental) {
2159
+ const {
2160
+ invalidStartIndex,
2161
+ lines,
2162
+ languageId,
2163
+ id
2164
+ } = editor;
2165
+ let hasLinesToSend = true;
2166
+ let linesToSend = lines;
2167
+ if (sentLines[id] === lines) {
2168
+ hasLinesToSend = false;
2169
+ linesToSend = [];
2170
+ } else {
2171
+ sentLines[id] = lines;
2172
+ }
2173
+ const slimEditor = {
2174
+ languageId,
2175
+ invalidStartIndex
2176
+ };
2177
+ return invoke$7('GetTokensViewport.getTokensViewport', slimEditor,
2178
+ // @ts-ignore
2179
+ startLineIndex, endLineIndex, hasLinesToSend, id, linesToSend);
2180
+ }
2181
+ // TODO only send needed lines of text
2182
+ // @ts-ignore
2183
+ return invoke$7('GetTokensViewport.getTokensViewport', editor, startLineIndex, endLineIndex, true, editor.id, editor.lines);
2184
+ }
2185
+ return getTokensViewport(editor, startLineIndex, endLineIndex);
2186
+ };
2187
+
2188
+ const loadTokenizers = async languageIds => {
2189
+ for (const languageId of languageIds) {
2190
+ // @ts-ignore
2191
+ await loadTokenizer(languageId);
2192
+ }
2193
+ };
2194
+
2195
+ const EmptyString = '';
2196
+ const NewLine = '\n';
2197
+ const Space$1 = ' ';
2198
+ const Tab$1 = '\t';
2199
+ const DoubleQuote$1 = '"';
2200
+
2201
+ const normalizeText = (text, normalize, tabSize) => {
2202
+ if (normalize) {
2203
+ return text.replaceAll(Tab$1, Space$1.repeat(tabSize));
2204
+ }
2205
+ return text;
2206
+ };
2207
+ const shouldNormalizeText = text => {
2208
+ return text.includes(Tab$1);
2209
+ };
2210
+
2211
+ // based on https://github.com/microsoft/vscode/blob/c0769274fa136b45799edeccc0d0a2f645b75caf/src/vs/base/common/arrays.ts#L625 (License MIT)
2212
+
2213
+ // @ts-ignore
2214
+ const insertInto = (array, start, newItems) => {
2215
+ const originalLength = array.length;
2216
+ const newItemsLength = newItems.length;
2217
+ array.length = originalLength + newItemsLength;
2218
+ // Move the items after the start index, start from the end so that we don't overwrite any value.
2219
+ for (let i = originalLength - 1; i >= start; i--) {
2220
+ array[i + newItemsLength] = array[i];
2221
+ }
2222
+ for (let i = 0; i < newItemsLength; i++) {
2223
+ array[i + start] = newItems[i];
2224
+ }
2225
+ };
2226
+
2227
+ /**
2228
+ * Alternative to the native Array.splice method, it
2229
+ * can only support limited number of items due to the maximum call stack size limit.
2230
+ */
2231
+ // @ts-ignore
2232
+ const spliceLargeArray = (array, start, deleteCount, newItems) => {
2233
+ const result = array.splice(start, deleteCount);
2234
+ insertInto(array, start, newItems);
2235
+ return result;
2236
+ };
2237
+
2238
+ const joinLines = lines => {
2239
+ return lines.join('\n');
2240
+ };
2241
+
2242
+ const RE_WHITESPACE = /^\s+/;
2243
+
2244
+ // TODO this doesn't belong here
2245
+ const getIndent = line => {
2246
+ const whitespaceMatch = line.match(RE_WHITESPACE);
2247
+ if (!whitespaceMatch) {
2248
+ return '';
2249
+ }
2250
+ return whitespaceMatch[0];
1824
2251
  };
1825
2252
 
1826
2253
  // TODO have function for single edit (most common, avoid one array)
@@ -1966,114 +2393,385 @@ const positionAt = (textDocument, offset) => {
1966
2393
  };
1967
2394
  };
1968
2395
 
1969
- const getSelectionPairs = (selections, i) => {
1970
- const first = selections[i];
1971
- const second = selections[i + 1];
1972
- const third = selections[i + 2];
1973
- const fourth = selections[i + 3];
1974
- if (first > third || first === third && second >= fourth) {
1975
- return [third, fourth, first, second, 1];
1976
- }
1977
- return [first, second, third, fourth, 0];
1978
- };
1979
-
1980
- const EmptyString = '';
1981
- const NewLine = '\n';
1982
- const Space$1 = ' ';
1983
- const Tab$1 = '\t';
1984
- const DoubleQuote$1 = '"';
2396
+ // const getTokensIncremental = (editor, min, max) => {
2397
+ // const currentLength = editor.lineStateCache.length
2398
+ // const tokens = []
2399
+ // const lines = editor.lines
2400
+ // let lineState = editor.tokenizer.initialLineState
2401
+ // for (let i = currentLength; i < max; i++) {
2402
+ // const line = lines[i]
2403
+ // try {
2404
+ // lineState = editor.tokenizer.tokenizeLine(line, lineState)
2405
+ // if (!lineState || !lineState.tokens || !lineState.state) {
2406
+ // throw new Error('invalid tokenization result')
2407
+ // }
2408
+ // } catch (error) {
2409
+ // tokens.push([{ length: line.length, type: 0 }])
2410
+ // console.error(error)
2411
+ // // renderWithoutSyntaxHighlighting(state, firstRow, lastRow)
2412
+ // continue
2413
+ // }
2414
+ // const newTokens = lineState.tokens
2415
+ // tokens.push(newTokens)
2416
+ // }
2417
+ // return tokens
2418
+ // }
1985
2419
 
1986
- const getTabCount = string => {
1987
- let count = 0;
1988
- for (const element of string) {
1989
- if (element === Tab$1) {
1990
- count++;
2420
+ // const getLineInfosIncremental = (editor, tokens, minLineY, maxLineY) => {
2421
+ // const result = []
2422
+ // const lines = editor.lines
2423
+ // const TokenMap = editor.tokenizer.TokenMap
2424
+ // for (let i = minLineY; i < maxLineY; i++) {
2425
+ // result.push(getLineInfo(lines[i], tokens[i], TokenMap))
2426
+ // }
2427
+ // return result
2428
+ // }
2429
+
2430
+ const getStartDefaults = (tokens, minOffset) => {
2431
+ let start = 0;
2432
+ let end = 0;
2433
+ let startIndex = 0;
2434
+ const tokensLength = tokens.length;
2435
+ for (let i = 0; i < tokensLength; i += 2) {
2436
+ const tokenLength = tokens[i + 1];
2437
+ end += tokenLength;
2438
+ start = end;
2439
+ if (start >= minOffset) {
2440
+ start -= tokenLength;
2441
+ end -= tokenLength;
2442
+ startIndex = i;
2443
+ break;
1991
2444
  }
1992
2445
  }
1993
- return count;
1994
- };
1995
-
1996
- const measureTextWidthFast = (text, charWidth) => {
1997
- return text.length * charWidth;
1998
- };
1999
-
2000
- const getFontString = (fontWeight, fontSize, fontFamily) => {
2001
- return `${fontWeight} ${fontSize}px ${fontFamily}`;
2002
- };
2003
-
2004
- const getLetterSpacingString = letterSpacing => {
2005
- return `${letterSpacing}px`;
2446
+ return {
2447
+ start,
2448
+ end,
2449
+ startIndex
2450
+ };
2006
2451
  };
2007
-
2008
- const createMeasureContext = () => {
2009
- const canvas = new OffscreenCanvas(0, 0);
2010
- const ctx = /** @type {OffscreenCanvasRenderingContext2D} */canvas.getContext('2d');
2011
- if (!ctx) {
2012
- throw new Error('Failed to get canvas context 2d');
2452
+ const getLineInfoEmbeddedFull = (embeddedResults, tokenResults, line, normalize, tabSize, width, deltaX, averageCharWidth, minOffset, maxOffset) => {
2453
+ const lineInfo = [];
2454
+ const embeddedResult = embeddedResults[tokenResults.embeddedResultIndex];
2455
+ const embeddedTokens = embeddedResult.result.tokens;
2456
+ const embeddedTokenMap = embeddedResult.TokenMap;
2457
+ const tokensLength = embeddedTokens.length;
2458
+ let {
2459
+ startIndex,
2460
+ start,
2461
+ end
2462
+ } = getStartDefaults(embeddedTokens, minOffset);
2463
+ const difference = getDifference(start, averageCharWidth, deltaX);
2464
+ for (let i = startIndex; i < tokensLength; i += 2) {
2465
+ const tokenType = embeddedTokens[i];
2466
+ const tokenLength = embeddedTokens[i + 1];
2467
+ end += tokenLength;
2468
+ const className = `Token ${embeddedTokenMap[tokenType] || 'Unknown'}`;
2469
+ const text = line.slice(start, end);
2470
+ const normalizedText = normalizeText(text, normalize, tabSize);
2471
+ lineInfo.push(normalizedText, className);
2472
+ start = end;
2473
+ if (end >= maxOffset) {
2474
+ break;
2475
+ }
2013
2476
  }
2014
- return ctx;
2015
- };
2016
-
2017
- const state$8 = {
2018
- ctx: undefined
2477
+ return {
2478
+ lineInfo,
2479
+ difference
2480
+ };
2019
2481
  };
2020
- const getOrCreate$4 = createCtx => {
2021
- if (state$8.ctx) {
2022
- return state$8.ctx;
2482
+ const getOffsets = (deltaX, width, averageCharWidth) => {
2483
+ // TODO accurately measure char widths using offscreen canvas
2484
+ // and use fast measurements for monospace ascii text
2485
+ if (deltaX === 0) {
2486
+ return {
2487
+ minOffset: 0,
2488
+ maxOffset: Math.ceil(width / averageCharWidth)
2489
+ };
2023
2490
  }
2024
- state$8.ctx = createCtx();
2025
- return state$8.ctx;
2491
+ const minOffset = Math.ceil(deltaX / averageCharWidth);
2492
+ const maxOffset = minOffset + Math.ceil(width / averageCharWidth);
2493
+ return {
2494
+ minOffset,
2495
+ maxOffset
2496
+ };
2026
2497
  };
2027
-
2028
- const getContext = () => {
2029
- const ctx = getOrCreate$4(createMeasureContext);
2030
- return ctx;
2498
+ const getDifference = (start, averageCharWidth, deltaX) => {
2499
+ const beforeWidth = start * averageCharWidth;
2500
+ const difference = beforeWidth - deltaX;
2501
+ return difference;
2031
2502
  };
2032
-
2033
- // TODO for text editor, could dispose measuring canvas after editor has been initialized to free up offscreencanvas space
2034
-
2035
- const measureTextWidthSlow = (text, fontWeight, fontSize, fontFamily, letterSpacing, isMonoSpaceFont, charWidth) => {
2036
- string(text);
2037
- number(fontWeight);
2038
- number(fontSize);
2039
- string(fontFamily);
2040
- boolean(isMonoSpaceFont);
2041
- number(charWidth);
2042
- if (typeof letterSpacing !== 'number') {
2043
- throw new TypeError('letterSpacing must be of type number');
2503
+ const getLineInfoDefault = (line, tokenResults, embeddedResults, decorations, TokenMap, lineOffset, normalize, tabSize, width, deltaX, averageCharWidth, minOffset, maxOffset) => {
2504
+ const lineInfo = [];
2505
+ let decorationIndex = 0;
2506
+ for (; decorationIndex < decorations.length; decorationIndex += 3) {
2507
+ const decorationOffset = decorations[decorationIndex];
2508
+ if (decorationOffset >= lineOffset) {
2509
+ break;
2510
+ }
2044
2511
  }
2045
- const letterSpacingString = getLetterSpacingString(letterSpacing);
2046
- const fontString = getFontString(fontWeight, fontSize, fontFamily);
2047
- const ctx = getContext();
2048
- ctx.letterSpacing = letterSpacingString;
2049
- ctx.font = fontString;
2050
- const metrics = ctx.measureText(text);
2051
2512
  const {
2052
- width
2053
- } = metrics;
2054
- return width;
2513
+ tokens
2514
+ } = tokenResults;
2515
+ let {
2516
+ startIndex,
2517
+ start,
2518
+ end
2519
+ } = getStartDefaults(tokens, minOffset);
2520
+ const difference = getDifference(start, averageCharWidth, deltaX);
2521
+ const tokensLength = tokens.length;
2522
+ for (let i = startIndex; i < tokensLength; i += 2) {
2523
+ const tokenType = tokens[i];
2524
+ const tokenLength = tokens[i + 1];
2525
+ const decorationOffset = decorations[decorationIndex];
2526
+ let extraClassName = '';
2527
+ if (decorationOffset !== undefined && decorationOffset - lineOffset === start) {
2528
+ // @ts-ignore
2529
+ decorations[++decorationIndex];
2530
+ const decorationType = decorations[++decorationIndex];
2531
+ // @ts-ignore
2532
+ decorations[++decorationIndex];
2533
+ // decorationIndex,
2534
+ // decorationLength,
2535
+ // decorationType,
2536
+ // decorationModifiers,
2537
+ // })
2538
+ extraClassName = getDecorationClassName(decorationType);
2539
+ }
2540
+ end += tokenLength;
2541
+ const text = line.slice(start, end);
2542
+ const className = `Token ${extraClassName || TokenMap[tokenType] || 'Unknown'}`;
2543
+ const normalizedText = normalizeText(text, normalize, tabSize);
2544
+ lineInfo.push(normalizedText, className);
2545
+ start = end;
2546
+ if (end >= maxOffset) {
2547
+ break;
2548
+ }
2549
+ }
2550
+ return {
2551
+ lineInfo,
2552
+ difference
2553
+ };
2055
2554
  };
2056
-
2057
- const measureTextWidth = (text, fontWeight, fontSize, fontFamily, letterSpacing, isMonoSpaceFont, charWidth) => {
2058
- if (isMonoSpaceFont) {
2059
- return measureTextWidthFast(text, charWidth);
2555
+ const getLineInfo$1 = (line, tokenResults, embeddedResults, decorations, TokenMap, lineOffset, normalize, tabSize, width, deltaX, averageCharWidth) => {
2556
+ const {
2557
+ minOffset,
2558
+ maxOffset
2559
+ } = getOffsets(deltaX, width, averageCharWidth);
2560
+ if (embeddedResults.length > 0 && tokenResults.embeddedResultIndex !== undefined) {
2561
+ const embeddedResult = embeddedResults[tokenResults.embeddedResultIndex];
2562
+ if (embeddedResult?.isFull) {
2563
+ return getLineInfoEmbeddedFull(embeddedResults, tokenResults, line, normalize, tabSize, width, deltaX, averageCharWidth, minOffset, maxOffset);
2564
+ }
2060
2565
  }
2061
- return measureTextWidthSlow(text, fontWeight, fontSize, fontFamily, letterSpacing, isMonoSpaceFont, charWidth);
2566
+ return getLineInfoDefault(line, tokenResults, embeddedResults, decorations, TokenMap, lineOffset, normalize, tabSize, width, deltaX, averageCharWidth, minOffset, maxOffset);
2062
2567
  };
2063
2568
 
2064
- const normalizeText = (text, normalize, tabSize) => {
2065
- if (normalize) {
2066
- return text.replaceAll(Tab$1, Space$1.repeat(tabSize));
2569
+ // TODO need lots of tests for this
2570
+ const getLineInfosViewport = (editor, tokens, embeddedResults, minLineY, maxLineY, minLineOffset, width, deltaX, averageCharWidth) => {
2571
+ const result = [];
2572
+ const differences = [];
2573
+ const {
2574
+ lines,
2575
+ decorations,
2576
+ languageId
2577
+ } = editor;
2578
+ const tokenMap = get$2(languageId);
2579
+ let offset = minLineOffset;
2580
+ const tabSize = 2;
2581
+ for (let i = minLineY; i < maxLineY; i++) {
2582
+ const line = lines[i];
2583
+ const normalize = shouldNormalizeText(line);
2584
+ const {
2585
+ lineInfo,
2586
+ difference
2587
+ } = getLineInfo$1(line, tokens[i - minLineY], embeddedResults, decorations, tokenMap, offset, normalize, tabSize, width, deltaX, averageCharWidth);
2588
+ result.push(lineInfo);
2589
+ differences.push(difference);
2590
+ offset += line.length + 1;
2067
2591
  }
2068
- return text;
2592
+ return {
2593
+ result,
2594
+ differences
2595
+ };
2069
2596
  };
2070
- const shouldNormalizeText = text => {
2071
- return text.includes(Tab$1);
2597
+ const getVisible$1 = async (editor, syncIncremental) => {
2598
+ // TODO should separate rendering from business logic somehow
2599
+ // currently hard to test because need to mock editor height, top, left,
2600
+ // invalidStartIndex, lineCache, etc. just for testing editorType
2601
+ // editor.invalidStartIndex = changes[0].start.rowIndex
2602
+ // @ts-ignore
2603
+ const {
2604
+ minLineY,
2605
+ numberOfVisibleLines,
2606
+ lines,
2607
+ width,
2608
+ deltaX,
2609
+ charWidth
2610
+ } = editor;
2611
+ const maxLineY = Math.min(minLineY + numberOfVisibleLines, lines.length);
2612
+ // @ts-ignore
2613
+ const {
2614
+ tokens,
2615
+ tokenizersToLoad,
2616
+ embeddedResults
2617
+ } = await getTokensViewport2(editor, minLineY, maxLineY, syncIncremental);
2618
+ const minLineOffset = offsetAtSync(editor, minLineY, 0);
2619
+ const averageCharWidth = charWidth;
2620
+ const {
2621
+ result,
2622
+ differences
2623
+ } = getLineInfosViewport(editor, tokens, embeddedResults, minLineY, maxLineY, minLineOffset, width, deltaX, averageCharWidth);
2624
+ if (tokenizersToLoad.length > 0) {
2625
+ loadTokenizers(tokenizersToLoad);
2626
+ }
2627
+ return {
2628
+ textInfos: result,
2629
+ differences
2630
+ };
2072
2631
  };
2073
2632
 
2074
- const getX = (line, column, fontWeight, fontSize, fontFamily, isMonospaceFont, letterSpacing, tabSize, halfCursorWidth, width, averageCharWidth, difference = 0) => {
2075
- if (!line) {
2076
- return 0;
2633
+ const emptyIncrementalEdits = [];
2634
+
2635
+ const getIncrementalEdits = async (oldState, newState) => {
2636
+ if (!newState.undoStack) {
2637
+ return emptyIncrementalEdits;
2638
+ }
2639
+ if (oldState.undoStack === newState.undoStack) {
2640
+ return emptyIncrementalEdits;
2641
+ }
2642
+ const lastChanges = newState.undoStack.at(-1);
2643
+ if (lastChanges && lastChanges.length === 1) {
2644
+ const lastChange = lastChanges[0];
2645
+ if (lastChange.origin === EditorType) {
2646
+ const {
2647
+ rowIndex
2648
+ } = lastChange.start;
2649
+ const {
2650
+ lines
2651
+ } = newState;
2652
+ const oldLine = oldState.lines[rowIndex];
2653
+ const newLine = lines[rowIndex];
2654
+ // @ts-ignore
2655
+ const incrementalEdits = await invoke$7(
2656
+ // @ts-ignore
2657
+ 'TokenizeIncremental.tokenizeIncremental', newState.uid,
2658
+ // @ts-ignore
2659
+ newState.languageId, oldLine, newLine, rowIndex, newState.minLineY);
2660
+ if (incrementalEdits && incrementalEdits.length === 1) {
2661
+ return incrementalEdits;
2662
+ }
2663
+ }
2664
+ }
2665
+ return emptyIncrementalEdits;
2666
+ };
2667
+
2668
+ const splitLines = lines => {
2669
+ if (!lines) {
2670
+ return [''];
2671
+ }
2672
+ return lines.split('\n');
2673
+ };
2674
+
2675
+ let enabled = false;
2676
+ const setEnabled = value => {
2677
+ enabled = value;
2678
+ };
2679
+ const getEnabled = () => {
2680
+ return enabled;
2681
+ };
2682
+
2683
+ const getSelectionPairs = (selections, i) => {
2684
+ const first = selections[i];
2685
+ const second = selections[i + 1];
2686
+ const third = selections[i + 2];
2687
+ const fourth = selections[i + 3];
2688
+ if (first > third || first === third && second >= fourth) {
2689
+ return [third, fourth, first, second, 1];
2690
+ }
2691
+ return [first, second, third, fourth, 0];
2692
+ };
2693
+
2694
+ const getTabCount = string => {
2695
+ let count = 0;
2696
+ for (const element of string) {
2697
+ if (element === Tab$1) {
2698
+ count++;
2699
+ }
2700
+ }
2701
+ return count;
2702
+ };
2703
+
2704
+ const measureTextWidthFast = (text, charWidth) => {
2705
+ return text.length * charWidth;
2706
+ };
2707
+
2708
+ const getFontString = (fontWeight, fontSize, fontFamily) => {
2709
+ return `${fontWeight} ${fontSize}px ${fontFamily}`;
2710
+ };
2711
+
2712
+ const getLetterSpacingString = letterSpacing => {
2713
+ return `${letterSpacing}px`;
2714
+ };
2715
+
2716
+ const createMeasureContext = () => {
2717
+ const canvas = new OffscreenCanvas(0, 0);
2718
+ const ctx = /** @type {OffscreenCanvasRenderingContext2D} */canvas.getContext('2d');
2719
+ if (!ctx) {
2720
+ throw new Error('Failed to get canvas context 2d');
2721
+ }
2722
+ return ctx;
2723
+ };
2724
+
2725
+ const state$6 = {
2726
+ ctx: undefined
2727
+ };
2728
+ const getOrCreate$4 = createCtx => {
2729
+ if (state$6.ctx) {
2730
+ return state$6.ctx;
2731
+ }
2732
+ state$6.ctx = createCtx();
2733
+ return state$6.ctx;
2734
+ };
2735
+
2736
+ const getContext = () => {
2737
+ const ctx = getOrCreate$4(createMeasureContext);
2738
+ return ctx;
2739
+ };
2740
+
2741
+ // TODO for text editor, could dispose measuring canvas after editor has been initialized to free up offscreencanvas space
2742
+
2743
+ const measureTextWidthSlow = (text, fontWeight, fontSize, fontFamily, letterSpacing, isMonoSpaceFont, charWidth) => {
2744
+ string(text);
2745
+ number(fontWeight);
2746
+ number(fontSize);
2747
+ string(fontFamily);
2748
+ boolean(isMonoSpaceFont);
2749
+ number(charWidth);
2750
+ if (typeof letterSpacing !== 'number') {
2751
+ throw new TypeError('letterSpacing must be of type number');
2752
+ }
2753
+ const letterSpacingString = getLetterSpacingString(letterSpacing);
2754
+ const fontString = getFontString(fontWeight, fontSize, fontFamily);
2755
+ const ctx = getContext();
2756
+ ctx.letterSpacing = letterSpacingString;
2757
+ ctx.font = fontString;
2758
+ const metrics = ctx.measureText(text);
2759
+ const {
2760
+ width
2761
+ } = metrics;
2762
+ return width;
2763
+ };
2764
+
2765
+ const measureTextWidth = (text, fontWeight, fontSize, fontFamily, letterSpacing, isMonoSpaceFont, charWidth) => {
2766
+ if (isMonoSpaceFont) {
2767
+ return measureTextWidthFast(text, charWidth);
2768
+ }
2769
+ return measureTextWidthSlow(text, fontWeight, fontSize, fontFamily, letterSpacing, isMonoSpaceFont, charWidth);
2770
+ };
2771
+
2772
+ const getX = (line, column, fontWeight, fontSize, fontFamily, isMonospaceFont, letterSpacing, tabSize, halfCursorWidth, width, averageCharWidth, difference = 0) => {
2773
+ if (!line) {
2774
+ return 0;
2077
2775
  }
2078
2776
  string(line);
2079
2777
  number(tabSize);
@@ -2210,7 +2908,7 @@ const getSelectionArray = visibleSelections => {
2210
2908
  }
2211
2909
  return selectionsArray;
2212
2910
  };
2213
- const getVisible$1 = editor => {
2911
+ const getVisible = editor => {
2214
2912
  const visibleCursors = [];
2215
2913
  const visibleSelections = [];
2216
2914
  // // TODO binary search
@@ -2428,15 +3126,29 @@ const scheduleDocumentAndCursorsSelections = async (editor, changes, selectionCh
2428
3126
  autoClosingRanges
2429
3127
  };
2430
3128
  set$6(editor.uid, editor, newEditor);
3129
+ const incrementalEdits = await getIncrementalEdits(editor, newEditor);
2431
3130
  const newWidgets = await applyWidgetChanges(newEditor, changes);
2432
3131
  const newEditor2 = {
2433
3132
  ...newEditor,
2434
- widgets: newWidgets
3133
+ widgets: newWidgets,
3134
+ incrementalEdits
3135
+ };
3136
+ if (incrementalEdits !== emptyIncrementalEdits) {
3137
+ return newEditor2;
3138
+ }
3139
+ const syncIncremental = getEnabled();
3140
+ const {
3141
+ textInfos,
3142
+ differences
3143
+ } = await getVisible$1(newEditor2, syncIncremental);
3144
+ return {
3145
+ ...newEditor2,
3146
+ textInfos,
3147
+ differences
2435
3148
  };
2436
- return newEditor2;
2437
3149
  };
2438
3150
  // @ts-ignore
2439
- const scheduleDocumentAndCursorsSelectionIsUndo = (editor, changes) => {
3151
+ const scheduleDocumentAndCursorsSelectionIsUndo = async (editor, changes) => {
2440
3152
  object(editor);
2441
3153
  array(changes);
2442
3154
  if (changes.length === 0) {
@@ -2456,7 +3168,26 @@ const scheduleDocumentAndCursorsSelectionIsUndo = (editor, changes) => {
2456
3168
  // undoStack: [...editor.undoStack.slice(0, -2)],
2457
3169
  invalidStartIndex
2458
3170
  };
2459
- return newEditor;
3171
+ const incrementalEdits = await getIncrementalEdits(editor, newEditor);
3172
+
3173
+ // TODO change event should be emitted after rendering
3174
+ const finalEditor = {
3175
+ ...newEditor,
3176
+ incrementalEdits
3177
+ };
3178
+ if (incrementalEdits !== emptyIncrementalEdits) {
3179
+ return finalEditor;
3180
+ }
3181
+ const syncIncremental = getEnabled();
3182
+ const {
3183
+ textInfos,
3184
+ differences
3185
+ } = await getVisible$1(finalEditor, syncIncremental);
3186
+ return {
3187
+ ...finalEditor,
3188
+ textInfos,
3189
+ differences
3190
+ };
2460
3191
  };
2461
3192
 
2462
3193
  // @ts-ignore
@@ -2481,8 +3212,26 @@ const scheduleDocument = async (editor, changes) => {
2481
3212
  lines: newLines,
2482
3213
  invalidStartIndex
2483
3214
  };
3215
+ const incrementalEdits = await getIncrementalEdits(editor, newEditor);
3216
+
2484
3217
  // TODO change event should be emitted after rendering
2485
- return newEditor;
3218
+ const finalEditor = {
3219
+ ...newEditor,
3220
+ incrementalEdits
3221
+ };
3222
+ if (incrementalEdits !== emptyIncrementalEdits) {
3223
+ return finalEditor;
3224
+ }
3225
+ const syncIncremental = getEnabled();
3226
+ const {
3227
+ textInfos,
3228
+ differences
3229
+ } = await getVisible$1(finalEditor, syncIncremental);
3230
+ return {
3231
+ ...finalEditor,
3232
+ textInfos,
3233
+ differences
3234
+ };
2486
3235
  // RendererProcess.send([
2487
3236
  // /* Viewlet.invoke */ 'Viewlet.send',
2488
3237
  // /* id */ 'EditorText',
@@ -2548,8 +3297,8 @@ const TabCompletionExecuteTabCompletionProvider = 'ExtensionHost.executeTabCompl
2548
3297
  const TextDocumentSyncFull = 'ExtensionHostTextDocument.syncFull';
2549
3298
 
2550
3299
  const {
2551
- set: set$5,
2552
- invoke: invoke$7} = ExtensionHost;
3300
+ set: set$1,
3301
+ invoke: invoke$6} = ExtensionHost;
2553
3302
 
2554
3303
  const ColorPicker = 41;
2555
3304
  const EditorCompletion = 9;
@@ -2578,7 +3327,7 @@ const execute = async ({
2578
3327
  }) => {
2579
3328
  const fullEvent = `${event}:${editor.languageId}`;
2580
3329
  await activateByEvent(fullEvent);
2581
- const result = await invoke$7(method, editor.uid, ...args);
3330
+ const result = await invoke$6(method, editor.uid, ...args);
2582
3331
  return result;
2583
3332
  };
2584
3333
 
@@ -2646,7 +3395,7 @@ const updateDiagnostics = async newState => {
2646
3395
  // TODO don't really need text document sync response
2647
3396
  // could perhaps save a lot of messages by using send instead of invoke
2648
3397
  // @ts-ignore
2649
- await invoke$7(TextDocumentSyncFull, newState.uri, newState.id, newState.languageId, content);
3398
+ await invoke$6(TextDocumentSyncFull, newState.uri, newState.id, newState.languageId, content);
2650
3399
  const diagnostics = await executeDiagnosticProvider(newState);
2651
3400
  const latest = get$4(newState.id);
2652
3401
  if (!latest) {
@@ -2672,6 +3421,8 @@ const updateDiagnostics = async newState => {
2672
3421
  };
2673
3422
 
2674
3423
  const emptyEditor = {
3424
+ textInfos: [],
3425
+ differences: [],
2675
3426
  uri: '',
2676
3427
  languageId: '',
2677
3428
  // TODO use numeric language id?
@@ -2695,7 +3446,8 @@ const emptyEditor = {
2695
3446
  selections: new Uint32Array(),
2696
3447
  diagnostics: [],
2697
3448
  highlightedLine: -1,
2698
- debugEnabled: false
3449
+ debugEnabled: false,
3450
+ incrementalEdits: emptyIncrementalEdits
2699
3451
  };
2700
3452
  const createEditor = async ({
2701
3453
  id,
@@ -2732,6 +3484,7 @@ const createEditor = async ({
2732
3484
  string(content);
2733
3485
  const charWidth = measureCharacterWidth(fontWeight, fontSize, fontFamily, letterSpacing);
2734
3486
  const editor = {
3487
+ textInfos: [],
2735
3488
  uri,
2736
3489
  isAutoClosingBracketsEnabled,
2737
3490
  isAutoClosingTagsEnabled,
@@ -2787,7 +3540,8 @@ const createEditor = async ({
2787
3540
  id,
2788
3541
  widgets: [],
2789
3542
  focusKey: Empty,
2790
- diagnosticsEnabled
3543
+ diagnosticsEnabled,
3544
+ incrementalEdits: emptyIncrementalEdits
2791
3545
  };
2792
3546
  // TODO avoid creating intermediate editors here
2793
3547
  const newEditor1 = setBounds(editor, x, y, width, height, 9);
@@ -2800,13 +3554,23 @@ const createEditor = async ({
2800
3554
  } else {
2801
3555
  newEditor3 = setDeltaY$2(newEditor2, 0);
2802
3556
  }
3557
+ const syncIncremental = getEnabled();
3558
+ const {
3559
+ textInfos,
3560
+ differences
3561
+ } = await getVisible$1(newEditor3, syncIncremental);
2803
3562
  const newEditor4 = {
2804
3563
  ...newEditor3,
2805
- focused: true
3564
+ focused: true,
3565
+ textInfos,
3566
+ differences
2806
3567
  };
2807
3568
  set$6(id, emptyEditor, newEditor4);
3569
+
3570
+ // TODO only sync when needed
3571
+ // e.g. it might not always be necessary to send text to extension host worker
2808
3572
  // @ts-ignore
2809
- await invoke$7(TextDocumentSyncFull, uri, id, languageId, content);
3573
+ await invoke$6(TextDocumentSyncFull, uri, id, languageId, content);
2810
3574
  if (diagnosticsEnabled) {
2811
3575
  updateDiagnostics(newEditor4);
2812
3576
  }
@@ -3180,7 +3944,7 @@ const y = (editor, rowIndex) => {
3180
3944
  return offsetY;
3181
3945
  };
3182
3946
 
3183
- const state$7 = {
3947
+ const state$5 = {
3184
3948
  timeout: -1
3185
3949
  };
3186
3950
 
@@ -3211,7 +3975,7 @@ const editorShowMessage = async (editor, rowIndex, columnIndex, message, isError
3211
3975
 
3212
3976
  // TODO use wrapper timing module instead of this
3213
3977
  // @ts-ignore
3214
- state$7.timeout = setTimeout(handleTimeout, 3000);
3978
+ state$5.timeout = setTimeout(handleTimeout, 3000);
3215
3979
  }
3216
3980
  return editor;
3217
3981
  };
@@ -3231,8 +3995,8 @@ const showErrorMessage = async (editor, rowIndex, columnIndex, message) => {
3231
3995
 
3232
3996
  // @ts-ignore
3233
3997
  const editorHideMessage = async editor => {
3234
- clearTimeout(state$7.timeout);
3235
- state$7.timeout = -1;
3998
+ clearTimeout(state$5.timeout);
3999
+ state$5.timeout = -1;
3236
4000
  // await RendererProcess.invoke(/* Viewlet.send */ 'Viewlet.send', /* id */ editor.uid, /* method */ 'hideOverlayMessage')
3237
4001
  return editor;
3238
4002
  };
@@ -3357,7 +4121,7 @@ const getOrCreate$3 = () => {
3357
4121
  }
3358
4122
  return workerPromise$3;
3359
4123
  };
3360
- const invoke$6 = async (method, ...params) => {
4124
+ const invoke$5 = async (method, ...params) => {
3361
4125
  const worker = await getOrCreate$3();
3362
4126
  return await worker.invoke(method, ...params);
3363
4127
  };
@@ -3376,7 +4140,7 @@ const closeRename = async editor => {
3376
4140
  return editor;
3377
4141
  }
3378
4142
  const renameWidget = widgets[renameWidgetIndex];
3379
- await invoke$6('Rename.close', renameWidget.newState.uid);
4143
+ await invoke$5('Rename.close', renameWidget.newState.uid);
3380
4144
  const latest = get$4(uid);
3381
4145
  const {
3382
4146
  newState
@@ -3495,12 +4259,12 @@ const openColorPicker = async editor => {
3495
4259
  return addWidgetToEditor(ColorPicker$1, ColorPicker, editor, create$6, newStateGenerator$6);
3496
4260
  };
3497
4261
 
3498
- const state$6 = {
4262
+ const state$4 = {
3499
4263
  isComposing: false,
3500
4264
  compositionText: ''
3501
4265
  };
3502
4266
  const compositionStart = (editor, event) => {
3503
- state$6.isComposing = true;
4267
+ state$4.isComposing = true;
3504
4268
  return editor;
3505
4269
  };
3506
4270
  const getCompositionChanges = (selections, data) => {
@@ -3510,7 +4274,7 @@ const getCompositionChanges = (selections, data) => {
3510
4274
  const selectionStartColumn = selections[i + 1];
3511
4275
  const selectionEndRow = selections[i + 2];
3512
4276
  const selectionEndColumn = selections[i + 3];
3513
- const startColumnIndex = selectionStartColumn - state$6.compositionText.length;
4277
+ const startColumnIndex = selectionStartColumn - state$4.compositionText.length;
3514
4278
  changes.push({
3515
4279
  start: {
3516
4280
  rowIndex: selectionStartRow,
@@ -3521,7 +4285,7 @@ const getCompositionChanges = (selections, data) => {
3521
4285
  columnIndex: selectionEndColumn
3522
4286
  },
3523
4287
  inserted: [data],
3524
- deleted: [state$6.compositionText],
4288
+ deleted: [state$4.compositionText],
3525
4289
  origin: CompositionUpdate
3526
4290
  });
3527
4291
  }
@@ -3532,7 +4296,7 @@ const compositionUpdate = (editor, data) => {
3532
4296
  selections
3533
4297
  } = editor;
3534
4298
  const changes = getCompositionChanges(selections, data);
3535
- state$6.compositionText = data;
4299
+ state$4.compositionText = data;
3536
4300
  return scheduleDocumentAndCursorsSelections(editor, changes);
3537
4301
  };
3538
4302
  const compositionEnd = (editor, data) => {
@@ -3540,8 +4304,8 @@ const compositionEnd = (editor, data) => {
3540
4304
  selections
3541
4305
  } = editor;
3542
4306
  const changes = getCompositionChanges(selections, data);
3543
- state$6.isComposing = false;
3544
- state$6.compositionText = '';
4307
+ state$4.isComposing = false;
4308
+ state$4.compositionText = '';
3545
4309
  return scheduleDocumentAndCursorsSelections(editor, changes);
3546
4310
  };
3547
4311
 
@@ -4616,19 +5380,19 @@ const Single = 1;
4616
5380
  const Double = 2;
4617
5381
  const Triple = 3;
4618
5382
 
4619
- const state$5 = {
5383
+ const state$3 = {
4620
5384
  position: {
4621
5385
  rowIndex: 0,
4622
5386
  columnIndex: 0
4623
5387
  }
4624
5388
  };
4625
5389
  const getPosition$1 = () => {
4626
- return state$5.position;
5390
+ return state$3.position;
4627
5391
  };
4628
5392
 
4629
5393
  // @ts-ignore
4630
5394
  const setPosition$1 = position => {
4631
- state$5.position = position;
5395
+ state$3.position = position;
4632
5396
  };
4633
5397
 
4634
5398
  // TODO first change cursor position, then run go to definition
@@ -4762,20 +5526,20 @@ const handleMouseDown = (state, modifier, x, y, detail) => {
4762
5526
  }
4763
5527
  };
4764
5528
 
4765
- const state$4 = {
5529
+ const state$2 = {
4766
5530
  timeout: -1,
4767
5531
  x: 0,
4768
5532
  y: 0,
4769
5533
  editor: undefined
4770
5534
  };
4771
- const get$3 = () => {
4772
- return state$4;
5535
+ const get = () => {
5536
+ return state$2;
4773
5537
  };
4774
- const set$4 = (editor, timeout, x, y) => {
4775
- state$4.editor = editor;
4776
- state$4.timeout = timeout;
4777
- state$4.x = x;
4778
- state$4.y = y;
5538
+ const set = (editor, timeout, x, y) => {
5539
+ state$2.editor = editor;
5540
+ state$2.timeout = timeout;
5541
+ state$2.x = x;
5542
+ state$2.y = y;
4779
5543
  };
4780
5544
 
4781
5545
  const showHover$1 = async (editor, position) => {
@@ -4797,7 +5561,7 @@ const onHoverIdle = async () => {
4797
5561
  x,
4798
5562
  y,
4799
5563
  editor
4800
- } = get$3();
5564
+ } = get();
4801
5565
  at(editor, x, y);
4802
5566
  await showHover$1();
4803
5567
  };
@@ -4808,12 +5572,12 @@ const handleMouseMove = (editor, x, y) => {
4808
5572
  if (!editor.hoverEnabled) {
4809
5573
  return editor;
4810
5574
  }
4811
- const oldState = get$3();
5575
+ const oldState = get();
4812
5576
  if (oldState.timeout !== -1) {
4813
5577
  clearTimeout(oldState.timeout);
4814
5578
  }
4815
5579
  const timeout = setTimeout(onHoverIdle, hoverDelay);
4816
- set$4(editor, timeout, x, y);
5580
+ set(editor, timeout, x, y);
4817
5581
  return editor;
4818
5582
  };
4819
5583
 
@@ -4920,7 +5684,7 @@ const editorHandleNativeSelectionChange = (editor, range) => {
4920
5684
  return scheduleSelections(editor, selections);
4921
5685
  };
4922
5686
 
4923
- const state$3 = {
5687
+ const state$1 = {
4924
5688
  /**
4925
5689
  * @type {any}
4926
5690
  */
@@ -4934,26 +5698,26 @@ const state$3 = {
4934
5698
 
4935
5699
  // @ts-ignore
4936
5700
  const setEditor = editor => {
4937
- state$3.currentEditor = editor;
4938
- state$3.hasListener = true;
5701
+ state$1.currentEditor = editor;
5702
+ state$1.hasListener = true;
4939
5703
  };
4940
5704
  const clearEditor = () => {
4941
- state$3.currentEditor = undefined;
4942
- state$3.hasListener = false;
5705
+ state$1.currentEditor = undefined;
5706
+ state$1.hasListener = false;
4943
5707
  };
4944
5708
 
4945
5709
  // @ts-ignore
4946
5710
  const setPosition = position => {
4947
- state$3.position = position;
5711
+ state$1.position = position;
4948
5712
  };
4949
5713
  const getEditor$1 = () => {
4950
- return state$3.currentEditor;
5714
+ return state$1.currentEditor;
4951
5715
  };
4952
5716
  const getPosition = () => {
4953
- return state$3.position;
5717
+ return state$1.position;
4954
5718
  };
4955
5719
  const hasListener = () => {
4956
- return state$3.hasListener;
5720
+ return state$1.hasListener;
4957
5721
  };
4958
5722
 
4959
5723
  // @ts-ignore
@@ -5136,7 +5900,7 @@ const handleTouchEnd = (editor, touchEvent) => {
5136
5900
  // }
5137
5901
  };
5138
5902
 
5139
- const state$2 = {
5903
+ const state = {
5140
5904
  touchOffsetY: 0,
5141
5905
  deltaY: 0
5142
5906
  };
@@ -5147,8 +5911,8 @@ const handleTouchStart = (editor, touchEvent) => {
5147
5911
  return;
5148
5912
  }
5149
5913
  const firstTouch = touchEvent.touches[0];
5150
- state$2.touchOffsetY = firstTouch.y;
5151
- state$2.deltaY = editor.deltaY;
5914
+ state.touchOffsetY = firstTouch.y;
5915
+ state.deltaY = editor.deltaY;
5152
5916
  // const position = EditorPosition.at(editor, firstTouch.x, firstTouch.y)
5153
5917
  // EditorMoveSelection.state.position = position
5154
5918
  // state.date = Date.now()
@@ -5188,7 +5952,7 @@ const handleTouchMove = (editor, touchEvent) => {
5188
5952
  return;
5189
5953
  }
5190
5954
  const firstTouch = touchEvent.touches[0];
5191
- const offsetY = state$2.deltaY + (state$2.touchOffsetY - firstTouch.y);
5955
+ const offsetY = state.deltaY + (state.touchOffsetY - firstTouch.y);
5192
5956
  setDeltaYFixedValue(editor, offsetY);
5193
5957
  };
5194
5958
 
@@ -5624,7 +6388,7 @@ const getOrCreate$2 = () => {
5624
6388
  }
5625
6389
  return workerPromise$2;
5626
6390
  };
5627
- const invoke$5 = async (method, ...params) => {
6391
+ const invoke$4 = async (method, ...params) => {
5628
6392
  const worker = await getOrCreate$2();
5629
6393
  return await worker.invoke(method, ...params);
5630
6394
  };
@@ -5643,10 +6407,10 @@ const newStateGenerator$4 = async (state, parentUid) => {
5643
6407
  const {
5644
6408
  languageId
5645
6409
  } = newState;
5646
- await invoke$5('Completions.create', uid, x, y, width, height, parentUid, languageId);
5647
- await invoke$5('Completions.loadContent', uid);
5648
- const diff = await invoke$5('Completions.diff2', uid);
5649
- const commands = await invoke$5('Completions.render2', uid, diff);
6410
+ await invoke$4('Completions.create', uid, x, y, width, height, parentUid, languageId);
6411
+ await invoke$4('Completions.loadContent', uid);
6412
+ const diff = await invoke$4('Completions.diff2', uid);
6413
+ const commands = await invoke$4('Completions.render2', uid, diff);
5650
6414
  return {
5651
6415
  ...state,
5652
6416
  commands
@@ -5698,7 +6462,7 @@ const launch = async () => {
5698
6462
  const rpc = await launchFindWidgetWorker();
5699
6463
  set$c(rpcId, rpc);
5700
6464
  };
5701
- const invoke$4 = async (method, ...params) => {
6465
+ const invoke$3 = async (method, ...params) => {
5702
6466
  const rpc = get$6(rpcId);
5703
6467
  return await rpc.invoke(method, ...params);
5704
6468
  };
@@ -5737,10 +6501,10 @@ const loadContent$1 = async (state, parentUid) => {
5737
6501
  height
5738
6502
  } = editor;
5739
6503
  await launch();
5740
- await invoke$4('FindWidget.create', uid, x, y, width, height, parentUid);
5741
- await invoke$4('FindWidget.loadContent', uid);
5742
- const diff = await invoke$4('FindWidget.diff2', uid);
5743
- const commands = await invoke$4('FindWidget.render2', uid, diff);
6504
+ await invoke$3('FindWidget.create', uid, x, y, width, height, parentUid);
6505
+ await invoke$3('FindWidget.loadContent', uid);
6506
+ const diff = await invoke$3('FindWidget.diff2', uid);
6507
+ const commands = await invoke$3('FindWidget.render2', uid, diff);
5744
6508
  return {
5745
6509
  ...state,
5746
6510
  commands
@@ -5813,10 +6577,10 @@ const newStateGenerator$2 = async (state, parentUid) => {
5813
6577
  const {
5814
6578
  languageId
5815
6579
  } = newState;
5816
- await invoke$6('Rename.create', uid, x, y, width, height, parentUid, languageId);
5817
- await invoke$6('Rename.loadContent', uid);
5818
- const diff = await invoke$6('Rename.diff2', uid);
5819
- const commands = await invoke$6('Rename.render2', uid, diff);
6580
+ await invoke$5('Rename.create', uid, x, y, width, height, parentUid, languageId);
6581
+ await invoke$5('Rename.loadContent', uid);
6582
+ const diff = await invoke$5('Rename.diff2', uid);
6583
+ const commands = await invoke$5('Rename.render2', uid, diff);
5820
6584
  return {
5821
6585
  ...state,
5822
6586
  commands
@@ -6556,155 +7320,45 @@ const setDecorations = (editor, decorations, diagnostics) => {
6556
7320
  };
6557
7321
  };
6558
7322
 
6559
- let enabled$1 = false;
6560
- const setEnabled$1 = value => {
6561
- enabled$1 = value;
6562
- };
6563
- const getEnabled$1 = () => {
6564
- return enabled$1;
6565
- };
6566
-
6567
- const {
6568
- set: set$3,
6569
- invoke: invoke$3} = SyntaxHighlightingWorker;
7323
+ // TODO add command to set language id
7324
+ // without needing to specify tokenizePath
7325
+ const setLanguageId = async (editor, languageId, tokenizePath) => {
7326
+ const {
7327
+ tokenizerId
7328
+ } = editor;
7329
+ // TODO move tokenizer to syntax highlighting worker
7330
+ // TODO only load tokenizer if not already loaded
7331
+ // if already loaded just set tokenizer and rerender text
7332
+ // TODO race condition
7333
+ await loadTokenizer(languageId, tokenizePath);
7334
+ const tokenizer = getTokenizer(languageId);
7335
+ const newTokenizerId = tokenizerId + 1;
7336
+ set$2(newTokenizerId, tokenizer);
7337
+ const latest = getEditor(editor.uid);
7338
+ if (!latest) {
7339
+ return editor;
7340
+ }
7341
+ const syncIncremental = getEnabled();
7342
+ const {
7343
+ textInfos,
7344
+ differences
7345
+ } = await getVisible$1(editor, syncIncremental);
7346
+ const newEditor4 = {
7347
+ ...latest,
7348
+ focused: true,
7349
+ textInfos,
7350
+ differences
7351
+ };
6570
7352
 
6571
- /**
6572
- * @enum number
6573
- */
6574
- const State = {
6575
- TopLevelContent: 1
6576
- };
7353
+ // TODO don't update editor if tokenizer was already loaded
7354
+ // TODO update syntax highlighting
7355
+ // TODO get edits
6577
7356
 
6578
- /**
6579
- * @enum number
6580
- */
6581
- const TokenType = {
6582
- Text: 1
6583
- };
6584
- const TokenMap = {
6585
- [TokenType.Text]: 'Text'
6586
- };
6587
- const initialLineState = {
6588
- state: State.TopLevelContent
6589
- };
6590
- const hasArrayReturn = true;
6591
- const tokenizeLine = (line, lineState) => {
6592
7357
  return {
6593
- tokens: [TokenType.Text, line.length],
6594
- state: lineState.state
6595
- };
6596
- };
6597
-
6598
- const TokenizePlainText = {
6599
- __proto__: null,
6600
- State,
6601
- TokenMap,
6602
- TokenType,
6603
- hasArrayReturn,
6604
- initialLineState,
6605
- tokenizeLine
6606
- };
6607
-
6608
- const state$1 = {
6609
- tokenizers: Object.create(null),
6610
- pending: Object.create(null)};
6611
- const has = languageId => {
6612
- return languageId in state$1.tokenizers;
6613
- };
6614
- const set$2 = (languageId, tokenizer) => {
6615
- state$1.tokenizers[languageId] = tokenizer;
6616
- };
6617
- const get$2 = languageId => {
6618
- return state$1.tokenizers[languageId];
6619
- };
6620
- const isPending = languageId => {
6621
- return languageId in state$1.pending;
6622
- };
6623
-
6624
- const tokenMaps = Object.create(null);
6625
- const set$1 = (languageId, tokenMap) => {
6626
- tokenMaps[languageId] = tokenMap;
6627
- };
6628
- const get$1 = languageId => {
6629
- return tokenMaps[languageId] || {};
6630
- };
6631
-
6632
- // TODO loadTokenizer should be invoked from renderer worker
6633
- const loadTokenizer = async (languageId, tokenizePath) => {
6634
- if (!tokenizePath) {
6635
- return;
6636
- }
6637
- if (getEnabled$1()) {
6638
- // @ts-ignore
6639
- const tokenMap = await invoke$3('Tokenizer.load', languageId, tokenizePath);
6640
- set$1(languageId, tokenMap);
6641
- return;
6642
- }
6643
- try {
6644
- // TODO check that tokenizer is valid
6645
- // 1. tokenizeLine should be of type function
6646
- // 2. getTokenClass should be of type function
6647
- const tokenizer = await import(tokenizePath);
6648
- if (typeof tokenizer.tokenizeLine !== 'function') {
6649
- console.warn(`tokenizer.tokenizeLine should be a function in "${tokenizePath}"`);
6650
- return;
6651
- }
6652
- if (!tokenizer.TokenMap || typeof tokenizer.TokenMap !== 'object' || Array.isArray(tokenizer.TokenMap)) {
6653
- console.warn(`tokenizer.TokenMap should be an object in "${tokenizePath}"`);
6654
- return;
6655
- }
6656
- set$1(languageId, tokenizer.TokenMap);
6657
- set$2(languageId, tokenizer);
6658
- } catch (error) {
6659
- // TODO better error handling
6660
- console.error(error);
6661
- }
6662
- };
6663
- const getTokenizer = languageId => {
6664
- if (has(languageId)) {
6665
- return get$2(languageId);
6666
- }
6667
- if (isPending(languageId)) {
6668
- return TokenizePlainText;
6669
- }
6670
- return TokenizePlainText;
6671
- };
6672
-
6673
- const tokenizers = Object.create(null);
6674
- const set = (id, value) => {
6675
- tokenizers[id] = value;
6676
- };
6677
- const get = id => {
6678
- return tokenizers[id] || TokenizePlainText;
6679
- };
6680
-
6681
- // TODO add command to set language id
6682
- // without needing to specify tokenizePath
6683
- const setLanguageId = async (editor, languageId, tokenizePath) => {
6684
- const {
6685
- tokenizerId
6686
- } = editor;
6687
- // TODO move tokenizer to syntax highlighting worker
6688
- // TODO only load tokenizer if not already loaded
6689
- // if already loaded just set tokenizer and rerender text
6690
- // TODO race condition
6691
- await loadTokenizer(languageId, tokenizePath);
6692
- const tokenizer = getTokenizer(languageId);
6693
- const newTokenizerId = tokenizerId + 1;
6694
- set(newTokenizerId, tokenizer);
6695
- const latest = getEditor(editor.uid);
6696
- if (!latest) {
6697
- return editor;
6698
- }
6699
- // TODO don't update editor if tokenizer was already loaded
6700
- // TODO update syntax highlighting
6701
- // TODO get edits
6702
-
6703
- return {
6704
- ...latest,
6705
- languageId,
6706
- invalidStartIndex: 0,
6707
- tokenizerId: newTokenizerId
7358
+ ...newEditor4,
7359
+ languageId,
7360
+ invalidStartIndex: 0,
7361
+ tokenizerId: newTokenizerId
6708
7362
  };
6709
7363
  };
6710
7364
 
@@ -7746,11 +8400,11 @@ const getWidgetInvoke = widgetId => {
7746
8400
  case ColorPicker$1:
7747
8401
  return invoke$8;
7748
8402
  case Completion:
7749
- return invoke$5;
7750
- case Find:
7751
8403
  return invoke$4;
8404
+ case Find:
8405
+ return invoke$3;
7752
8406
  case Rename$1:
7753
- return invoke$6;
8407
+ return invoke$5;
7754
8408
  case SourceAction$1:
7755
8409
  return invoke$1;
7756
8410
  case Hover:
@@ -7953,8 +8607,9 @@ const {
7953
8607
  toggleReplace,
7954
8608
  toggleUseRegularExpression,
7955
8609
  focusNextElement,
7956
- focusPreviousElement
7957
- } = createFns(['close', 'focusCloseButton', 'focusFind', 'focusNext', 'focusNextMatchButton', 'focusPrevious', 'focusPreviousMatchButton', 'focusReplace', 'focusReplaceAllButton', 'focusReplaceButton', 'focusToggleReplace', 'handleBlur', 'handleClickButton', 'handleFocus', 'handleInput', 'handleReplaceFocus', 'handleReplaceInput', 'handleToggleReplaceFocus', 'replace', 'replaceAll', 'toggleMatchCase', 'toggleMatchWholeWord', 'toggleReplace', 'toggleUseRegularExpression', 'focusNextElement', 'focusPreviousElement'], 'FindWidget', Find);
8610
+ focusPreviousElement,
8611
+ togglePreserveCase
8612
+ } = createFns(['close', 'focusCloseButton', 'focusFind', 'focusNext', 'focusNextMatchButton', 'focusPrevious', 'focusPreviousMatchButton', 'focusReplace', 'focusReplaceAllButton', 'focusReplaceButton', 'focusToggleReplace', 'handleBlur', 'handleClickButton', 'handleFocus', 'handleInput', 'handleReplaceFocus', 'handleReplaceInput', 'handleToggleReplaceFocus', 'replace', 'replaceAll', 'toggleMatchCase', 'toggleMatchWholeWord', 'toggleReplace', 'toggleUseRegularExpression', 'focusNextElement', 'focusPreviousElement', 'togglePreserveCase'], 'FindWidget', Find);
7958
8613
 
7959
8614
  const EditorFindWidget = {
7960
8615
  __proto__: null,
@@ -7985,6 +8640,7 @@ const EditorFindWidget = {
7985
8640
  replaceAll,
7986
8641
  toggleMatchCase,
7987
8642
  toggleMatchWholeWord,
8643
+ togglePreserveCase,
7988
8644
  toggleReplace,
7989
8645
  toggleUseRegularExpression
7990
8646
  };
@@ -8015,15 +8671,7 @@ const measureTextBlockHeight = async (text, fontFamily, fontSize, lineHeight, wi
8015
8671
  return 100;
8016
8672
  };
8017
8673
 
8018
- const deepCopy = value => {
8019
- return structuredClone(value);
8020
- };
8021
-
8022
- const getInitialLineState = initialLineState => {
8023
- return deepCopy(initialLineState);
8024
- };
8025
-
8026
- const getLineInfo$1 = (line, tokens, TokenMap) => {
8674
+ const getLineInfo = (line, tokens, TokenMap) => {
8027
8675
  const tokensLength = tokens.length;
8028
8676
  let end = 0;
8029
8677
  let start = 0;
@@ -8041,45 +8689,6 @@ const getLineInfo$1 = (line, tokens, TokenMap) => {
8041
8689
  return lineInfo;
8042
8690
  };
8043
8691
 
8044
- const state = {
8045
- warned: []
8046
- };
8047
- const flattenTokensArray = tokens => {
8048
- const flattened = [];
8049
- for (const token of tokens) {
8050
- object(token);
8051
- flattened.push(token.type, token.length);
8052
- }
8053
- return flattened;
8054
- };
8055
- const warnDeprecatedArrayReturn = (languageId, fn) => {
8056
- if (state.warned.includes(fn)) {
8057
- return;
8058
- }
8059
- state.warned.push(fn);
8060
- console.warn(`tokenizers without hasArrayReturn=false are deprecated (language ${languageId})`);
8061
- };
8062
- const safeTokenizeLine = (languageId, tokenizeLine, line, lineStateAtStart, hasArrayReturn) => {
8063
- try {
8064
- const lineState = tokenizeLine(line, lineStateAtStart);
8065
- if (!lineState?.tokens || !lineState.state) {
8066
- throw new Error('invalid tokenization result');
8067
- }
8068
- if (!hasArrayReturn) {
8069
- warnDeprecatedArrayReturn(languageId, tokenizeLine);
8070
- // workaround for old tokenizers
8071
- lineState.tokens = flattenTokensArray(lineState.tokens);
8072
- }
8073
- return lineState;
8074
- } catch (error) {
8075
- console.error(error);
8076
- return {
8077
- tokens: [/* type */0, /* length */line.length],
8078
- lineState: lineStateAtStart
8079
- };
8080
- }
8081
- };
8082
-
8083
8692
  const getLineInfos = (lines, tokenizer, languageId) => {
8084
8693
  const lineInfos = [];
8085
8694
  const {
@@ -8094,7 +8703,7 @@ const getLineInfos = (lines, tokenizer, languageId) => {
8094
8703
  const {
8095
8704
  tokens
8096
8705
  } = result;
8097
- const lineInfo = getLineInfo$1(line, tokens, TokenMap);
8706
+ const lineInfo = getLineInfo(line, tokens, TokenMap);
8098
8707
  lineInfos.push(lineInfo);
8099
8708
  currentLineState = result;
8100
8709
  }
@@ -9379,7 +9988,7 @@ const createExtensionHostRpc = async () => {
9379
9988
 
9380
9989
  const initializeExtensionHost = async () => {
9381
9990
  const extensionHostRpc = await createExtensionHostRpc();
9382
- set$5(extensionHostRpc);
9991
+ set$1(extensionHostRpc);
9383
9992
  };
9384
9993
 
9385
9994
  const sendMessagePortToSyntaxHighlightingWorker = async () => {
@@ -9399,586 +10008,92 @@ const sendMessagePortToSyntaxHighlightingWorker = async () => {
9399
10008
  } = getPortTuple();
9400
10009
  await invokeAndTransfer(
9401
10010
  // @ts-ignore
9402
- 'SendMessagePortToSyntaxHighlightingWorker.sendMessagePortToSyntaxHighlightingWorker', port1, 'HandleMessagePort.handleMessagePort');
9403
- return port2;
9404
- }
9405
- };
9406
-
9407
- const createSyntaxHighlightingWorkerRpc = async () => {
9408
- try {
9409
- const port = await sendMessagePortToSyntaxHighlightingWorker();
9410
- const rpc = await PlainMessagePortRpcParent.create({
9411
- commandMap: {},
9412
- messagePort: port
9413
- });
9414
- return rpc;
9415
- } catch (error) {
9416
- throw new VError(error, `Failed to create syntax highlighting worker rpc`);
9417
- }
9418
- };
9419
-
9420
- let enabled = false;
9421
- const setEnabled = value => {
9422
- enabled = value;
9423
- };
9424
- const getEnabled = () => {
9425
- return enabled;
9426
- };
9427
-
9428
- const initializeSyntaxHighlighting = async (syntaxHighlightingEnabled, syncIncremental) => {
9429
- if (syntaxHighlightingEnabled) {
9430
- setEnabled$1(true);
9431
- const syntaxRpc = await createSyntaxHighlightingWorkerRpc();
9432
- set$3(syntaxRpc);
9433
- }
9434
- if (syncIncremental) {
9435
- setEnabled(true);
9436
- }
9437
- };
9438
-
9439
- const intialize = async (syntaxHighlightingEnabled, syncIncremental) => {
9440
- await Promise.all([initializeSyntaxHighlighting(syntaxHighlightingEnabled, syncIncremental), initializeExtensionHost()]);
9441
- };
9442
-
9443
- // TODO move cursor
9444
- // TODO multiple cursors -> vscode removes multiple cursors
9445
- // TODO with selection -> vscode moves whole selection
9446
- const moveLineDown = editor => {
9447
- // const rowIndex = editor.cursor.rowIndex
9448
- // if (rowIndex === editor.lines.length - 1) {
9449
- // return
9450
- // }
9451
- // const documentEdits = [
9452
- // {
9453
- // type: /* splice */ 2,
9454
- // rowIndex: rowIndex,
9455
- // count: 2,
9456
- // newLines: [TextDocument.getLine(editor.textDocument, rowIndex + 1), TextDocument.getLine(editor.textDocument, rowIndex)],
9457
- // },
9458
- // ]
9459
- // // @ts-ignore
9460
- // const cursorEdits = Editor.moveCursors(editor, (editor, cursor) => {
9461
- // return {
9462
- // rowIndex: cursor.rowIndex + 1,
9463
- // columnIndex: cursor.columnIndex,
9464
- // }
9465
- // })
9466
- // @ts-ignore
9467
- // Editor.scheduleDocumentAndCursors(editor, documentEdits, cursorEdits)
9468
- return editor;
9469
- };
9470
-
9471
- // TODO handle multiple cursors
9472
- const moveLineUp = editor => {
9473
- // const rowIndex = editor.cursor.rowIndex
9474
- // if (rowIndex === 0) {
9475
- // return
9476
- // }
9477
- // const documentEdits = [
9478
- // {
9479
- // type: /* splice */ 2,
9480
- // rowIndex: rowIndex - 1,
9481
- // count: 2,
9482
- // newLines: [TextDocument.getLine(editor.textDocument, rowIndex), TextDocument.getLine(editor.textDocument, rowIndex - 1)],
9483
- // },
9484
- // ]
9485
- // // @ts-ignore
9486
- // const cursorEdits = Editor.moveCursors(editor, (editor, cursor) => {
9487
- // return {
9488
- // // TODO handle bottom 0
9489
- // rowIndex: cursor.rowIndex - 1,
9490
- // columnIndex: cursor.columnIndex,
9491
- // }
9492
- // })
9493
- // // @ts-ignore
9494
- // Editor.scheduleDocumentAndCursors(editor, documentEdits, cursorEdits)
9495
- return editor;
9496
- };
9497
-
9498
- const Link$1 = 'Link';
9499
- const Function = 'Function';
9500
- const Parameter = 'Parameter';
9501
- const Type = 'Type';
9502
- const VariableName = 'VariableName';
9503
- const Class = 'Class';
9504
-
9505
- const Link = 1;
9506
- const Ts2816 = 2816;
9507
- const Ts2817 = 2817;
9508
- const Ts2824 = 2824;
9509
- const Ts2825 = 2825;
9510
- const Ts2856 = 2956;
9511
- const Ts2857 = 2857;
9512
- const Ts3072 = 3072;
9513
- const Ts3073 = 3073;
9514
- const Ts3077 = 3077;
9515
- const Ts3088 = 3088;
9516
- const Ts1792 = 1792;
9517
- const Ts1793 = 1793;
9518
- const Ts512 = 512;
9519
- const Ts513 = 513;
9520
- const Ts769 = 769;
9521
- const Ts1024 = 1024;
9522
- const Ts1536 = 1536;
9523
- const Ts1537 = 1537;
9524
- const Ts1544 = 1544;
9525
- const Ts1545 = 1545;
9526
- const Ts2048 = 2048;
9527
- const Ts2049 = 2049;
9528
- const Ts2056 = 2056;
9529
- const Ts2057 = 2057;
9530
- const Ts2064 = 2064;
9531
- const Ts2080 = 2080;
9532
- const Ts2081 = 2081;
9533
- const Ts2088 = 2088;
9534
- const Ts2089 = 2089;
9535
- const Ts2313 = 2313;
9536
- const Ts2560 = 2560;
9537
- const Ts2561 = 2561;
9538
- const Ts2569 = 2569;
9539
- const Ts2584 = 2584;
9540
- const Ts256 = 256;
9541
- const Ts257 = 257;
9542
- const Ts272 = 272;
9543
-
9544
- const getDecorationClassName = type => {
9545
- switch (type) {
9546
- case Link:
9547
- return Link$1;
9548
- case Ts2816:
9549
- case Ts2817:
9550
- case Ts2824:
9551
- case Ts2825:
9552
- case Ts2856:
9553
- case Ts2857:
9554
- case Ts3072:
9555
- case Ts3073:
9556
- case Ts3077:
9557
- case Ts3088:
9558
- return Function;
9559
- case Ts1792:
9560
- case Ts1793:
9561
- return Parameter;
9562
- case Ts512:
9563
- case Ts513:
9564
- case Ts769:
9565
- case Ts1024:
9566
- case Ts1536:
9567
- case Ts1537:
9568
- case Ts1544:
9569
- case Ts1545:
9570
- return Type;
9571
- case Ts2048:
9572
- case Ts2049:
9573
- case Ts2056:
9574
- case Ts2057:
9575
- case Ts2064:
9576
- case Ts2080:
9577
- case Ts2081:
9578
- case Ts2088:
9579
- case Ts2089:
9580
- case Ts2313:
9581
- case Ts2560:
9582
- case Ts2561:
9583
- case Ts2569:
9584
- case Ts2584:
9585
- return VariableName;
9586
- case Ts256:
9587
- case Ts257:
9588
- case Ts272:
9589
- return Class;
9590
- default:
9591
- return `Unknown-${type}`;
9592
- }
9593
- };
9594
-
9595
- const getTokensViewportEmbedded = (langageId, lines, lineCache, linesWithEmbed) => {
9596
- const tokenizersToLoad = [];
9597
- const embeddedResults = [];
9598
- let topContext;
9599
- for (const index of linesWithEmbed) {
9600
- const result = lineCache[index + 1];
9601
- const line = lines[index];
9602
- if (result.embeddedLanguage) {
9603
- const {
9604
- embeddedLanguage,
9605
- embeddedLanguageStart,
9606
- embeddedLanguageEnd
9607
- } = result;
9608
- const embeddedTokenizer = getTokenizer(embeddedLanguage);
9609
- if (embeddedLanguageStart !== line.length && embeddedTokenizer && embeddedTokenizer !== TokenizePlainText) {
9610
- const isFull = embeddedLanguageStart === 0 && embeddedLanguageEnd === line.length;
9611
- const partialLine = line.slice(embeddedLanguageStart, embeddedLanguageEnd);
9612
- const embedResult = safeTokenizeLine(langageId, embeddedTokenizer.tokenizeLine, partialLine, topContext || getInitialLineState(embeddedTokenizer.initialLineState), embeddedTokenizer.hasArrayReturn);
9613
- topContext = embedResult;
9614
- result.embeddedResultIndex = embeddedResults.length;
9615
- embeddedResults.push({
9616
- result: embedResult,
9617
- TokenMap: embeddedTokenizer.TokenMap,
9618
- isFull
9619
- });
9620
- } else if (line.length === 0) {
9621
- const embedResult = {
9622
- tokens: []
9623
- };
9624
- result.embeddedResultIndex = embeddedResults.length;
9625
- embeddedResults.push({
9626
- result: embedResult,
9627
- isFull: true,
9628
- TokenMap: []
9629
- });
9630
- } else {
9631
- tokenizersToLoad.push(embeddedLanguage);
9632
- embeddedResults.push({
9633
- result: {},
9634
- isFull: false,
9635
- TokenMap: []
9636
- });
9637
- topContext = undefined;
9638
- }
9639
- } else {
9640
- topContext = undefined;
9641
- }
9642
- }
9643
- return {
9644
- tokenizersToLoad,
9645
- embeddedResults
9646
- };
9647
- };
9648
- const getTokenizeEndIndex = (invalidStartIndex, endLineIndex, tokenizeStartIndex) => {
9649
- return invalidStartIndex < endLineIndex ? endLineIndex : tokenizeStartIndex;
9650
- };
9651
-
9652
- // TODO only send changed lines to renderer process instead of all lines in viewport
9653
- const getTokensViewport = (editor, startLineIndex, endLineIndex) => {
9654
- const {
9655
- invalidStartIndex,
9656
- lineCache,
9657
- tokenizerId,
9658
- lines,
9659
- languageId
9660
- } = editor;
9661
- const tokenizer = get(tokenizerId);
9662
- const {
9663
- hasArrayReturn,
9664
- tokenizeLine,
9665
- initialLineState
9666
- } = tokenizer;
9667
- const tokenizeStartIndex = invalidStartIndex;
9668
- const tokenizeEndIndex = getTokenizeEndIndex(invalidStartIndex, endLineIndex, tokenizeStartIndex);
9669
- const tokenizersToLoad = [];
9670
- const embeddedResults = [];
9671
- const linesWithEmbed = [];
9672
- for (let i = tokenizeStartIndex; i < tokenizeEndIndex; i++) {
9673
- const lineState = i === 0 ? getInitialLineState(initialLineState) : lineCache[i];
9674
- const line = lines[i];
9675
- const result = safeTokenizeLine(languageId, tokenizeLine, line, lineState, hasArrayReturn);
9676
- // TODO if lineCacheEnd matches the one before, skip tokenizing lines after
9677
- lineCache[i + 1] = result;
9678
- if (result.embeddedLanguage) {
9679
- result.embeddedResultIndex = linesWithEmbed.length;
9680
- linesWithEmbed.push(i);
9681
- }
9682
- }
9683
- const visibleLines = lineCache.slice(startLineIndex + 1, endLineIndex + 1);
9684
- if (linesWithEmbed.length > 0) {
9685
- const {
9686
- tokenizersToLoad,
9687
- embeddedResults
9688
- } = getTokensViewportEmbedded(languageId, lines, lineCache, linesWithEmbed);
9689
- // TODO support lineCache with embedded content
9690
- editor.invalidStartIndex = 0;
9691
- return {
9692
- tokens: visibleLines,
9693
- tokenizersToLoad,
9694
- embeddedResults
9695
- };
9696
- }
9697
- editor.invalidStartIndex = Math.max(invalidStartIndex, tokenizeEndIndex);
9698
- return {
9699
- tokens: visibleLines,
9700
- tokenizersToLoad,
9701
- embeddedResults
9702
- };
9703
- };
9704
-
9705
- const sentLines = Object.create(null);
9706
-
9707
- // TODO only send changed lines to renderer process instead of all lines in viewport
9708
- const getTokensViewport2 = async (editor, startLineIndex, endLineIndex, syncIncremental) => {
9709
- if (getEnabled$1()) {
9710
- if (syncIncremental) {
9711
- const {
9712
- invalidStartIndex,
9713
- lines,
9714
- languageId,
9715
- id
9716
- } = editor;
9717
- let hasLinesToSend = true;
9718
- let linesToSend = lines;
9719
- if (sentLines[id] === lines) {
9720
- hasLinesToSend = false;
9721
- linesToSend = [];
9722
- } else {
9723
- sentLines[id] = lines;
9724
- }
9725
- const slimEditor = {
9726
- languageId,
9727
- invalidStartIndex
9728
- };
9729
- return invoke$3('GetTokensViewport.getTokensViewport', slimEditor,
9730
- // @ts-ignore
9731
- startLineIndex, endLineIndex, hasLinesToSend, id, linesToSend);
9732
- }
9733
- // TODO only send needed lines of text
9734
- // @ts-ignore
9735
- return invoke$3('GetTokensViewport.getTokensViewport', editor, startLineIndex, endLineIndex, true, editor.id, editor.lines);
9736
- }
9737
- return getTokensViewport(editor, startLineIndex, endLineIndex);
9738
- };
9739
-
9740
- const loadTokenizers = async languageIds => {
9741
- for (const languageId of languageIds) {
9742
- // @ts-ignore
9743
- await loadTokenizer(languageId);
9744
- }
9745
- };
9746
-
9747
- // const getTokensIncremental = (editor, min, max) => {
9748
- // const currentLength = editor.lineStateCache.length
9749
- // const tokens = []
9750
- // const lines = editor.lines
9751
- // let lineState = editor.tokenizer.initialLineState
9752
- // for (let i = currentLength; i < max; i++) {
9753
- // const line = lines[i]
9754
- // try {
9755
- // lineState = editor.tokenizer.tokenizeLine(line, lineState)
9756
- // if (!lineState || !lineState.tokens || !lineState.state) {
9757
- // throw new Error('invalid tokenization result')
9758
- // }
9759
- // } catch (error) {
9760
- // tokens.push([{ length: line.length, type: 0 }])
9761
- // console.error(error)
9762
- // // renderWithoutSyntaxHighlighting(state, firstRow, lastRow)
9763
- // continue
9764
- // }
9765
- // const newTokens = lineState.tokens
9766
- // tokens.push(newTokens)
9767
- // }
9768
- // return tokens
9769
- // }
9770
-
9771
- // const getLineInfosIncremental = (editor, tokens, minLineY, maxLineY) => {
9772
- // const result = []
9773
- // const lines = editor.lines
9774
- // const TokenMap = editor.tokenizer.TokenMap
9775
- // for (let i = minLineY; i < maxLineY; i++) {
9776
- // result.push(getLineInfo(lines[i], tokens[i], TokenMap))
9777
- // }
9778
- // return result
9779
- // }
9780
-
9781
- const getStartDefaults = (tokens, minOffset) => {
9782
- let start = 0;
9783
- let end = 0;
9784
- let startIndex = 0;
9785
- const tokensLength = tokens.length;
9786
- for (let i = 0; i < tokensLength; i += 2) {
9787
- const tokenLength = tokens[i + 1];
9788
- end += tokenLength;
9789
- start = end;
9790
- if (start >= minOffset) {
9791
- start -= tokenLength;
9792
- end -= tokenLength;
9793
- startIndex = i;
9794
- break;
9795
- }
9796
- }
9797
- return {
9798
- start,
9799
- end,
9800
- startIndex
9801
- };
9802
- };
9803
- const getLineInfoEmbeddedFull = (embeddedResults, tokenResults, line, normalize, tabSize, width, deltaX, averageCharWidth, minOffset, maxOffset) => {
9804
- const lineInfo = [];
9805
- const embeddedResult = embeddedResults[tokenResults.embeddedResultIndex];
9806
- const embeddedTokens = embeddedResult.result.tokens;
9807
- const embeddedTokenMap = embeddedResult.TokenMap;
9808
- const tokensLength = embeddedTokens.length;
9809
- let {
9810
- startIndex,
9811
- start,
9812
- end
9813
- } = getStartDefaults(embeddedTokens, minOffset);
9814
- const difference = getDifference(start, averageCharWidth, deltaX);
9815
- for (let i = startIndex; i < tokensLength; i += 2) {
9816
- const tokenType = embeddedTokens[i];
9817
- const tokenLength = embeddedTokens[i + 1];
9818
- end += tokenLength;
9819
- const className = `Token ${embeddedTokenMap[tokenType] || 'Unknown'}`;
9820
- const text = line.slice(start, end);
9821
- const normalizedText = normalizeText(text, normalize, tabSize);
9822
- lineInfo.push(normalizedText, className);
9823
- start = end;
9824
- if (end >= maxOffset) {
9825
- break;
9826
- }
10011
+ 'SendMessagePortToSyntaxHighlightingWorker.sendMessagePortToSyntaxHighlightingWorker', port1, 'HandleMessagePort.handleMessagePort');
10012
+ return port2;
9827
10013
  }
9828
- return {
9829
- lineInfo,
9830
- difference
9831
- };
9832
10014
  };
9833
- const getOffsets = (deltaX, width, averageCharWidth) => {
9834
- // TODO accurately measure char widths using offscreen canvas
9835
- // and use fast measurements for monospace ascii text
9836
- if (deltaX === 0) {
9837
- return {
9838
- minOffset: 0,
9839
- maxOffset: Math.ceil(width / averageCharWidth)
9840
- };
10015
+
10016
+ const createSyntaxHighlightingWorkerRpc = async () => {
10017
+ try {
10018
+ const port = await sendMessagePortToSyntaxHighlightingWorker();
10019
+ const rpc = await PlainMessagePortRpcParent.create({
10020
+ commandMap: {},
10021
+ messagePort: port
10022
+ });
10023
+ return rpc;
10024
+ } catch (error) {
10025
+ throw new VError(error, `Failed to create syntax highlighting worker rpc`);
9841
10026
  }
9842
- const minOffset = Math.ceil(deltaX / averageCharWidth);
9843
- const maxOffset = minOffset + Math.ceil(width / averageCharWidth);
9844
- return {
9845
- minOffset,
9846
- maxOffset
9847
- };
9848
- };
9849
- const getDifference = (start, averageCharWidth, deltaX) => {
9850
- const beforeWidth = start * averageCharWidth;
9851
- const difference = beforeWidth - deltaX;
9852
- return difference;
9853
10027
  };
9854
- const getLineInfoDefault = (line, tokenResults, embeddedResults, decorations, TokenMap, lineOffset, normalize, tabSize, width, deltaX, averageCharWidth, minOffset, maxOffset) => {
9855
- const lineInfo = [];
9856
- let decorationIndex = 0;
9857
- for (; decorationIndex < decorations.length; decorationIndex += 3) {
9858
- const decorationOffset = decorations[decorationIndex];
9859
- if (decorationOffset >= lineOffset) {
9860
- break;
9861
- }
9862
- }
9863
- const {
9864
- tokens
9865
- } = tokenResults;
9866
- let {
9867
- startIndex,
9868
- start,
9869
- end
9870
- } = getStartDefaults(tokens, minOffset);
9871
- const difference = getDifference(start, averageCharWidth, deltaX);
9872
- const tokensLength = tokens.length;
9873
- for (let i = startIndex; i < tokensLength; i += 2) {
9874
- const tokenType = tokens[i];
9875
- const tokenLength = tokens[i + 1];
9876
- const decorationOffset = decorations[decorationIndex];
9877
- let extraClassName = '';
9878
- if (decorationOffset !== undefined && decorationOffset - lineOffset === start) {
9879
- // @ts-ignore
9880
- decorations[++decorationIndex];
9881
- const decorationType = decorations[++decorationIndex];
9882
- // @ts-ignore
9883
- decorations[++decorationIndex];
9884
- // decorationIndex,
9885
- // decorationLength,
9886
- // decorationType,
9887
- // decorationModifiers,
9888
- // })
9889
- extraClassName = getDecorationClassName(decorationType);
9890
- }
9891
- end += tokenLength;
9892
- const text = line.slice(start, end);
9893
- const className = `Token ${extraClassName || TokenMap[tokenType] || 'Unknown'}`;
9894
- const normalizedText = normalizeText(text, normalize, tabSize);
9895
- lineInfo.push(normalizedText, className);
9896
- start = end;
9897
- if (end >= maxOffset) {
9898
- break;
9899
- }
10028
+
10029
+ const initializeSyntaxHighlighting = async (syntaxHighlightingEnabled, syncIncremental) => {
10030
+ if (syntaxHighlightingEnabled) {
10031
+ setEnabled$1(true);
10032
+ const syntaxRpc = await createSyntaxHighlightingWorkerRpc();
10033
+ set$5(syntaxRpc);
9900
10034
  }
9901
- return {
9902
- lineInfo,
9903
- difference
9904
- };
9905
- };
9906
- const getLineInfo = (line, tokenResults, embeddedResults, decorations, TokenMap, lineOffset, normalize, tabSize, width, deltaX, averageCharWidth) => {
9907
- const {
9908
- minOffset,
9909
- maxOffset
9910
- } = getOffsets(deltaX, width, averageCharWidth);
9911
- if (embeddedResults.length > 0 && tokenResults.embeddedResultIndex !== undefined) {
9912
- const embeddedResult = embeddedResults[tokenResults.embeddedResultIndex];
9913
- if (embeddedResult?.isFull) {
9914
- return getLineInfoEmbeddedFull(embeddedResults, tokenResults, line, normalize, tabSize, width, deltaX, averageCharWidth, minOffset, maxOffset);
9915
- }
10035
+ if (syncIncremental) {
10036
+ setEnabled(true);
9916
10037
  }
9917
- return getLineInfoDefault(line, tokenResults, embeddedResults, decorations, TokenMap, lineOffset, normalize, tabSize, width, deltaX, averageCharWidth, minOffset, maxOffset);
9918
10038
  };
9919
10039
 
9920
- // TODO need lots of tests for this
9921
- const getLineInfosViewport = (editor, tokens, embeddedResults, minLineY, maxLineY, minLineOffset, width, deltaX, averageCharWidth) => {
9922
- const result = [];
9923
- const differences = [];
9924
- const {
9925
- lines,
9926
- decorations,
9927
- languageId
9928
- } = editor;
9929
- const tokenMap = get$1(languageId);
9930
- let offset = minLineOffset;
9931
- const tabSize = 2;
9932
- for (let i = minLineY; i < maxLineY; i++) {
9933
- const line = lines[i];
9934
- const normalize = shouldNormalizeText(line);
9935
- const {
9936
- lineInfo,
9937
- difference
9938
- } = getLineInfo(line, tokens[i - minLineY], embeddedResults, decorations, tokenMap, offset, normalize, tabSize, width, deltaX, averageCharWidth);
9939
- result.push(lineInfo);
9940
- differences.push(difference);
9941
- offset += line.length + 1;
9942
- }
9943
- return {
9944
- result,
9945
- differences
9946
- };
10040
+ const intialize = async (syntaxHighlightingEnabled, syncIncremental) => {
10041
+ await Promise.all([initializeSyntaxHighlighting(syntaxHighlightingEnabled, syncIncremental), initializeExtensionHost()]);
9947
10042
  };
9948
- const getVisible = async (editor, syncIncremental) => {
9949
- // TODO should separate rendering from business logic somehow
9950
- // currently hard to test because need to mock editor height, top, left,
9951
- // invalidStartIndex, lineCache, etc. just for testing editorType
9952
- // editor.invalidStartIndex = changes[0].start.rowIndex
9953
- // @ts-ignore
9954
- const {
9955
- minLineY,
9956
- numberOfVisibleLines,
9957
- lines,
9958
- width,
9959
- deltaX,
9960
- charWidth
9961
- } = editor;
9962
- const maxLineY = Math.min(minLineY + numberOfVisibleLines, lines.length);
10043
+
10044
+ // TODO move cursor
10045
+ // TODO multiple cursors -> vscode removes multiple cursors
10046
+ // TODO with selection -> vscode moves whole selection
10047
+ const moveLineDown = editor => {
10048
+ // const rowIndex = editor.cursor.rowIndex
10049
+ // if (rowIndex === editor.lines.length - 1) {
10050
+ // return
10051
+ // }
10052
+ // const documentEdits = [
10053
+ // {
10054
+ // type: /* splice */ 2,
10055
+ // rowIndex: rowIndex,
10056
+ // count: 2,
10057
+ // newLines: [TextDocument.getLine(editor.textDocument, rowIndex + 1), TextDocument.getLine(editor.textDocument, rowIndex)],
10058
+ // },
10059
+ // ]
10060
+ // // @ts-ignore
10061
+ // const cursorEdits = Editor.moveCursors(editor, (editor, cursor) => {
10062
+ // return {
10063
+ // rowIndex: cursor.rowIndex + 1,
10064
+ // columnIndex: cursor.columnIndex,
10065
+ // }
10066
+ // })
9963
10067
  // @ts-ignore
9964
- const {
9965
- tokens,
9966
- tokenizersToLoad,
9967
- embeddedResults
9968
- } = await getTokensViewport2(editor, minLineY, maxLineY, syncIncremental);
9969
- const minLineOffset = offsetAtSync(editor, minLineY, 0);
9970
- const averageCharWidth = charWidth;
9971
- const {
9972
- result,
9973
- differences
9974
- } = getLineInfosViewport(editor, tokens, embeddedResults, minLineY, maxLineY, minLineOffset, width, deltaX, averageCharWidth);
9975
- if (tokenizersToLoad.length > 0) {
9976
- loadTokenizers(tokenizersToLoad);
9977
- }
9978
- return {
9979
- textInfos: result,
9980
- differences
9981
- };
10068
+ // Editor.scheduleDocumentAndCursors(editor, documentEdits, cursorEdits)
10069
+ return editor;
10070
+ };
10071
+
10072
+ // TODO handle multiple cursors
10073
+ const moveLineUp = editor => {
10074
+ // const rowIndex = editor.cursor.rowIndex
10075
+ // if (rowIndex === 0) {
10076
+ // return
10077
+ // }
10078
+ // const documentEdits = [
10079
+ // {
10080
+ // type: /* splice */ 2,
10081
+ // rowIndex: rowIndex - 1,
10082
+ // count: 2,
10083
+ // newLines: [TextDocument.getLine(editor.textDocument, rowIndex), TextDocument.getLine(editor.textDocument, rowIndex - 1)],
10084
+ // },
10085
+ // ]
10086
+ // // @ts-ignore
10087
+ // const cursorEdits = Editor.moveCursors(editor, (editor, cursor) => {
10088
+ // return {
10089
+ // // TODO handle bottom 0
10090
+ // rowIndex: cursor.rowIndex - 1,
10091
+ // columnIndex: cursor.columnIndex,
10092
+ // }
10093
+ // })
10094
+ // // @ts-ignore
10095
+ // Editor.scheduleDocumentAndCursors(editor, documentEdits, cursorEdits)
10096
+ return editor;
9982
10097
  };
9983
10098
 
9984
10099
  const getCursorsVirtualDom = cursors => {
@@ -10077,36 +10192,6 @@ const getEditorRowsVirtualDom = (textInfos, differences, lineNumbers = true, hig
10077
10192
  return dom;
10078
10193
  };
10079
10194
 
10080
- const getIncrementalEdits = async (oldState, newState) => {
10081
- if (!newState.undoStack) {
10082
- return undefined;
10083
- }
10084
- const lastChanges = newState.undoStack.at(-1);
10085
- if (lastChanges && lastChanges.length === 1) {
10086
- const lastChange = lastChanges[0];
10087
- if (lastChange.origin === EditorType) {
10088
- const {
10089
- rowIndex
10090
- } = lastChange.start;
10091
- const {
10092
- lines
10093
- } = newState;
10094
- const oldLine = oldState.lines[rowIndex];
10095
- const newLine = lines[rowIndex];
10096
- // @ts-ignore
10097
- const incrementalEdits = await invoke$3(
10098
- // @ts-ignore
10099
- 'TokenizeIncremental.tokenizeIncremental', newState.uid,
10100
- // @ts-ignore
10101
- newState.languageId, oldLine, newLine, rowIndex, newState.minLineY);
10102
- if (incrementalEdits && incrementalEdits.length === 1) {
10103
- return incrementalEdits;
10104
- }
10105
- }
10106
- }
10107
- return undefined;
10108
- };
10109
-
10110
10195
  const getSelectionsVirtualDom = selections => {
10111
10196
  const dom = [];
10112
10197
  for (let i = 0; i < selections.length; i += 4) {
@@ -10152,16 +10237,17 @@ const renderLines = {
10152
10237
  isEqual(oldState, newState) {
10153
10238
  return oldState.lines === newState.lines && oldState.tokenizerId === newState.tokenizerId && oldState.minLineY === newState.minLineY && oldState.decorations === newState.decorations && oldState.embeds === newState.embeds && oldState.deltaX === newState.deltaX && oldState.width === newState.width && oldState.highlightedLine === newState.highlightedLine && oldState.debugEnabled === newState.debugEnabled;
10154
10239
  },
10155
- async apply(oldState, newState) {
10156
- const incrementalEdits = await getIncrementalEdits(oldState, newState);
10157
- if (incrementalEdits) {
10240
+ apply(oldState, newState) {
10241
+ const {
10242
+ incrementalEdits
10243
+ } = newState;
10244
+ if (incrementalEdits !== emptyIncrementalEdits) {
10158
10245
  return [/* method */'setIncrementalEdits', /* incrementalEdits */incrementalEdits];
10159
10246
  }
10160
- const syncIncremental = getEnabled();
10161
10247
  const {
10162
10248
  textInfos,
10163
10249
  differences
10164
- } = await getVisible(newState, syncIncremental);
10250
+ } = newState;
10165
10251
  newState.differences = differences;
10166
10252
  const {
10167
10253
  highlightedLine,
@@ -10180,7 +10266,7 @@ const renderSelections = {
10180
10266
  const {
10181
10267
  cursorInfos,
10182
10268
  selectionInfos
10183
- } = getVisible$1(newState);
10269
+ } = getVisible(newState);
10184
10270
  const cursorsDom = getCursorsVirtualDom(cursorInfos);
10185
10271
  const selectionsDom = getSelectionsVirtualDom(selectionInfos);
10186
10272
  return [/* method */'setSelections', cursorsDom, selectionsDom];
@@ -10306,7 +10392,7 @@ const renderWidgets = {
10306
10392
  multiple: true
10307
10393
  };
10308
10394
  const render$6 = [renderLines, renderSelections, renderScrollBarX, renderScrollBarY, renderFocus$1, renderDecorations, renderGutterInfo, renderWidgets];
10309
- const renderEditor = async id => {
10395
+ const renderEditor = id => {
10310
10396
  const instance = get$4(id);
10311
10397
  if (!instance) {
10312
10398
  return [];
@@ -10319,7 +10405,7 @@ const renderEditor = async id => {
10319
10405
  set$6(id, newState, newState);
10320
10406
  for (const item of render$6) {
10321
10407
  if (!item.isEqual(oldState, newState)) {
10322
- const result = await item.apply(oldState, newState);
10408
+ const result = item.apply(oldState, newState);
10323
10409
  // @ts-ignore
10324
10410
  if (item.multiple) {
10325
10411
  commands.push(...result);
@@ -10456,11 +10542,16 @@ const wrapCommand = fn => async (editorUid, ...args) => {
10456
10542
  effect.apply(newEditor);
10457
10543
  }
10458
10544
  }
10545
+ // TODO if editor did not change, no need to update furthur
10546
+
10547
+ // TODO combine neweditor with latest editor?
10548
+
10459
10549
  set$6(editorUid, oldInstance.newState, newEditor);
10460
- // TODO if possible, rendering should be sync
10461
- const commands = await renderEditor(editorUid);
10462
- newEditor.commands = commands;
10463
- return newEditor;
10550
+ const commands = renderEditor(editorUid);
10551
+ return {
10552
+ ...newEditor,
10553
+ commands
10554
+ };
10464
10555
  };
10465
10556
  const wrapCommands = commands => {
10466
10557
  for (const [key, value] of Object.entries(commands)) {
@@ -10695,6 +10786,7 @@ const commandMap = {
10695
10786
  'FindWidget.toggleUseRegularExpression': toggleUseRegularExpression,
10696
10787
  'FindWidget.focusNextElement': focusNextElement,
10697
10788
  'FindWidget.focusPreviousElement': focusPreviousElement,
10789
+ 'FindWidget.togglePreserveCase': togglePreserveCase,
10698
10790
  'Font.ensure': ensure,
10699
10791
  'HandleMessagePort.handleMessagePort': handleMessagePort,
10700
10792
  'Hover.getHoverInfo': getEditorHoverInfo,