@lvce-editor/editor-worker 9.1.0 → 10.1.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 +1768 -1671
  2. package/package.json +2 -2
@@ -1066,6 +1066,39 @@ const createMockRpc = ({
1066
1066
  return mockRpc;
1067
1067
  };
1068
1068
 
1069
+ const Backspace = 1;
1070
+ const Tab$1 = 2;
1071
+ const Enter = 3;
1072
+ const Escape = 8;
1073
+ const Space$1 = 9;
1074
+ const End = 255;
1075
+ const Home = 12;
1076
+ const LeftArrow = 13;
1077
+ const UpArrow = 14;
1078
+ const RightArrow = 15;
1079
+ const DownArrow = 16;
1080
+ const Delete = 18;
1081
+ const KeyA = 29;
1082
+ const KeyC = 31;
1083
+ const KeyD = 32;
1084
+ const KeyF = 34;
1085
+ const KeyH = 36;
1086
+ const KeyJ = 38;
1087
+ const KeyK = 39;
1088
+ const KeyL = 40;
1089
+ const KeyO = 43;
1090
+ const KeyV = 50;
1091
+ const KeyX = 52;
1092
+ const KeyZ = 54;
1093
+ const F2 = 58;
1094
+ const F3 = 59;
1095
+ const F4 = 60;
1096
+ const F12 = 68;
1097
+ const Period = 87;
1098
+ const Slash$1 = 88;
1099
+ const BracketLeft = 90;
1100
+ const BracketRight = 92;
1101
+
1069
1102
  const CodeGenerator = 1;
1070
1103
  const ColorPicker$1 = 2;
1071
1104
  const Completion = 3;
@@ -1075,6 +1108,10 @@ const Hover = 6;
1075
1108
  const Rename$1 = 7;
1076
1109
  const SourceAction$1 = 8;
1077
1110
 
1111
+ const CtrlCmd = 1 << 11 >>> 0;
1112
+ const Shift = 1 << 10 >>> 0;
1113
+ const Alt$1 = 1 << 9 >>> 0;
1114
+
1078
1115
  const DebugWorker = 55;
1079
1116
  const EditorWorker = 99;
1080
1117
  const ExtensionHostWorker = 44;
@@ -1774,574 +1811,1272 @@ const setDeltaY$2 = (state, value) => {
1774
1811
  };
1775
1812
  };
1776
1813
 
1777
- const splitLines = lines => {
1778
- if (!lines) {
1779
- return [''];
1814
+ const Link$1 = 'Link';
1815
+ const Function = 'Function';
1816
+ const Parameter = 'Parameter';
1817
+ const Type = 'Type';
1818
+ const VariableName = 'VariableName';
1819
+ const Class = 'Class';
1820
+
1821
+ const Link = 1;
1822
+ const Ts2816 = 2816;
1823
+ const Ts2817 = 2817;
1824
+ const Ts2824 = 2824;
1825
+ const Ts2825 = 2825;
1826
+ const Ts2856 = 2956;
1827
+ const Ts2857 = 2857;
1828
+ const Ts3072 = 3072;
1829
+ const Ts3073 = 3073;
1830
+ const Ts3077 = 3077;
1831
+ const Ts3088 = 3088;
1832
+ const Ts1792 = 1792;
1833
+ const Ts1793 = 1793;
1834
+ const Ts512 = 512;
1835
+ const Ts513 = 513;
1836
+ const Ts769 = 769;
1837
+ const Ts1024 = 1024;
1838
+ const Ts1536 = 1536;
1839
+ const Ts1537 = 1537;
1840
+ const Ts1544 = 1544;
1841
+ const Ts1545 = 1545;
1842
+ const Ts2048 = 2048;
1843
+ const Ts2049 = 2049;
1844
+ const Ts2056 = 2056;
1845
+ const Ts2057 = 2057;
1846
+ const Ts2064 = 2064;
1847
+ const Ts2080 = 2080;
1848
+ const Ts2081 = 2081;
1849
+ const Ts2088 = 2088;
1850
+ const Ts2089 = 2089;
1851
+ const Ts2313 = 2313;
1852
+ const Ts2560 = 2560;
1853
+ const Ts2561 = 2561;
1854
+ const Ts2569 = 2569;
1855
+ const Ts2584 = 2584;
1856
+ const Ts256 = 256;
1857
+ const Ts257 = 257;
1858
+ const Ts272 = 272;
1859
+
1860
+ const getDecorationClassName = type => {
1861
+ switch (type) {
1862
+ case Link:
1863
+ return Link$1;
1864
+ case Ts2816:
1865
+ case Ts2817:
1866
+ case Ts2824:
1867
+ case Ts2825:
1868
+ case Ts2856:
1869
+ case Ts2857:
1870
+ case Ts3072:
1871
+ case Ts3073:
1872
+ case Ts3077:
1873
+ case Ts3088:
1874
+ return Function;
1875
+ case Ts1792:
1876
+ case Ts1793:
1877
+ return Parameter;
1878
+ case Ts512:
1879
+ case Ts513:
1880
+ case Ts769:
1881
+ case Ts1024:
1882
+ case Ts1536:
1883
+ case Ts1537:
1884
+ case Ts1544:
1885
+ case Ts1545:
1886
+ return Type;
1887
+ case Ts2048:
1888
+ case Ts2049:
1889
+ case Ts2056:
1890
+ case Ts2057:
1891
+ case Ts2064:
1892
+ case Ts2080:
1893
+ case Ts2081:
1894
+ case Ts2088:
1895
+ case Ts2089:
1896
+ case Ts2313:
1897
+ case Ts2560:
1898
+ case Ts2561:
1899
+ case Ts2569:
1900
+ case Ts2584:
1901
+ return VariableName;
1902
+ case Ts256:
1903
+ case Ts257:
1904
+ case Ts272:
1905
+ return Class;
1906
+ default:
1907
+ return `Unknown-${type}`;
1780
1908
  }
1781
- return lines.split('\n');
1782
1909
  };
1783
1910
 
1784
- // based on https://github.com/microsoft/vscode/blob/c0769274fa136b45799edeccc0d0a2f645b75caf/src/vs/base/common/arrays.ts#L625 (License MIT)
1911
+ const deepCopy = value => {
1912
+ return structuredClone(value);
1913
+ };
1785
1914
 
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];
1915
+ const getInitialLineState = initialLineState => {
1916
+ return deepCopy(initialLineState);
1917
+ };
1918
+
1919
+ const state$8 = {
1920
+ warned: []
1921
+ };
1922
+ const flattenTokensArray = tokens => {
1923
+ const flattened = [];
1924
+ for (const token of tokens) {
1925
+ object(token);
1926
+ flattened.push(token.type, token.length);
1794
1927
  }
1795
- for (let i = 0; i < newItemsLength; i++) {
1796
- array[i + start] = newItems[i];
1928
+ return flattened;
1929
+ };
1930
+ const warnDeprecatedArrayReturn = (languageId, fn) => {
1931
+ if (state$8.warned.includes(fn)) {
1932
+ return;
1933
+ }
1934
+ state$8.warned.push(fn);
1935
+ console.warn(`tokenizers without hasArrayReturn=false are deprecated (language ${languageId})`);
1936
+ };
1937
+ const safeTokenizeLine = (languageId, tokenizeLine, line, lineStateAtStart, hasArrayReturn) => {
1938
+ try {
1939
+ const lineState = tokenizeLine(line, lineStateAtStart);
1940
+ if (!lineState?.tokens || !lineState.state) {
1941
+ throw new Error('invalid tokenization result');
1942
+ }
1943
+ if (!hasArrayReturn) {
1944
+ warnDeprecatedArrayReturn(languageId, tokenizeLine);
1945
+ // workaround for old tokenizers
1946
+ lineState.tokens = flattenTokensArray(lineState.tokens);
1947
+ }
1948
+ return lineState;
1949
+ } catch (error) {
1950
+ console.error(error);
1951
+ return {
1952
+ tokens: [/* type */0, /* length */line.length],
1953
+ lineState: lineStateAtStart
1954
+ };
1797
1955
  }
1798
1956
  };
1799
1957
 
1800
1958
  /**
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.
1959
+ * @enum number
1803
1960
  */
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;
1961
+ const State = {
1962
+ TopLevelContent: 1
1809
1963
  };
1810
1964
 
1811
- const joinLines = lines => {
1812
- return lines.join('\n');
1965
+ /**
1966
+ * @enum number
1967
+ */
1968
+ const TokenType = {
1969
+ Text: 1
1970
+ };
1971
+ const TokenMap = {
1972
+ [TokenType.Text]: 'Text'
1973
+ };
1974
+ const initialLineState = {
1975
+ state: State.TopLevelContent
1976
+ };
1977
+ const hasArrayReturn = true;
1978
+ const tokenizeLine = (line, lineState) => {
1979
+ return {
1980
+ tokens: [TokenType.Text, line.length],
1981
+ state: lineState.state
1982
+ };
1813
1983
  };
1814
1984
 
1815
- const RE_WHITESPACE = /^\s+/;
1985
+ const TokenizePlainText = {
1986
+ __proto__: null,
1987
+ State,
1988
+ TokenMap,
1989
+ TokenType,
1990
+ hasArrayReturn,
1991
+ initialLineState,
1992
+ tokenizeLine
1993
+ };
1816
1994
 
1817
- // TODO this doesn't belong here
1818
- const getIndent = line => {
1819
- const whitespaceMatch = line.match(RE_WHITESPACE);
1820
- if (!whitespaceMatch) {
1821
- return '';
1822
- }
1823
- return whitespaceMatch[0];
1995
+ let enabled$1 = false;
1996
+ const setEnabled$1 = value => {
1997
+ enabled$1 = value;
1998
+ };
1999
+ const getEnabled$1 = () => {
2000
+ return enabled$1;
1824
2001
  };
1825
2002
 
1826
- // TODO have function for single edit (most common, avoid one array)
1827
- const applyEdits = (textDocument, changes) => {
1828
- object(textDocument);
1829
- array(changes);
1830
- // TODO don't copy all lines (can be expensive, e.g. 10000 lines = 10000 * 64bit = 64kB on every keystroke)
1831
- const newLines = [...textDocument.lines];
1832
- let linesDelta = 0;
1833
- for (const change of changes) {
1834
- const startRowIndex = change.start.rowIndex + linesDelta;
1835
- const endRowIndex = change.end.rowIndex + linesDelta;
1836
- const startColumnIndex = change.start.columnIndex;
1837
- const endColumnIndex = change.end.columnIndex;
1838
- const {
1839
- inserted
1840
- } = change;
1841
- const {
1842
- deleted
1843
- } = change;
1844
- number(startRowIndex);
1845
- number(endRowIndex);
1846
- number(startColumnIndex);
1847
- number(endColumnIndex);
1848
- array(inserted);
1849
- array(deleted);
1850
- if (startRowIndex === endRowIndex) {
1851
- if (inserted.length === 0) {
1852
- const line = newLines[startRowIndex];
1853
- const before = line.slice(0, startColumnIndex);
1854
- const after = line.slice(endColumnIndex);
1855
- newLines[startRowIndex] = before + after;
1856
- } else if (inserted.length === 1) {
1857
- const line = newLines[startRowIndex];
1858
- let before = line.slice(0, startColumnIndex);
1859
- if (startColumnIndex > line.length) {
1860
- before += ' '.repeat(startColumnIndex - line.length);
1861
- }
1862
- const after = line.slice(endColumnIndex);
1863
- const text = inserted[0];
1864
- newLines[startRowIndex] = before + text + after;
1865
- } else {
1866
- const line = newLines[startRowIndex];
1867
- const before = line.slice(0, startColumnIndex) + inserted[0];
1868
- const after = inserted.at(-1) + line.slice(endColumnIndex);
1869
- spliceLargeArray(newLines, startRowIndex, deleted.length, [before, ...inserted.slice(1, -1), after]);
1870
- // TODO only do this once after all edits, not inside loop
1871
- textDocument.maxLineY = Math.min(textDocument.numberOfVisibleLines, newLines.length);
1872
- }
1873
- } else {
1874
- if (inserted.length === 1) {
1875
- const before = newLines[startRowIndex].slice(0, startColumnIndex) + inserted[0];
1876
- const after = endRowIndex >= newLines.length ? '' : newLines[endRowIndex].slice(endColumnIndex);
1877
- spliceLargeArray(newLines, startRowIndex, deleted.length, [before + after]);
1878
- } else {
1879
- const before = newLines[startRowIndex].slice(0, startColumnIndex) + inserted[0];
1880
- const middle = inserted.slice(1, -1);
1881
- const after = inserted.at(-1) + (endRowIndex >= newLines.length ? '' : newLines[endRowIndex].slice(endColumnIndex));
1882
- spliceLargeArray(newLines, startRowIndex, deleted.length, [before, ...middle, after]);
1883
- }
1884
- // TODO only do this once after all edits, not inside loop
1885
- textDocument.maxLineY = Math.min(textDocument.numberOfVisibleLines, textDocument.lines.length);
1886
- }
1887
- linesDelta += inserted.length - deleted.length;
1888
- }
1889
- return newLines;
2003
+ const {
2004
+ set: set$5,
2005
+ invoke: invoke$7} = SyntaxHighlightingWorker;
2006
+
2007
+ const state$7 = {
2008
+ tokenizers: Object.create(null),
2009
+ pending: Object.create(null)};
2010
+ const has = languageId => {
2011
+ return languageId in state$7.tokenizers;
1890
2012
  };
1891
- const getLine = (textDocument, index) => {
1892
- return textDocument.lines[index];
2013
+ const set$4 = (languageId, tokenizer) => {
2014
+ state$7.tokenizers[languageId] = tokenizer;
1893
2015
  };
1894
- const getText$1 = state => {
1895
- return joinLines(state.lines);
2016
+ const get$3 = languageId => {
2017
+ return state$7.tokenizers[languageId];
2018
+ };
2019
+ const isPending = languageId => {
2020
+ return languageId in state$7.pending;
1896
2021
  };
1897
2022
 
1898
- // TDOO this doesn;t belong here
1899
- const getSelectionText = (textDocument, range) => {
1900
- object(textDocument);
1901
- const startRowIndex = range.start.rowIndex;
1902
- const startColumnIndex = range.start.columnIndex;
1903
- const endRowIndex = Math.min(range.end.rowIndex, textDocument.lines.length - 1);
1904
- const endColumnIndex = range.end.columnIndex;
1905
- if (startRowIndex === endRowIndex) {
1906
- return [textDocument.lines[startRowIndex].slice(startColumnIndex, endColumnIndex)];
1907
- }
1908
- const selectedLines = [textDocument.lines[startRowIndex].slice(startColumnIndex), ...textDocument.lines.slice(startRowIndex + 1, endRowIndex), textDocument.lines[endRowIndex].slice(0, endColumnIndex)];
1909
- return selectedLines;
2023
+ const tokenMaps = Object.create(null);
2024
+ const set$3 = (languageId, tokenMap) => {
2025
+ tokenMaps[languageId] = tokenMap;
1910
2026
  };
1911
- const offsetAtSync = async (textDocument, positionRowIndex, positionColumnIndex) => {
1912
- object(textDocument);
1913
- number(positionRowIndex);
1914
- number(positionColumnIndex);
1915
- let offset = 0;
1916
- let rowIndex = 0;
1917
- const {
1918
- lines
1919
- } = textDocument;
1920
- const max = Math.min(positionRowIndex, textDocument.lines.length);
1921
- while (rowIndex < max) {
1922
- offset += lines[rowIndex].length + 1;
1923
- rowIndex++;
1924
- }
1925
- offset += positionColumnIndex;
1926
- return offset;
2027
+ const get$2 = languageId => {
2028
+ return tokenMaps[languageId] || {};
1927
2029
  };
1928
- const offsetAt = (textDocument, positionRowIndex, positionColumnIndex) => {
1929
- object(textDocument);
1930
- number(positionRowIndex);
1931
- number(positionColumnIndex);
1932
- let offset = 0;
1933
- let rowIndex = 0;
1934
- const {
1935
- lines
1936
- } = textDocument;
1937
- const max = Math.min(positionRowIndex, textDocument.lines.length);
1938
- while (rowIndex < max) {
1939
- offset += lines[rowIndex].length + 1;
1940
- rowIndex++;
2030
+
2031
+ // TODO loadTokenizer should be invoked from renderer worker
2032
+ const loadTokenizer = async (languageId, tokenizePath) => {
2033
+ if (!tokenizePath) {
2034
+ return;
1941
2035
  }
1942
- offset += positionColumnIndex;
1943
- return offset;
1944
- };
1945
- const positionAt = (textDocument, offset) => {
1946
- const {
1947
- lines
1948
- } = textDocument;
1949
- let rowIndex = 0;
1950
- let columnIndex = 0;
1951
- let currentOffset = 0;
1952
- while (rowIndex < lines.length && currentOffset < offset) {
1953
- currentOffset += lines[rowIndex].length + 1;
1954
- rowIndex++;
2036
+ if (getEnabled$1()) {
2037
+ // @ts-ignore
2038
+ const tokenMap = await invoke$7('Tokenizer.load', languageId, tokenizePath);
2039
+ set$3(languageId, tokenMap);
2040
+ return;
1955
2041
  }
1956
- if (currentOffset > offset) {
1957
- rowIndex--;
1958
- currentOffset -= lines[rowIndex].length + 1;
1959
- columnIndex = offset - currentOffset;
1960
- } else {
1961
- columnIndex = currentOffset - offset;
2042
+ try {
2043
+ // TODO check that tokenizer is valid
2044
+ // 1. tokenizeLine should be of type function
2045
+ // 2. getTokenClass should be of type function
2046
+ const tokenizer = await import(tokenizePath);
2047
+ if (typeof tokenizer.tokenizeLine !== 'function') {
2048
+ console.warn(`tokenizer.tokenizeLine should be a function in "${tokenizePath}"`);
2049
+ return;
2050
+ }
2051
+ if (!tokenizer.TokenMap || typeof tokenizer.TokenMap !== 'object' || Array.isArray(tokenizer.TokenMap)) {
2052
+ console.warn(`tokenizer.TokenMap should be an object in "${tokenizePath}"`);
2053
+ return;
2054
+ }
2055
+ set$3(languageId, tokenizer.TokenMap);
2056
+ set$4(languageId, tokenizer);
2057
+ } catch (error) {
2058
+ // TODO better error handling
2059
+ console.error(error);
1962
2060
  }
1963
- return {
1964
- rowIndex,
1965
- columnIndex
1966
- };
1967
2061
  };
1968
-
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];
2062
+ const getTokenizer = languageId => {
2063
+ if (has(languageId)) {
2064
+ return get$3(languageId);
1976
2065
  }
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 = '"';
1985
-
1986
- const getTabCount = string => {
1987
- let count = 0;
1988
- for (const element of string) {
1989
- if (element === Tab$1) {
1990
- count++;
1991
- }
2066
+ if (isPending(languageId)) {
2067
+ return TokenizePlainText;
1992
2068
  }
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}`;
2069
+ return TokenizePlainText;
2002
2070
  };
2003
2071
 
2004
- const getLetterSpacingString = letterSpacing => {
2005
- return `${letterSpacing}px`;
2072
+ const tokenizers = Object.create(null);
2073
+ const set$2 = (id, value) => {
2074
+ tokenizers[id] = value;
2006
2075
  };
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');
2013
- }
2014
- return ctx;
2076
+ const get$1 = id => {
2077
+ return tokenizers[id] || TokenizePlainText;
2015
2078
  };
2016
2079
 
2017
- const state$8 = {
2018
- ctx: undefined
2019
- };
2020
- const getOrCreate$4 = createCtx => {
2021
- if (state$8.ctx) {
2022
- return state$8.ctx;
2080
+ const getTokensViewportEmbedded = (langageId, lines, lineCache, linesWithEmbed) => {
2081
+ const tokenizersToLoad = [];
2082
+ const embeddedResults = [];
2083
+ let topContext;
2084
+ for (const index of linesWithEmbed) {
2085
+ const result = lineCache[index + 1];
2086
+ const line = lines[index];
2087
+ if (result.embeddedLanguage) {
2088
+ const {
2089
+ embeddedLanguage,
2090
+ embeddedLanguageStart,
2091
+ embeddedLanguageEnd
2092
+ } = result;
2093
+ const embeddedTokenizer = getTokenizer(embeddedLanguage);
2094
+ if (embeddedLanguageStart !== line.length && embeddedTokenizer && embeddedTokenizer !== TokenizePlainText) {
2095
+ const isFull = embeddedLanguageStart === 0 && embeddedLanguageEnd === line.length;
2096
+ const partialLine = line.slice(embeddedLanguageStart, embeddedLanguageEnd);
2097
+ const embedResult = safeTokenizeLine(langageId, embeddedTokenizer.tokenizeLine, partialLine, topContext || getInitialLineState(embeddedTokenizer.initialLineState), embeddedTokenizer.hasArrayReturn);
2098
+ topContext = embedResult;
2099
+ result.embeddedResultIndex = embeddedResults.length;
2100
+ embeddedResults.push({
2101
+ result: embedResult,
2102
+ TokenMap: embeddedTokenizer.TokenMap,
2103
+ isFull
2104
+ });
2105
+ } else if (line.length === 0) {
2106
+ const embedResult = {
2107
+ tokens: []
2108
+ };
2109
+ result.embeddedResultIndex = embeddedResults.length;
2110
+ embeddedResults.push({
2111
+ result: embedResult,
2112
+ isFull: true,
2113
+ TokenMap: []
2114
+ });
2115
+ } else {
2116
+ tokenizersToLoad.push(embeddedLanguage);
2117
+ embeddedResults.push({
2118
+ result: {},
2119
+ isFull: false,
2120
+ TokenMap: []
2121
+ });
2122
+ topContext = undefined;
2123
+ }
2124
+ } else {
2125
+ topContext = undefined;
2126
+ }
2023
2127
  }
2024
- state$8.ctx = createCtx();
2025
- return state$8.ctx;
2128
+ return {
2129
+ tokenizersToLoad,
2130
+ embeddedResults
2131
+ };
2026
2132
  };
2027
-
2028
- const getContext = () => {
2029
- const ctx = getOrCreate$4(createMeasureContext);
2030
- return ctx;
2133
+ const getTokenizeEndIndex = (invalidStartIndex, endLineIndex, tokenizeStartIndex) => {
2134
+ return invalidStartIndex < endLineIndex ? endLineIndex : tokenizeStartIndex;
2031
2135
  };
2032
2136
 
2033
- // TODO for text editor, could dispose measuring canvas after editor has been initialized to free up offscreencanvas space
2137
+ // TODO only send changed lines to renderer process instead of all lines in viewport
2138
+ const getTokensViewport = (editor, startLineIndex, endLineIndex) => {
2139
+ const {
2140
+ invalidStartIndex,
2141
+ lineCache,
2142
+ tokenizerId,
2143
+ lines,
2144
+ languageId
2145
+ } = editor;
2146
+ const tokenizer = get$1(tokenizerId);
2147
+ const {
2148
+ hasArrayReturn,
2149
+ tokenizeLine,
2150
+ initialLineState
2151
+ } = tokenizer;
2152
+ const tokenizeStartIndex = invalidStartIndex;
2153
+ const tokenizeEndIndex = getTokenizeEndIndex(invalidStartIndex, endLineIndex, tokenizeStartIndex);
2154
+ const tokenizersToLoad = [];
2155
+ const embeddedResults = [];
2156
+ const linesWithEmbed = [];
2157
+ for (let i = tokenizeStartIndex; i < tokenizeEndIndex; i++) {
2158
+ const lineState = i === 0 ? getInitialLineState(initialLineState) : lineCache[i];
2159
+ const line = lines[i];
2160
+ const result = safeTokenizeLine(languageId, tokenizeLine, line, lineState, hasArrayReturn);
2161
+ // TODO if lineCacheEnd matches the one before, skip tokenizing lines after
2162
+ lineCache[i + 1] = result;
2163
+ if (result.embeddedLanguage) {
2164
+ result.embeddedResultIndex = linesWithEmbed.length;
2165
+ linesWithEmbed.push(i);
2166
+ }
2167
+ }
2168
+ const visibleLines = lineCache.slice(startLineIndex + 1, endLineIndex + 1);
2169
+ if (linesWithEmbed.length > 0) {
2170
+ const {
2171
+ tokenizersToLoad,
2172
+ embeddedResults
2173
+ } = getTokensViewportEmbedded(languageId, lines, lineCache, linesWithEmbed);
2174
+ // TODO support lineCache with embedded content
2175
+ editor.invalidStartIndex = 0;
2176
+ return {
2177
+ tokens: visibleLines,
2178
+ tokenizersToLoad,
2179
+ embeddedResults
2180
+ };
2181
+ }
2182
+ editor.invalidStartIndex = Math.max(invalidStartIndex, tokenizeEndIndex);
2183
+ return {
2184
+ tokens: visibleLines,
2185
+ tokenizersToLoad,
2186
+ embeddedResults
2187
+ };
2188
+ };
2034
2189
 
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');
2190
+ const sentLines = Object.create(null);
2191
+
2192
+ // TODO only send changed lines to renderer process instead of all lines in viewport
2193
+ const getTokensViewport2 = async (editor, startLineIndex, endLineIndex, syncIncremental) => {
2194
+ if (getEnabled$1()) {
2195
+ if (syncIncremental) {
2196
+ const {
2197
+ invalidStartIndex,
2198
+ lines,
2199
+ languageId,
2200
+ id
2201
+ } = editor;
2202
+ let hasLinesToSend = true;
2203
+ let linesToSend = lines;
2204
+ if (sentLines[id] === lines) {
2205
+ hasLinesToSend = false;
2206
+ linesToSend = [];
2207
+ } else {
2208
+ sentLines[id] = lines;
2209
+ }
2210
+ const slimEditor = {
2211
+ languageId,
2212
+ invalidStartIndex
2213
+ };
2214
+ return invoke$7('GetTokensViewport.getTokensViewport', slimEditor,
2215
+ // @ts-ignore
2216
+ startLineIndex, endLineIndex, hasLinesToSend, id, linesToSend);
2217
+ }
2218
+ // TODO only send needed lines of text
2219
+ // @ts-ignore
2220
+ return invoke$7('GetTokensViewport.getTokensViewport', editor, startLineIndex, endLineIndex, true, editor.id, editor.lines);
2044
2221
  }
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
- const {
2052
- width
2053
- } = metrics;
2054
- return width;
2222
+ return getTokensViewport(editor, startLineIndex, endLineIndex);
2055
2223
  };
2056
2224
 
2057
- const measureTextWidth = (text, fontWeight, fontSize, fontFamily, letterSpacing, isMonoSpaceFont, charWidth) => {
2058
- if (isMonoSpaceFont) {
2059
- return measureTextWidthFast(text, charWidth);
2225
+ const loadTokenizers = async languageIds => {
2226
+ for (const languageId of languageIds) {
2227
+ // @ts-ignore
2228
+ await loadTokenizer(languageId);
2060
2229
  }
2061
- return measureTextWidthSlow(text, fontWeight, fontSize, fontFamily, letterSpacing, isMonoSpaceFont, charWidth);
2062
2230
  };
2063
2231
 
2232
+ const EmptyString = '';
2233
+ const NewLine = '\n';
2234
+ const Space = ' ';
2235
+ const Tab = '\t';
2236
+ const DoubleQuote$1 = '"';
2237
+
2064
2238
  const normalizeText = (text, normalize, tabSize) => {
2065
2239
  if (normalize) {
2066
- return text.replaceAll(Tab$1, Space$1.repeat(tabSize));
2240
+ return text.replaceAll(Tab, Space.repeat(tabSize));
2067
2241
  }
2068
2242
  return text;
2069
2243
  };
2070
2244
  const shouldNormalizeText = text => {
2071
- return text.includes(Tab$1);
2245
+ return text.includes(Tab);
2072
2246
  };
2073
2247
 
2074
- const getX = (line, column, fontWeight, fontSize, fontFamily, isMonospaceFont, letterSpacing, tabSize, halfCursorWidth, width, averageCharWidth, difference = 0) => {
2075
- if (!line) {
2076
- return 0;
2077
- }
2078
- string(line);
2079
- number(tabSize);
2080
- number(halfCursorWidth);
2081
- number(width);
2082
- boolean(isMonospaceFont);
2083
- number(averageCharWidth);
2084
- number(difference);
2085
- if (column === 0) {
2086
- return 0;
2248
+ // based on https://github.com/microsoft/vscode/blob/c0769274fa136b45799edeccc0d0a2f645b75caf/src/vs/base/common/arrays.ts#L625 (License MIT)
2249
+
2250
+ // @ts-ignore
2251
+ const insertInto = (array, start, newItems) => {
2252
+ const originalLength = array.length;
2253
+ const newItemsLength = newItems.length;
2254
+ array.length = originalLength + newItemsLength;
2255
+ // Move the items after the start index, start from the end so that we don't overwrite any value.
2256
+ for (let i = originalLength - 1; i >= start; i--) {
2257
+ array[i + newItemsLength] = array[i];
2087
2258
  }
2088
- // TODO support non-monospace font, emoji, tab character, zero width characters
2089
- if (column * averageCharWidth > width) {
2090
- return width;
2259
+ for (let i = 0; i < newItemsLength; i++) {
2260
+ array[i + start] = newItems[i];
2091
2261
  }
2092
- const normalize = shouldNormalizeText(line);
2093
- const normalizedLine = normalizeText(line, normalize, tabSize);
2094
- const tabCount = getTabCount(line.slice(0, column));
2095
- const partialText = normalizedLine.slice(0, column + tabCount);
2096
- return measureTextWidth(partialText, fontWeight, fontSize, fontFamily, letterSpacing, isMonospaceFont, averageCharWidth) - halfCursorWidth + difference;
2097
2262
  };
2098
2263
 
2099
- const getY = (row, minLineY, rowHeight) => {
2100
- return (row - minLineY) * rowHeight;
2264
+ /**
2265
+ * Alternative to the native Array.splice method, it
2266
+ * can only support limited number of items due to the maximum call stack size limit.
2267
+ */
2268
+ // @ts-ignore
2269
+ const spliceLargeArray = (array, start, deleteCount, newItems) => {
2270
+ const result = array.splice(start, deleteCount);
2271
+ insertInto(array, start, newItems);
2272
+ return result;
2101
2273
  };
2102
2274
 
2103
- const px = value => {
2104
- return `${value}px`;
2275
+ const joinLines = lines => {
2276
+ return lines.join('\n');
2105
2277
  };
2106
2278
 
2107
- const fromRange = (startRowIndex, startColumnIndex, endRowIndex, endColumnIndex) => {
2108
- return new Uint32Array([startRowIndex, startColumnIndex, endRowIndex, endColumnIndex]);
2109
- };
2110
- const alloc = length => {
2111
- return new Uint32Array(length);
2112
- };
2113
- const clone = selections => {
2114
- return alloc(selections.length);
2115
- };
2116
- const map = (selections, fn) => {
2117
- const newSelections = clone(selections);
2118
- for (let i = 0; i < newSelections.length; i += 4) {
2119
- const [selectionStartRow, selectionStartColumn, selectionEndRow, selectionEndColumn] = getSelectionPairs(selections, i);
2120
- fn(newSelections, i, selectionStartRow, selectionStartColumn, selectionEndRow, selectionEndColumn);
2279
+ const RE_WHITESPACE = /^\s+/;
2280
+
2281
+ // TODO this doesn't belong here
2282
+ const getIndent = line => {
2283
+ const whitespaceMatch = line.match(RE_WHITESPACE);
2284
+ if (!whitespaceMatch) {
2285
+ return '';
2121
2286
  }
2122
- return newSelections;
2287
+ return whitespaceMatch[0];
2123
2288
  };
2124
- const forEach = (selections, fn) => {
2125
- for (let i = 0; i < selections.length; i += 4) {
2126
- const selectionStartRow = selections[i];
2127
- const selectionStartColumn = selections[i + 1];
2128
- const selectionEndRow = selections[i + 2];
2129
- const selectionEndColumn = selections[i + 3];
2130
- fn(selectionStartRow, selectionStartColumn, selectionEndRow, selectionEndColumn);
2289
+
2290
+ // TODO have function for single edit (most common, avoid one array)
2291
+ const applyEdits = (textDocument, changes) => {
2292
+ object(textDocument);
2293
+ array(changes);
2294
+ // TODO don't copy all lines (can be expensive, e.g. 10000 lines = 10000 * 64bit = 64kB on every keystroke)
2295
+ const newLines = [...textDocument.lines];
2296
+ let linesDelta = 0;
2297
+ for (const change of changes) {
2298
+ const startRowIndex = change.start.rowIndex + linesDelta;
2299
+ const endRowIndex = change.end.rowIndex + linesDelta;
2300
+ const startColumnIndex = change.start.columnIndex;
2301
+ const endColumnIndex = change.end.columnIndex;
2302
+ const {
2303
+ inserted
2304
+ } = change;
2305
+ const {
2306
+ deleted
2307
+ } = change;
2308
+ number(startRowIndex);
2309
+ number(endRowIndex);
2310
+ number(startColumnIndex);
2311
+ number(endColumnIndex);
2312
+ array(inserted);
2313
+ array(deleted);
2314
+ if (startRowIndex === endRowIndex) {
2315
+ if (inserted.length === 0) {
2316
+ const line = newLines[startRowIndex];
2317
+ const before = line.slice(0, startColumnIndex);
2318
+ const after = line.slice(endColumnIndex);
2319
+ newLines[startRowIndex] = before + after;
2320
+ } else if (inserted.length === 1) {
2321
+ const line = newLines[startRowIndex];
2322
+ let before = line.slice(0, startColumnIndex);
2323
+ if (startColumnIndex > line.length) {
2324
+ before += ' '.repeat(startColumnIndex - line.length);
2325
+ }
2326
+ const after = line.slice(endColumnIndex);
2327
+ const text = inserted[0];
2328
+ newLines[startRowIndex] = before + text + after;
2329
+ } else {
2330
+ const line = newLines[startRowIndex];
2331
+ const before = line.slice(0, startColumnIndex) + inserted[0];
2332
+ const after = inserted.at(-1) + line.slice(endColumnIndex);
2333
+ spliceLargeArray(newLines, startRowIndex, deleted.length, [before, ...inserted.slice(1, -1), after]);
2334
+ // TODO only do this once after all edits, not inside loop
2335
+ textDocument.maxLineY = Math.min(textDocument.numberOfVisibleLines, newLines.length);
2336
+ }
2337
+ } else {
2338
+ if (inserted.length === 1) {
2339
+ const before = newLines[startRowIndex].slice(0, startColumnIndex) + inserted[0];
2340
+ const after = endRowIndex >= newLines.length ? '' : newLines[endRowIndex].slice(endColumnIndex);
2341
+ spliceLargeArray(newLines, startRowIndex, deleted.length, [before + after]);
2342
+ } else {
2343
+ const before = newLines[startRowIndex].slice(0, startColumnIndex) + inserted[0];
2344
+ const middle = inserted.slice(1, -1);
2345
+ const after = inserted.at(-1) + (endRowIndex >= newLines.length ? '' : newLines[endRowIndex].slice(endColumnIndex));
2346
+ spliceLargeArray(newLines, startRowIndex, deleted.length, [before, ...middle, after]);
2347
+ }
2348
+ // TODO only do this once after all edits, not inside loop
2349
+ textDocument.maxLineY = Math.min(textDocument.numberOfVisibleLines, textDocument.lines.length);
2350
+ }
2351
+ linesDelta += inserted.length - deleted.length;
2131
2352
  }
2353
+ return newLines;
2132
2354
  };
2133
- const moveRangeToPosition$1 = (selections, i, rowIndex, columnIndex) => {
2134
- selections[i] = selections[i + 2] = rowIndex;
2135
- selections[i + 1] = selections[i + 3] = columnIndex;
2136
- };
2137
- const isEmpty = (selectionStartRow, selectionStartColumn, selectionEndRow, selectionEndColumn) => {
2138
- return selectionStartRow === selectionEndRow && selectionStartColumn === selectionEndColumn;
2139
- };
2140
- const isSelectionSingleLine = (selectionStartRow, selectionStartColumn, selectionEndRow, selectionEndColumn) => {
2141
- return selectionStartRow === selectionEndRow;
2142
- };
2143
- const isEverySelection = (selections, fn) => {
2144
- for (let i = 0; i < selections.length; i += 4) {
2145
- const selectionStartRow = selections[i];
2146
- const selectionStartColumn = selections[i + 1];
2147
- const selectionEndRow = selections[i + 2];
2148
- const selectionEndColumn = selections[i + 3];
2149
- if (!fn(selectionStartRow, selectionStartColumn, selectionEndRow, selectionEndColumn)) {
2150
- return false;
2151
- }
2152
- }
2153
- return true;
2154
- };
2155
- const isEverySelectionEmpty = selections => {
2156
- return isEverySelection(selections, isEmpty);
2157
- };
2158
- const isEverySelectionSingleLine = selections => {
2159
- return isEverySelection(selections, isSelectionSingleLine);
2160
- };
2161
- const from = (array, getSelection) => {
2162
- const newSelections = alloc(array.length * 4);
2163
- let i = 0;
2164
- for (const item of array) {
2165
- const {
2166
- start,
2167
- end
2168
- } = getSelection(item);
2169
- newSelections[i++] = start.rowIndex;
2170
- newSelections[i++] = start.columnIndex;
2171
- newSelections[i++] = end.rowIndex;
2172
- newSelections[i++] = end.columnIndex;
2173
- }
2174
- return newSelections;
2355
+ const getLine = (textDocument, index) => {
2356
+ return textDocument.lines[index];
2175
2357
  };
2176
- const push = (selections, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex) => {
2177
- const oldLength = selections.length;
2178
- const newSelections = alloc(oldLength + 4);
2179
- newSelections.set(selections);
2180
- newSelections[oldLength + 1] = startRowIndex;
2181
- newSelections[oldLength + 2] = startColumnIndex;
2182
- newSelections[oldLength + 3] = endRowIndex;
2183
- newSelections[oldLength + 4] = endColumnIndex;
2184
- return newSelections;
2358
+ const getText$1 = state => {
2359
+ return joinLines(state.lines);
2185
2360
  };
2186
2361
 
2187
- // TODO maybe only accept sorted selection edits in the first place
2188
-
2189
- const emptyCursors = [];
2190
- const getCursorArray = (visibleCursors, isFocused) => {
2191
- if (!isFocused) {
2192
- return emptyCursors;
2193
- }
2194
- const cursorArray = [];
2195
- for (let i = 0; i < visibleCursors.length; i += 2) {
2196
- const x = visibleCursors[i];
2197
- const y = visibleCursors[i + 1];
2198
- cursorArray.push(`${px(x)} ${px(y)}`);
2362
+ // TDOO this doesn;t belong here
2363
+ const getSelectionText = (textDocument, range) => {
2364
+ object(textDocument);
2365
+ const startRowIndex = range.start.rowIndex;
2366
+ const startColumnIndex = range.start.columnIndex;
2367
+ const endRowIndex = Math.min(range.end.rowIndex, textDocument.lines.length - 1);
2368
+ const endColumnIndex = range.end.columnIndex;
2369
+ if (startRowIndex === endRowIndex) {
2370
+ return [textDocument.lines[startRowIndex].slice(startColumnIndex, endColumnIndex)];
2199
2371
  }
2200
- return cursorArray;
2372
+ const selectedLines = [textDocument.lines[startRowIndex].slice(startColumnIndex), ...textDocument.lines.slice(startRowIndex + 1, endRowIndex), textDocument.lines[endRowIndex].slice(0, endColumnIndex)];
2373
+ return selectedLines;
2201
2374
  };
2202
- const getSelectionArray = visibleSelections => {
2203
- const selectionsArray = [];
2204
- for (let i = 0; i < visibleSelections.length; i += 4) {
2205
- const x = visibleSelections[i];
2206
- const y = visibleSelections[i + 1];
2207
- const width = visibleSelections[i + 2];
2208
- const height = visibleSelections[i + 3];
2209
- selectionsArray.push(px(x), px(y), px(width), px(height));
2375
+ const offsetAtSync = async (textDocument, positionRowIndex, positionColumnIndex) => {
2376
+ object(textDocument);
2377
+ number(positionRowIndex);
2378
+ number(positionColumnIndex);
2379
+ let offset = 0;
2380
+ let rowIndex = 0;
2381
+ const {
2382
+ lines
2383
+ } = textDocument;
2384
+ const max = Math.min(positionRowIndex, textDocument.lines.length);
2385
+ while (rowIndex < max) {
2386
+ offset += lines[rowIndex].length + 1;
2387
+ rowIndex++;
2210
2388
  }
2211
- return selectionsArray;
2389
+ offset += positionColumnIndex;
2390
+ return offset;
2212
2391
  };
2213
- const getVisible$1 = editor => {
2214
- const visibleCursors = [];
2215
- const visibleSelections = [];
2216
- // // TODO binary search
2217
-
2392
+ const offsetAt = (textDocument, positionRowIndex, positionColumnIndex) => {
2393
+ object(textDocument);
2394
+ number(positionRowIndex);
2395
+ number(positionColumnIndex);
2396
+ let offset = 0;
2397
+ let rowIndex = 0;
2218
2398
  const {
2219
- selections,
2220
- minLineY,
2221
- maxLineY,
2222
- rowHeight,
2223
- lines,
2224
- fontSize,
2225
- fontFamily,
2226
- fontWeight,
2227
- letterSpacing,
2228
- cursorWidth,
2229
- tabSize,
2230
- width,
2231
- differences,
2232
- focused,
2233
- charWidth,
2234
- isMonospaceFont
2235
- } = editor;
2236
- const averageCharWidth = charWidth;
2237
- const halfCursorWidth = cursorWidth / 2;
2238
- for (let i = 0; i < selections.length; i += 4) {
2239
- const [selectionStartRow, selectionStartColumn, selectionEndRow, selectionEndColumn, reversed] = getSelectionPairs(selections, i);
2240
- if (selectionEndRow < minLineY || selectionStartRow > maxLineY) {
2241
- continue;
2242
- }
2243
- const relativeEndLineRow = selectionEndRow - minLineY;
2244
- const endLineDifference = differences[relativeEndLineRow];
2245
- const endLine = lines[selectionEndRow];
2246
- const endLineEndX = getX(endLine, selectionEndColumn, fontWeight, fontSize, fontFamily, isMonospaceFont, letterSpacing, tabSize, halfCursorWidth, width, averageCharWidth, endLineDifference);
2247
- const endLineY = getY(selectionEndRow, minLineY, rowHeight);
2248
- if (isEmpty(selectionStartRow, selectionStartColumn, selectionEndRow, selectionEndColumn) && endLineEndX > 0) {
2249
- visibleCursors.push(endLineEndX, endLineY);
2250
- continue;
2251
- }
2252
- const startLineY = getY(selectionStartRow, minLineY, rowHeight);
2253
- const startLineYRelative = selectionStartRow - minLineY;
2254
- const startLineDifference = differences[startLineYRelative];
2255
- if (selectionStartRow === selectionEndRow) {
2256
- const startX = getX(endLine, selectionStartColumn, fontWeight, fontSize, fontFamily, isMonospaceFont, letterSpacing, tabSize, halfCursorWidth, width, averageCharWidth, startLineDifference);
2257
- if (reversed) {
2258
- visibleCursors.push(startX, endLineY);
2259
- } else if (endLineEndX >= 0) {
2260
- visibleCursors.push(endLineEndX, endLineY);
2261
- }
2262
- const selectionWidth = endLineEndX - startX;
2263
- visibleSelections.push(startX, startLineY, selectionWidth, rowHeight);
2264
- } else {
2265
- if (selectionStartRow >= minLineY) {
2266
- const startLine = lines[selectionStartRow];
2267
- const startLineStartX = getX(startLine, selectionStartColumn, fontWeight, fontSize, fontFamily, isMonospaceFont, letterSpacing, tabSize, halfCursorWidth, width, averageCharWidth, startLineDifference);
2268
- const startLineEndX = getX(startLine, startLine.length, fontWeight, fontSize, fontFamily, isMonospaceFont, letterSpacing, tabSize, halfCursorWidth, width, averageCharWidth, startLineDifference);
2269
- const startLineStartY = getY(selectionStartRow, minLineY, rowHeight);
2270
- const selectionWidth = startLineEndX - startLineStartX;
2271
- if (reversed) {
2272
- visibleCursors.push(startLineStartX, startLineStartY);
2273
- }
2274
- visibleSelections.push(startLineStartX, startLineStartY, selectionWidth, rowHeight);
2275
- }
2276
- const iMin = Math.max(selectionStartRow + 1, minLineY);
2277
- const iMax = Math.min(selectionEndRow, maxLineY);
2278
- for (let i = iMin; i < iMax; i++) {
2279
- const currentLine = lines[i];
2280
- const currentLineY = getY(i, minLineY, rowHeight);
2281
- const relativeLine = i - minLineY;
2282
- const difference = differences[relativeLine];
2283
- const selectionWidth = getX(currentLine, currentLine.length, fontWeight, fontSize, fontFamily, isMonospaceFont, letterSpacing, tabSize, halfCursorWidth, width, averageCharWidth, difference);
2284
- visibleSelections.push(0, currentLineY, selectionWidth, rowHeight);
2285
- }
2286
- if (selectionEndRow <= maxLineY) {
2287
- const selectionWidth = endLineEndX;
2288
- visibleSelections.push(0, endLineY, selectionWidth, rowHeight);
2289
- if (!reversed) {
2290
- visibleCursors.push(selectionWidth, endLineY);
2291
- }
2292
- }
2293
- }
2399
+ lines
2400
+ } = textDocument;
2401
+ const max = Math.min(positionRowIndex, textDocument.lines.length);
2402
+ while (rowIndex < max) {
2403
+ offset += lines[rowIndex].length + 1;
2404
+ rowIndex++;
2294
2405
  }
2295
- // TODO maybe use Uint32array or Float64Array?
2296
- return {
2297
- cursorInfos: getCursorArray(visibleCursors, focused),
2298
- selectionInfos: getSelectionArray(visibleSelections)
2299
- };
2406
+ offset += positionColumnIndex;
2407
+ return offset;
2300
2408
  };
2301
-
2302
- const getSelectionFromChange = change => {
2409
+ const positionAt = (textDocument, offset) => {
2303
2410
  const {
2304
- start,
2305
- inserted
2306
- } = change;
2307
- const startRowIndex = start.rowIndex;
2308
- const startColumnIndex = start.columnIndex;
2309
- const insertedLength = inserted.length;
2310
- if (insertedLength === 1) {
2311
- const newPosition = {
2312
- rowIndex: startRowIndex + insertedLength - 1,
2313
- columnIndex: inserted.at(-1).length + startColumnIndex
2314
- };
2315
- return {
2316
- start: newPosition,
2317
- end: newPosition
2318
- };
2411
+ lines
2412
+ } = textDocument;
2413
+ let rowIndex = 0;
2414
+ let columnIndex = 0;
2415
+ let currentOffset = 0;
2416
+ while (rowIndex < lines.length && currentOffset < offset) {
2417
+ currentOffset += lines[rowIndex].length + 1;
2418
+ rowIndex++;
2419
+ }
2420
+ if (currentOffset > offset) {
2421
+ rowIndex--;
2422
+ currentOffset -= lines[rowIndex].length + 1;
2423
+ columnIndex = offset - currentOffset;
2424
+ } else {
2425
+ columnIndex = currentOffset - offset;
2319
2426
  }
2320
- const newPosition = {
2321
- rowIndex: startRowIndex + insertedLength - 1,
2322
- columnIndex: startColumnIndex
2323
- };
2324
- return {
2325
- start: newPosition,
2326
- end: newPosition
2327
- };
2328
- };
2329
- const setSelections$1 = (editor, selections) => {
2330
- object(editor);
2331
- // Assert.uint32array(selections)
2332
2427
  return {
2333
- ...editor,
2334
- selections
2428
+ rowIndex,
2429
+ columnIndex
2335
2430
  };
2336
- // editor.selections = selections
2337
- // GlobalEventBus.emitEvent('editor.selectionChange', editor, selections)
2338
2431
  };
2339
2432
 
2340
- // TODO maybe only accept sorted selection edits in the first place
2341
-
2342
- // TODO avoid allocating too many objects when creating new selection from changes
2343
- // @ts-ignore
2344
- const applyEdit$1 = (editor, changes) => {
2433
+ // const getTokensIncremental = (editor, min, max) => {
2434
+ // const currentLength = editor.lineStateCache.length
2435
+ // const tokens = []
2436
+ // const lines = editor.lines
2437
+ // let lineState = editor.tokenizer.initialLineState
2438
+ // for (let i = currentLength; i < max; i++) {
2439
+ // const line = lines[i]
2440
+ // try {
2441
+ // lineState = editor.tokenizer.tokenizeLine(line, lineState)
2442
+ // if (!lineState || !lineState.tokens || !lineState.state) {
2443
+ // throw new Error('invalid tokenization result')
2444
+ // }
2445
+ // } catch (error) {
2446
+ // tokens.push([{ length: line.length, type: 0 }])
2447
+ // console.error(error)
2448
+ // // renderWithoutSyntaxHighlighting(state, firstRow, lastRow)
2449
+ // continue
2450
+ // }
2451
+ // const newTokens = lineState.tokens
2452
+ // tokens.push(newTokens)
2453
+ // }
2454
+ // return tokens
2455
+ // }
2456
+
2457
+ // const getLineInfosIncremental = (editor, tokens, minLineY, maxLineY) => {
2458
+ // const result = []
2459
+ // const lines = editor.lines
2460
+ // const TokenMap = editor.tokenizer.TokenMap
2461
+ // for (let i = minLineY; i < maxLineY; i++) {
2462
+ // result.push(getLineInfo(lines[i], tokens[i], TokenMap))
2463
+ // }
2464
+ // return result
2465
+ // }
2466
+
2467
+ const getStartDefaults = (tokens, minOffset) => {
2468
+ let start = 0;
2469
+ let end = 0;
2470
+ let startIndex = 0;
2471
+ const tokensLength = tokens.length;
2472
+ for (let i = 0; i < tokensLength; i += 2) {
2473
+ const tokenLength = tokens[i + 1];
2474
+ end += tokenLength;
2475
+ start = end;
2476
+ if (start >= minOffset) {
2477
+ start -= tokenLength;
2478
+ end -= tokenLength;
2479
+ startIndex = i;
2480
+ break;
2481
+ }
2482
+ }
2483
+ return {
2484
+ start,
2485
+ end,
2486
+ startIndex
2487
+ };
2488
+ };
2489
+ const getLineInfoEmbeddedFull = (embeddedResults, tokenResults, line, normalize, tabSize, width, deltaX, averageCharWidth, minOffset, maxOffset) => {
2490
+ const lineInfo = [];
2491
+ const embeddedResult = embeddedResults[tokenResults.embeddedResultIndex];
2492
+ const embeddedTokens = embeddedResult.result.tokens;
2493
+ const embeddedTokenMap = embeddedResult.TokenMap;
2494
+ const tokensLength = embeddedTokens.length;
2495
+ let {
2496
+ startIndex,
2497
+ start,
2498
+ end
2499
+ } = getStartDefaults(embeddedTokens, minOffset);
2500
+ const difference = getDifference(start, averageCharWidth, deltaX);
2501
+ for (let i = startIndex; i < tokensLength; i += 2) {
2502
+ const tokenType = embeddedTokens[i];
2503
+ const tokenLength = embeddedTokens[i + 1];
2504
+ end += tokenLength;
2505
+ const className = `Token ${embeddedTokenMap[tokenType] || 'Unknown'}`;
2506
+ const text = line.slice(start, end);
2507
+ const normalizedText = normalizeText(text, normalize, tabSize);
2508
+ lineInfo.push(normalizedText, className);
2509
+ start = end;
2510
+ if (end >= maxOffset) {
2511
+ break;
2512
+ }
2513
+ }
2514
+ return {
2515
+ lineInfo,
2516
+ difference
2517
+ };
2518
+ };
2519
+ const getOffsets = (deltaX, width, averageCharWidth) => {
2520
+ // TODO accurately measure char widths using offscreen canvas
2521
+ // and use fast measurements for monospace ascii text
2522
+ if (deltaX === 0) {
2523
+ return {
2524
+ minOffset: 0,
2525
+ maxOffset: Math.ceil(width / averageCharWidth)
2526
+ };
2527
+ }
2528
+ const minOffset = Math.ceil(deltaX / averageCharWidth);
2529
+ const maxOffset = minOffset + Math.ceil(width / averageCharWidth);
2530
+ return {
2531
+ minOffset,
2532
+ maxOffset
2533
+ };
2534
+ };
2535
+ const getDifference = (start, averageCharWidth, deltaX) => {
2536
+ const beforeWidth = start * averageCharWidth;
2537
+ const difference = beforeWidth - deltaX;
2538
+ return difference;
2539
+ };
2540
+ const getLineInfoDefault = (line, tokenResults, embeddedResults, decorations, TokenMap, lineOffset, normalize, tabSize, width, deltaX, averageCharWidth, minOffset, maxOffset) => {
2541
+ const lineInfo = [];
2542
+ let decorationIndex = 0;
2543
+ for (; decorationIndex < decorations.length; decorationIndex += 3) {
2544
+ const decorationOffset = decorations[decorationIndex];
2545
+ if (decorationOffset >= lineOffset) {
2546
+ break;
2547
+ }
2548
+ }
2549
+ const {
2550
+ tokens
2551
+ } = tokenResults;
2552
+ let {
2553
+ startIndex,
2554
+ start,
2555
+ end
2556
+ } = getStartDefaults(tokens, minOffset);
2557
+ const difference = getDifference(start, averageCharWidth, deltaX);
2558
+ const tokensLength = tokens.length;
2559
+ for (let i = startIndex; i < tokensLength; i += 2) {
2560
+ const tokenType = tokens[i];
2561
+ const tokenLength = tokens[i + 1];
2562
+ const decorationOffset = decorations[decorationIndex];
2563
+ let extraClassName = '';
2564
+ if (decorationOffset !== undefined && decorationOffset - lineOffset === start) {
2565
+ // @ts-ignore
2566
+ decorations[++decorationIndex];
2567
+ const decorationType = decorations[++decorationIndex];
2568
+ // @ts-ignore
2569
+ decorations[++decorationIndex];
2570
+ // decorationIndex,
2571
+ // decorationLength,
2572
+ // decorationType,
2573
+ // decorationModifiers,
2574
+ // })
2575
+ extraClassName = getDecorationClassName(decorationType);
2576
+ }
2577
+ end += tokenLength;
2578
+ const text = line.slice(start, end);
2579
+ const className = `Token ${extraClassName || TokenMap[tokenType] || 'Unknown'}`;
2580
+ const normalizedText = normalizeText(text, normalize, tabSize);
2581
+ lineInfo.push(normalizedText, className);
2582
+ start = end;
2583
+ if (end >= maxOffset) {
2584
+ break;
2585
+ }
2586
+ }
2587
+ return {
2588
+ lineInfo,
2589
+ difference
2590
+ };
2591
+ };
2592
+ const getLineInfo$1 = (line, tokenResults, embeddedResults, decorations, TokenMap, lineOffset, normalize, tabSize, width, deltaX, averageCharWidth) => {
2593
+ const {
2594
+ minOffset,
2595
+ maxOffset
2596
+ } = getOffsets(deltaX, width, averageCharWidth);
2597
+ if (embeddedResults.length > 0 && tokenResults.embeddedResultIndex !== undefined) {
2598
+ const embeddedResult = embeddedResults[tokenResults.embeddedResultIndex];
2599
+ if (embeddedResult?.isFull) {
2600
+ return getLineInfoEmbeddedFull(embeddedResults, tokenResults, line, normalize, tabSize, width, deltaX, averageCharWidth, minOffset, maxOffset);
2601
+ }
2602
+ }
2603
+ return getLineInfoDefault(line, tokenResults, embeddedResults, decorations, TokenMap, lineOffset, normalize, tabSize, width, deltaX, averageCharWidth, minOffset, maxOffset);
2604
+ };
2605
+
2606
+ // TODO need lots of tests for this
2607
+ const getLineInfosViewport = (editor, tokens, embeddedResults, minLineY, maxLineY, minLineOffset, width, deltaX, averageCharWidth) => {
2608
+ const result = [];
2609
+ const differences = [];
2610
+ const {
2611
+ lines,
2612
+ decorations,
2613
+ languageId
2614
+ } = editor;
2615
+ const tokenMap = get$2(languageId);
2616
+ let offset = minLineOffset;
2617
+ const tabSize = 2;
2618
+ for (let i = minLineY; i < maxLineY; i++) {
2619
+ const line = lines[i];
2620
+ const normalize = shouldNormalizeText(line);
2621
+ const {
2622
+ lineInfo,
2623
+ difference
2624
+ } = getLineInfo$1(line, tokens[i - minLineY], embeddedResults, decorations, tokenMap, offset, normalize, tabSize, width, deltaX, averageCharWidth);
2625
+ result.push(lineInfo);
2626
+ differences.push(difference);
2627
+ offset += line.length + 1;
2628
+ }
2629
+ return {
2630
+ result,
2631
+ differences
2632
+ };
2633
+ };
2634
+ const getVisible$1 = async (editor, syncIncremental) => {
2635
+ // TODO should separate rendering from business logic somehow
2636
+ // currently hard to test because need to mock editor height, top, left,
2637
+ // invalidStartIndex, lineCache, etc. just for testing editorType
2638
+ // editor.invalidStartIndex = changes[0].start.rowIndex
2639
+ // @ts-ignore
2640
+ const {
2641
+ minLineY,
2642
+ numberOfVisibleLines,
2643
+ lines,
2644
+ width,
2645
+ deltaX,
2646
+ charWidth
2647
+ } = editor;
2648
+ const maxLineY = Math.min(minLineY + numberOfVisibleLines, lines.length);
2649
+ // @ts-ignore
2650
+ const {
2651
+ tokens,
2652
+ tokenizersToLoad,
2653
+ embeddedResults
2654
+ } = await getTokensViewport2(editor, minLineY, maxLineY, syncIncremental);
2655
+ const minLineOffset = offsetAtSync(editor, minLineY, 0);
2656
+ const averageCharWidth = charWidth;
2657
+ const {
2658
+ result,
2659
+ differences
2660
+ } = getLineInfosViewport(editor, tokens, embeddedResults, minLineY, maxLineY, minLineOffset, width, deltaX, averageCharWidth);
2661
+ if (tokenizersToLoad.length > 0) {
2662
+ loadTokenizers(tokenizersToLoad);
2663
+ }
2664
+ return {
2665
+ textInfos: result,
2666
+ differences
2667
+ };
2668
+ };
2669
+
2670
+ const emptyIncrementalEdits = [];
2671
+
2672
+ const getIncrementalEdits = async (oldState, newState) => {
2673
+ if (!newState.undoStack) {
2674
+ return emptyIncrementalEdits;
2675
+ }
2676
+ if (oldState.undoStack === newState.undoStack) {
2677
+ return emptyIncrementalEdits;
2678
+ }
2679
+ const lastChanges = newState.undoStack.at(-1);
2680
+ if (lastChanges && lastChanges.length === 1) {
2681
+ const lastChange = lastChanges[0];
2682
+ if (lastChange.origin === EditorType) {
2683
+ const {
2684
+ rowIndex
2685
+ } = lastChange.start;
2686
+ const {
2687
+ lines
2688
+ } = newState;
2689
+ const oldLine = oldState.lines[rowIndex];
2690
+ const newLine = lines[rowIndex];
2691
+ // @ts-ignore
2692
+ const incrementalEdits = await invoke$7(
2693
+ // @ts-ignore
2694
+ 'TokenizeIncremental.tokenizeIncremental', newState.uid,
2695
+ // @ts-ignore
2696
+ newState.languageId, oldLine, newLine, rowIndex, newState.minLineY);
2697
+ if (incrementalEdits && incrementalEdits.length === 1) {
2698
+ return incrementalEdits;
2699
+ }
2700
+ }
2701
+ }
2702
+ return emptyIncrementalEdits;
2703
+ };
2704
+
2705
+ const splitLines = lines => {
2706
+ if (!lines) {
2707
+ return [''];
2708
+ }
2709
+ return lines.split('\n');
2710
+ };
2711
+
2712
+ let enabled = false;
2713
+ const setEnabled = value => {
2714
+ enabled = value;
2715
+ };
2716
+ const getEnabled = () => {
2717
+ return enabled;
2718
+ };
2719
+
2720
+ const getSelectionPairs = (selections, i) => {
2721
+ const first = selections[i];
2722
+ const second = selections[i + 1];
2723
+ const third = selections[i + 2];
2724
+ const fourth = selections[i + 3];
2725
+ if (first > third || first === third && second >= fourth) {
2726
+ return [third, fourth, first, second, 1];
2727
+ }
2728
+ return [first, second, third, fourth, 0];
2729
+ };
2730
+
2731
+ const getTabCount = string => {
2732
+ let count = 0;
2733
+ for (const element of string) {
2734
+ if (element === Tab) {
2735
+ count++;
2736
+ }
2737
+ }
2738
+ return count;
2739
+ };
2740
+
2741
+ const measureTextWidthFast = (text, charWidth) => {
2742
+ return text.length * charWidth;
2743
+ };
2744
+
2745
+ const getFontString = (fontWeight, fontSize, fontFamily) => {
2746
+ return `${fontWeight} ${fontSize}px ${fontFamily}`;
2747
+ };
2748
+
2749
+ const getLetterSpacingString = letterSpacing => {
2750
+ return `${letterSpacing}px`;
2751
+ };
2752
+
2753
+ const createMeasureContext = () => {
2754
+ const canvas = new OffscreenCanvas(0, 0);
2755
+ const ctx = /** @type {OffscreenCanvasRenderingContext2D} */canvas.getContext('2d');
2756
+ if (!ctx) {
2757
+ throw new Error('Failed to get canvas context 2d');
2758
+ }
2759
+ return ctx;
2760
+ };
2761
+
2762
+ const state$6 = {
2763
+ ctx: undefined
2764
+ };
2765
+ const getOrCreate$4 = createCtx => {
2766
+ if (state$6.ctx) {
2767
+ return state$6.ctx;
2768
+ }
2769
+ state$6.ctx = createCtx();
2770
+ return state$6.ctx;
2771
+ };
2772
+
2773
+ const getContext = () => {
2774
+ const ctx = getOrCreate$4(createMeasureContext);
2775
+ return ctx;
2776
+ };
2777
+
2778
+ // TODO for text editor, could dispose measuring canvas after editor has been initialized to free up offscreencanvas space
2779
+
2780
+ const measureTextWidthSlow = (text, fontWeight, fontSize, fontFamily, letterSpacing, isMonoSpaceFont, charWidth) => {
2781
+ string(text);
2782
+ number(fontWeight);
2783
+ number(fontSize);
2784
+ string(fontFamily);
2785
+ boolean(isMonoSpaceFont);
2786
+ number(charWidth);
2787
+ if (typeof letterSpacing !== 'number') {
2788
+ throw new TypeError('letterSpacing must be of type number');
2789
+ }
2790
+ const letterSpacingString = getLetterSpacingString(letterSpacing);
2791
+ const fontString = getFontString(fontWeight, fontSize, fontFamily);
2792
+ const ctx = getContext();
2793
+ ctx.letterSpacing = letterSpacingString;
2794
+ ctx.font = fontString;
2795
+ const metrics = ctx.measureText(text);
2796
+ const {
2797
+ width
2798
+ } = metrics;
2799
+ return width;
2800
+ };
2801
+
2802
+ const measureTextWidth = (text, fontWeight, fontSize, fontFamily, letterSpacing, isMonoSpaceFont, charWidth) => {
2803
+ if (isMonoSpaceFont) {
2804
+ return measureTextWidthFast(text, charWidth);
2805
+ }
2806
+ return measureTextWidthSlow(text, fontWeight, fontSize, fontFamily, letterSpacing, isMonoSpaceFont, charWidth);
2807
+ };
2808
+
2809
+ const getX = (line, column, fontWeight, fontSize, fontFamily, isMonospaceFont, letterSpacing, tabSize, halfCursorWidth, width, averageCharWidth, difference = 0) => {
2810
+ if (!line) {
2811
+ return 0;
2812
+ }
2813
+ string(line);
2814
+ number(tabSize);
2815
+ number(halfCursorWidth);
2816
+ number(width);
2817
+ boolean(isMonospaceFont);
2818
+ number(averageCharWidth);
2819
+ number(difference);
2820
+ if (column === 0) {
2821
+ return 0;
2822
+ }
2823
+ // TODO support non-monospace font, emoji, tab character, zero width characters
2824
+ if (column * averageCharWidth > width) {
2825
+ return width;
2826
+ }
2827
+ const normalize = shouldNormalizeText(line);
2828
+ const normalizedLine = normalizeText(line, normalize, tabSize);
2829
+ const tabCount = getTabCount(line.slice(0, column));
2830
+ const partialText = normalizedLine.slice(0, column + tabCount);
2831
+ return measureTextWidth(partialText, fontWeight, fontSize, fontFamily, letterSpacing, isMonospaceFont, averageCharWidth) - halfCursorWidth + difference;
2832
+ };
2833
+
2834
+ const getY = (row, minLineY, rowHeight) => {
2835
+ return (row - minLineY) * rowHeight;
2836
+ };
2837
+
2838
+ const px = value => {
2839
+ return `${value}px`;
2840
+ };
2841
+
2842
+ const fromRange = (startRowIndex, startColumnIndex, endRowIndex, endColumnIndex) => {
2843
+ return new Uint32Array([startRowIndex, startColumnIndex, endRowIndex, endColumnIndex]);
2844
+ };
2845
+ const alloc = length => {
2846
+ return new Uint32Array(length);
2847
+ };
2848
+ const clone = selections => {
2849
+ return alloc(selections.length);
2850
+ };
2851
+ const map = (selections, fn) => {
2852
+ const newSelections = clone(selections);
2853
+ for (let i = 0; i < newSelections.length; i += 4) {
2854
+ const [selectionStartRow, selectionStartColumn, selectionEndRow, selectionEndColumn] = getSelectionPairs(selections, i);
2855
+ fn(newSelections, i, selectionStartRow, selectionStartColumn, selectionEndRow, selectionEndColumn);
2856
+ }
2857
+ return newSelections;
2858
+ };
2859
+ const forEach = (selections, fn) => {
2860
+ for (let i = 0; i < selections.length; i += 4) {
2861
+ const selectionStartRow = selections[i];
2862
+ const selectionStartColumn = selections[i + 1];
2863
+ const selectionEndRow = selections[i + 2];
2864
+ const selectionEndColumn = selections[i + 3];
2865
+ fn(selectionStartRow, selectionStartColumn, selectionEndRow, selectionEndColumn);
2866
+ }
2867
+ };
2868
+ const moveRangeToPosition$1 = (selections, i, rowIndex, columnIndex) => {
2869
+ selections[i] = selections[i + 2] = rowIndex;
2870
+ selections[i + 1] = selections[i + 3] = columnIndex;
2871
+ };
2872
+ const isEmpty = (selectionStartRow, selectionStartColumn, selectionEndRow, selectionEndColumn) => {
2873
+ return selectionStartRow === selectionEndRow && selectionStartColumn === selectionEndColumn;
2874
+ };
2875
+ const isSelectionSingleLine = (selectionStartRow, selectionStartColumn, selectionEndRow, selectionEndColumn) => {
2876
+ return selectionStartRow === selectionEndRow;
2877
+ };
2878
+ const isEverySelection = (selections, fn) => {
2879
+ for (let i = 0; i < selections.length; i += 4) {
2880
+ const selectionStartRow = selections[i];
2881
+ const selectionStartColumn = selections[i + 1];
2882
+ const selectionEndRow = selections[i + 2];
2883
+ const selectionEndColumn = selections[i + 3];
2884
+ if (!fn(selectionStartRow, selectionStartColumn, selectionEndRow, selectionEndColumn)) {
2885
+ return false;
2886
+ }
2887
+ }
2888
+ return true;
2889
+ };
2890
+ const isEverySelectionEmpty = selections => {
2891
+ return isEverySelection(selections, isEmpty);
2892
+ };
2893
+ const isEverySelectionSingleLine = selections => {
2894
+ return isEverySelection(selections, isSelectionSingleLine);
2895
+ };
2896
+ const from = (array, getSelection) => {
2897
+ const newSelections = alloc(array.length * 4);
2898
+ let i = 0;
2899
+ for (const item of array) {
2900
+ const {
2901
+ start,
2902
+ end
2903
+ } = getSelection(item);
2904
+ newSelections[i++] = start.rowIndex;
2905
+ newSelections[i++] = start.columnIndex;
2906
+ newSelections[i++] = end.rowIndex;
2907
+ newSelections[i++] = end.columnIndex;
2908
+ }
2909
+ return newSelections;
2910
+ };
2911
+ const push = (selections, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex) => {
2912
+ const oldLength = selections.length;
2913
+ const newSelections = alloc(oldLength + 4);
2914
+ newSelections.set(selections);
2915
+ newSelections[oldLength + 1] = startRowIndex;
2916
+ newSelections[oldLength + 2] = startColumnIndex;
2917
+ newSelections[oldLength + 3] = endRowIndex;
2918
+ newSelections[oldLength + 4] = endColumnIndex;
2919
+ return newSelections;
2920
+ };
2921
+
2922
+ // TODO maybe only accept sorted selection edits in the first place
2923
+
2924
+ const emptyCursors = [];
2925
+ const getCursorArray = (visibleCursors, isFocused) => {
2926
+ if (!isFocused) {
2927
+ return emptyCursors;
2928
+ }
2929
+ const cursorArray = [];
2930
+ for (let i = 0; i < visibleCursors.length; i += 2) {
2931
+ const x = visibleCursors[i];
2932
+ const y = visibleCursors[i + 1];
2933
+ cursorArray.push(`${px(x)} ${px(y)}`);
2934
+ }
2935
+ return cursorArray;
2936
+ };
2937
+ const getSelectionArray = visibleSelections => {
2938
+ const selectionsArray = [];
2939
+ for (let i = 0; i < visibleSelections.length; i += 4) {
2940
+ const x = visibleSelections[i];
2941
+ const y = visibleSelections[i + 1];
2942
+ const width = visibleSelections[i + 2];
2943
+ const height = visibleSelections[i + 3];
2944
+ selectionsArray.push(px(x), px(y), px(width), px(height));
2945
+ }
2946
+ return selectionsArray;
2947
+ };
2948
+ const getVisible = editor => {
2949
+ const visibleCursors = [];
2950
+ const visibleSelections = [];
2951
+ // // TODO binary search
2952
+
2953
+ const {
2954
+ selections,
2955
+ minLineY,
2956
+ maxLineY,
2957
+ rowHeight,
2958
+ lines,
2959
+ fontSize,
2960
+ fontFamily,
2961
+ fontWeight,
2962
+ letterSpacing,
2963
+ cursorWidth,
2964
+ tabSize,
2965
+ width,
2966
+ differences,
2967
+ focused,
2968
+ charWidth,
2969
+ isMonospaceFont
2970
+ } = editor;
2971
+ const averageCharWidth = charWidth;
2972
+ const halfCursorWidth = cursorWidth / 2;
2973
+ for (let i = 0; i < selections.length; i += 4) {
2974
+ const [selectionStartRow, selectionStartColumn, selectionEndRow, selectionEndColumn, reversed] = getSelectionPairs(selections, i);
2975
+ if (selectionEndRow < minLineY || selectionStartRow > maxLineY) {
2976
+ continue;
2977
+ }
2978
+ const relativeEndLineRow = selectionEndRow - minLineY;
2979
+ const endLineDifference = differences[relativeEndLineRow];
2980
+ const endLine = lines[selectionEndRow];
2981
+ const endLineEndX = getX(endLine, selectionEndColumn, fontWeight, fontSize, fontFamily, isMonospaceFont, letterSpacing, tabSize, halfCursorWidth, width, averageCharWidth, endLineDifference);
2982
+ const endLineY = getY(selectionEndRow, minLineY, rowHeight);
2983
+ if (isEmpty(selectionStartRow, selectionStartColumn, selectionEndRow, selectionEndColumn) && endLineEndX > 0) {
2984
+ visibleCursors.push(endLineEndX, endLineY);
2985
+ continue;
2986
+ }
2987
+ const startLineY = getY(selectionStartRow, minLineY, rowHeight);
2988
+ const startLineYRelative = selectionStartRow - minLineY;
2989
+ const startLineDifference = differences[startLineYRelative];
2990
+ if (selectionStartRow === selectionEndRow) {
2991
+ const startX = getX(endLine, selectionStartColumn, fontWeight, fontSize, fontFamily, isMonospaceFont, letterSpacing, tabSize, halfCursorWidth, width, averageCharWidth, startLineDifference);
2992
+ if (reversed) {
2993
+ visibleCursors.push(startX, endLineY);
2994
+ } else if (endLineEndX >= 0) {
2995
+ visibleCursors.push(endLineEndX, endLineY);
2996
+ }
2997
+ const selectionWidth = endLineEndX - startX;
2998
+ visibleSelections.push(startX, startLineY, selectionWidth, rowHeight);
2999
+ } else {
3000
+ if (selectionStartRow >= minLineY) {
3001
+ const startLine = lines[selectionStartRow];
3002
+ const startLineStartX = getX(startLine, selectionStartColumn, fontWeight, fontSize, fontFamily, isMonospaceFont, letterSpacing, tabSize, halfCursorWidth, width, averageCharWidth, startLineDifference);
3003
+ const startLineEndX = getX(startLine, startLine.length, fontWeight, fontSize, fontFamily, isMonospaceFont, letterSpacing, tabSize, halfCursorWidth, width, averageCharWidth, startLineDifference);
3004
+ const startLineStartY = getY(selectionStartRow, minLineY, rowHeight);
3005
+ const selectionWidth = startLineEndX - startLineStartX;
3006
+ if (reversed) {
3007
+ visibleCursors.push(startLineStartX, startLineStartY);
3008
+ }
3009
+ visibleSelections.push(startLineStartX, startLineStartY, selectionWidth, rowHeight);
3010
+ }
3011
+ const iMin = Math.max(selectionStartRow + 1, minLineY);
3012
+ const iMax = Math.min(selectionEndRow, maxLineY);
3013
+ for (let i = iMin; i < iMax; i++) {
3014
+ const currentLine = lines[i];
3015
+ const currentLineY = getY(i, minLineY, rowHeight);
3016
+ const relativeLine = i - minLineY;
3017
+ const difference = differences[relativeLine];
3018
+ const selectionWidth = getX(currentLine, currentLine.length, fontWeight, fontSize, fontFamily, isMonospaceFont, letterSpacing, tabSize, halfCursorWidth, width, averageCharWidth, difference);
3019
+ visibleSelections.push(0, currentLineY, selectionWidth, rowHeight);
3020
+ }
3021
+ if (selectionEndRow <= maxLineY) {
3022
+ const selectionWidth = endLineEndX;
3023
+ visibleSelections.push(0, endLineY, selectionWidth, rowHeight);
3024
+ if (!reversed) {
3025
+ visibleCursors.push(selectionWidth, endLineY);
3026
+ }
3027
+ }
3028
+ }
3029
+ }
3030
+ // TODO maybe use Uint32array or Float64Array?
3031
+ return {
3032
+ cursorInfos: getCursorArray(visibleCursors, focused),
3033
+ selectionInfos: getSelectionArray(visibleSelections)
3034
+ };
3035
+ };
3036
+
3037
+ const getSelectionFromChange = change => {
3038
+ const {
3039
+ start,
3040
+ inserted
3041
+ } = change;
3042
+ const startRowIndex = start.rowIndex;
3043
+ const startColumnIndex = start.columnIndex;
3044
+ const insertedLength = inserted.length;
3045
+ if (insertedLength === 1) {
3046
+ const newPosition = {
3047
+ rowIndex: startRowIndex + insertedLength - 1,
3048
+ columnIndex: inserted.at(-1).length + startColumnIndex
3049
+ };
3050
+ return {
3051
+ start: newPosition,
3052
+ end: newPosition
3053
+ };
3054
+ }
3055
+ const newPosition = {
3056
+ rowIndex: startRowIndex + insertedLength - 1,
3057
+ columnIndex: startColumnIndex
3058
+ };
3059
+ return {
3060
+ start: newPosition,
3061
+ end: newPosition
3062
+ };
3063
+ };
3064
+ const setSelections$1 = (editor, selections) => {
3065
+ object(editor);
3066
+ // Assert.uint32array(selections)
3067
+ return {
3068
+ ...editor,
3069
+ selections
3070
+ };
3071
+ // editor.selections = selections
3072
+ // GlobalEventBus.emitEvent('editor.selectionChange', editor, selections)
3073
+ };
3074
+
3075
+ // TODO maybe only accept sorted selection edits in the first place
3076
+
3077
+ // TODO avoid allocating too many objects when creating new selection from changes
3078
+ // @ts-ignore
3079
+ const applyEdit$1 = (editor, changes) => {
2345
3080
  object(editor);
2346
3081
  array(changes);
2347
3082
  const newSelections = from(changes, getSelectionFromChange);
@@ -2428,15 +3163,29 @@ const scheduleDocumentAndCursorsSelections = async (editor, changes, selectionCh
2428
3163
  autoClosingRanges
2429
3164
  };
2430
3165
  set$6(editor.uid, editor, newEditor);
3166
+ const incrementalEdits = await getIncrementalEdits(editor, newEditor);
2431
3167
  const newWidgets = await applyWidgetChanges(newEditor, changes);
2432
3168
  const newEditor2 = {
2433
3169
  ...newEditor,
2434
- widgets: newWidgets
3170
+ widgets: newWidgets,
3171
+ incrementalEdits
3172
+ };
3173
+ if (incrementalEdits !== emptyIncrementalEdits) {
3174
+ return newEditor2;
3175
+ }
3176
+ const syncIncremental = getEnabled();
3177
+ const {
3178
+ textInfos,
3179
+ differences
3180
+ } = await getVisible$1(newEditor2, syncIncremental);
3181
+ return {
3182
+ ...newEditor2,
3183
+ textInfos,
3184
+ differences
2435
3185
  };
2436
- return newEditor2;
2437
3186
  };
2438
3187
  // @ts-ignore
2439
- const scheduleDocumentAndCursorsSelectionIsUndo = (editor, changes) => {
3188
+ const scheduleDocumentAndCursorsSelectionIsUndo = async (editor, changes) => {
2440
3189
  object(editor);
2441
3190
  array(changes);
2442
3191
  if (changes.length === 0) {
@@ -2456,7 +3205,26 @@ const scheduleDocumentAndCursorsSelectionIsUndo = (editor, changes) => {
2456
3205
  // undoStack: [...editor.undoStack.slice(0, -2)],
2457
3206
  invalidStartIndex
2458
3207
  };
2459
- return newEditor;
3208
+ const incrementalEdits = await getIncrementalEdits(editor, newEditor);
3209
+
3210
+ // TODO change event should be emitted after rendering
3211
+ const finalEditor = {
3212
+ ...newEditor,
3213
+ incrementalEdits
3214
+ };
3215
+ if (incrementalEdits !== emptyIncrementalEdits) {
3216
+ return finalEditor;
3217
+ }
3218
+ const syncIncremental = getEnabled();
3219
+ const {
3220
+ textInfos,
3221
+ differences
3222
+ } = await getVisible$1(finalEditor, syncIncremental);
3223
+ return {
3224
+ ...finalEditor,
3225
+ textInfos,
3226
+ differences
3227
+ };
2460
3228
  };
2461
3229
 
2462
3230
  // @ts-ignore
@@ -2481,8 +3249,26 @@ const scheduleDocument = async (editor, changes) => {
2481
3249
  lines: newLines,
2482
3250
  invalidStartIndex
2483
3251
  };
3252
+ const incrementalEdits = await getIncrementalEdits(editor, newEditor);
3253
+
2484
3254
  // TODO change event should be emitted after rendering
2485
- return newEditor;
3255
+ const finalEditor = {
3256
+ ...newEditor,
3257
+ incrementalEdits
3258
+ };
3259
+ if (incrementalEdits !== emptyIncrementalEdits) {
3260
+ return finalEditor;
3261
+ }
3262
+ const syncIncremental = getEnabled();
3263
+ const {
3264
+ textInfos,
3265
+ differences
3266
+ } = await getVisible$1(finalEditor, syncIncremental);
3267
+ return {
3268
+ ...finalEditor,
3269
+ textInfos,
3270
+ differences
3271
+ };
2486
3272
  // RendererProcess.send([
2487
3273
  // /* Viewlet.invoke */ 'Viewlet.send',
2488
3274
  // /* id */ 'EditorText',
@@ -2548,8 +3334,8 @@ const TabCompletionExecuteTabCompletionProvider = 'ExtensionHost.executeTabCompl
2548
3334
  const TextDocumentSyncFull = 'ExtensionHostTextDocument.syncFull';
2549
3335
 
2550
3336
  const {
2551
- set: set$5,
2552
- invoke: invoke$7} = ExtensionHost;
3337
+ set: set$1,
3338
+ invoke: invoke$6} = ExtensionHost;
2553
3339
 
2554
3340
  const ColorPicker = 41;
2555
3341
  const EditorCompletion = 9;
@@ -2578,7 +3364,7 @@ const execute = async ({
2578
3364
  }) => {
2579
3365
  const fullEvent = `${event}:${editor.languageId}`;
2580
3366
  await activateByEvent(fullEvent);
2581
- const result = await invoke$7(method, editor.uid, ...args);
3367
+ const result = await invoke$6(method, editor.uid, ...args);
2582
3368
  return result;
2583
3369
  };
2584
3370
 
@@ -2646,7 +3432,7 @@ const updateDiagnostics = async newState => {
2646
3432
  // TODO don't really need text document sync response
2647
3433
  // could perhaps save a lot of messages by using send instead of invoke
2648
3434
  // @ts-ignore
2649
- await invoke$7(TextDocumentSyncFull, newState.uri, newState.id, newState.languageId, content);
3435
+ await invoke$6(TextDocumentSyncFull, newState.uri, newState.id, newState.languageId, content);
2650
3436
  const diagnostics = await executeDiagnosticProvider(newState);
2651
3437
  const latest = get$4(newState.id);
2652
3438
  if (!latest) {
@@ -2672,6 +3458,8 @@ const updateDiagnostics = async newState => {
2672
3458
  };
2673
3459
 
2674
3460
  const emptyEditor = {
3461
+ textInfos: [],
3462
+ differences: [],
2675
3463
  uri: '',
2676
3464
  languageId: '',
2677
3465
  // TODO use numeric language id?
@@ -2695,7 +3483,8 @@ const emptyEditor = {
2695
3483
  selections: new Uint32Array(),
2696
3484
  diagnostics: [],
2697
3485
  highlightedLine: -1,
2698
- debugEnabled: false
3486
+ debugEnabled: false,
3487
+ incrementalEdits: emptyIncrementalEdits
2699
3488
  };
2700
3489
  const createEditor = async ({
2701
3490
  id,
@@ -2732,6 +3521,7 @@ const createEditor = async ({
2732
3521
  string(content);
2733
3522
  const charWidth = measureCharacterWidth(fontWeight, fontSize, fontFamily, letterSpacing);
2734
3523
  const editor = {
3524
+ textInfos: [],
2735
3525
  uri,
2736
3526
  isAutoClosingBracketsEnabled,
2737
3527
  isAutoClosingTagsEnabled,
@@ -2787,7 +3577,8 @@ const createEditor = async ({
2787
3577
  id,
2788
3578
  widgets: [],
2789
3579
  focusKey: Empty,
2790
- diagnosticsEnabled
3580
+ diagnosticsEnabled,
3581
+ incrementalEdits: emptyIncrementalEdits
2791
3582
  };
2792
3583
  // TODO avoid creating intermediate editors here
2793
3584
  const newEditor1 = setBounds(editor, x, y, width, height, 9);
@@ -2800,13 +3591,23 @@ const createEditor = async ({
2800
3591
  } else {
2801
3592
  newEditor3 = setDeltaY$2(newEditor2, 0);
2802
3593
  }
3594
+ const syncIncremental = getEnabled();
3595
+ const {
3596
+ textInfos,
3597
+ differences
3598
+ } = await getVisible$1(newEditor3, syncIncremental);
2803
3599
  const newEditor4 = {
2804
3600
  ...newEditor3,
2805
- focused: true
3601
+ focused: true,
3602
+ textInfos,
3603
+ differences
2806
3604
  };
2807
3605
  set$6(id, emptyEditor, newEditor4);
3606
+
3607
+ // TODO only sync when needed
3608
+ // e.g. it might not always be necessary to send text to extension host worker
2808
3609
  // @ts-ignore
2809
- await invoke$7(TextDocumentSyncFull, uri, id, languageId, content);
3610
+ await invoke$6(TextDocumentSyncFull, uri, id, languageId, content);
2810
3611
  if (diagnosticsEnabled) {
2811
3612
  updateDiagnostics(newEditor4);
2812
3613
  }
@@ -3086,7 +3887,7 @@ const guessOffset = (eventX, averageCharWidth) => {
3086
3887
  const normalizeGuess = (line, guess, tabSize) => {
3087
3888
  let normalizedGuess = guess;
3088
3889
  for (let i = 0; i < guess; i++) {
3089
- if (line[i] === Tab$1) {
3890
+ if (line[i] === Tab) {
3090
3891
  normalizedGuess -= tabSize - 1;
3091
3892
  }
3092
3893
  }
@@ -3180,7 +3981,7 @@ const y = (editor, rowIndex) => {
3180
3981
  return offsetY;
3181
3982
  };
3182
3983
 
3183
- const state$7 = {
3984
+ const state$5 = {
3184
3985
  timeout: -1
3185
3986
  };
3186
3987
 
@@ -3211,7 +4012,7 @@ const editorShowMessage = async (editor, rowIndex, columnIndex, message, isError
3211
4012
 
3212
4013
  // TODO use wrapper timing module instead of this
3213
4014
  // @ts-ignore
3214
- state$7.timeout = setTimeout(handleTimeout, 3000);
4015
+ state$5.timeout = setTimeout(handleTimeout, 3000);
3215
4016
  }
3216
4017
  return editor;
3217
4018
  };
@@ -3231,8 +4032,8 @@ const showErrorMessage = async (editor, rowIndex, columnIndex, message) => {
3231
4032
 
3232
4033
  // @ts-ignore
3233
4034
  const editorHideMessage = async editor => {
3234
- clearTimeout(state$7.timeout);
3235
- state$7.timeout = -1;
4035
+ clearTimeout(state$5.timeout);
4036
+ state$5.timeout = -1;
3236
4037
  // await RendererProcess.invoke(/* Viewlet.send */ 'Viewlet.send', /* id */ editor.uid, /* method */ 'hideOverlayMessage')
3237
4038
  return editor;
3238
4039
  };
@@ -3357,7 +4158,7 @@ const getOrCreate$3 = () => {
3357
4158
  }
3358
4159
  return workerPromise$3;
3359
4160
  };
3360
- const invoke$6 = async (method, ...params) => {
4161
+ const invoke$5 = async (method, ...params) => {
3361
4162
  const worker = await getOrCreate$3();
3362
4163
  return await worker.invoke(method, ...params);
3363
4164
  };
@@ -3376,7 +4177,7 @@ const closeRename = async editor => {
3376
4177
  return editor;
3377
4178
  }
3378
4179
  const renameWidget = widgets[renameWidgetIndex];
3379
- await invoke$6('Rename.close', renameWidget.newState.uid);
4180
+ await invoke$5('Rename.close', renameWidget.newState.uid);
3380
4181
  const latest = get$4(uid);
3381
4182
  const {
3382
4183
  newState
@@ -3495,12 +4296,12 @@ const openColorPicker = async editor => {
3495
4296
  return addWidgetToEditor(ColorPicker$1, ColorPicker, editor, create$6, newStateGenerator$6);
3496
4297
  };
3497
4298
 
3498
- const state$6 = {
4299
+ const state$4 = {
3499
4300
  isComposing: false,
3500
4301
  compositionText: ''
3501
4302
  };
3502
4303
  const compositionStart = (editor, event) => {
3503
- state$6.isComposing = true;
4304
+ state$4.isComposing = true;
3504
4305
  return editor;
3505
4306
  };
3506
4307
  const getCompositionChanges = (selections, data) => {
@@ -3510,7 +4311,7 @@ const getCompositionChanges = (selections, data) => {
3510
4311
  const selectionStartColumn = selections[i + 1];
3511
4312
  const selectionEndRow = selections[i + 2];
3512
4313
  const selectionEndColumn = selections[i + 3];
3513
- const startColumnIndex = selectionStartColumn - state$6.compositionText.length;
4314
+ const startColumnIndex = selectionStartColumn - state$4.compositionText.length;
3514
4315
  changes.push({
3515
4316
  start: {
3516
4317
  rowIndex: selectionStartRow,
@@ -3521,7 +4322,7 @@ const getCompositionChanges = (selections, data) => {
3521
4322
  columnIndex: selectionEndColumn
3522
4323
  },
3523
4324
  inserted: [data],
3524
- deleted: [state$6.compositionText],
4325
+ deleted: [state$4.compositionText],
3525
4326
  origin: CompositionUpdate
3526
4327
  });
3527
4328
  }
@@ -3532,7 +4333,7 @@ const compositionUpdate = (editor, data) => {
3532
4333
  selections
3533
4334
  } = editor;
3534
4335
  const changes = getCompositionChanges(selections, data);
3535
- state$6.compositionText = data;
4336
+ state$4.compositionText = data;
3536
4337
  return scheduleDocumentAndCursorsSelections(editor, changes);
3537
4338
  };
3538
4339
  const compositionEnd = (editor, data) => {
@@ -3540,8 +4341,8 @@ const compositionEnd = (editor, data) => {
3540
4341
  selections
3541
4342
  } = editor;
3542
4343
  const changes = getCompositionChanges(selections, data);
3543
- state$6.isComposing = false;
3544
- state$6.compositionText = '';
4344
+ state$4.isComposing = false;
4345
+ state$4.compositionText = '';
3545
4346
  return scheduleDocumentAndCursorsSelections(editor, changes);
3546
4347
  };
3547
4348
 
@@ -3755,7 +4556,7 @@ const characterRight = (line, columnIndex) => {
3755
4556
  return next.segment.length;
3756
4557
  };
3757
4558
  const isWhitespace = char => {
3758
- return char === Space$1 || char === Tab$1;
4559
+ return char === Space || char === Tab;
3759
4560
  };
3760
4561
  const lineCharacterStart = (line, columnIndex) => {
3761
4562
  if (line.length === 0) {
@@ -4567,68 +5368,19 @@ const goToTypeDefinition = async (editor, explicit = true) => {
4567
5368
  });
4568
5369
  };
4569
5370
 
4570
- const Editor = 3;
4571
-
4572
- const handleContextMenu = async (editor, button, x, y) => {
4573
- await invoke$9(/* ContextMenu.show */'ContextMenu.show', /* x */x, /* y */y, /* id */Editor);
4574
- return editor;
4575
- };
4576
-
4577
- // @ts-ignore
4578
-
4579
- // match all words, including umlauts, see https://stackoverflow.com/questions/5436824/matching-accented-characters-with-javascript-regexes/#answer-11550799
4580
- const RE_WORD_START = /^[a-z\u00C0-\u017F\d]+/i;
4581
- const RE_WORD_END = /[a-z\u00C0-\u017F\d]+$/i;
4582
-
4583
- // @ts-ignore
4584
- const getNewSelections$7 = (line, rowIndex, columnIndex) => {
4585
- const before = line.slice(0, columnIndex);
4586
- const after = line.slice(columnIndex);
4587
- const beforeMatch = before.match(RE_WORD_END);
4588
- const afterMatch = after.match(RE_WORD_START);
4589
- const columnStart = columnIndex - (beforeMatch ? beforeMatch[0].length : 0);
4590
- const columnEnd = columnIndex + (afterMatch ? afterMatch[0].length : 0);
4591
- const newSelections = new Uint32Array([rowIndex, columnStart, rowIndex, columnEnd]);
4592
- return newSelections;
4593
- };
4594
-
4595
- // @ts-ignore
4596
- const selectWord = (editor, rowIndex, columnIndex) => {
4597
- const line = getLine(editor, rowIndex);
4598
- const newSelections = getNewSelections$7(line, rowIndex, columnIndex);
4599
- return scheduleSelections(editor, newSelections);
4600
- };
4601
-
4602
- const handleDoubleClick = (editor, modifier, x, y) => {
4603
- const position = at(editor, x, y);
4604
- return selectWord(editor, position.rowIndex, position.columnIndex);
4605
- };
4606
-
4607
- const WhenExpressionEditorText = 12;
4608
- const handleFocus$1 = editor => {
4609
- // TODO make change events functional,
4610
- // when rendering, send focus changes to renderer worker
4611
- invoke$9('Focus.setFocus', WhenExpressionEditorText);
4612
- return editor;
4613
- };
4614
-
4615
- const Single = 1;
4616
- const Double = 2;
4617
- const Triple = 3;
4618
-
4619
- const state$5 = {
5371
+ const state$3 = {
4620
5372
  position: {
4621
5373
  rowIndex: 0,
4622
5374
  columnIndex: 0
4623
5375
  }
4624
5376
  };
4625
5377
  const getPosition$1 = () => {
4626
- return state$5.position;
5378
+ return state$3.position;
4627
5379
  };
4628
5380
 
4629
5381
  // @ts-ignore
4630
5382
  const setPosition$1 = position => {
4631
- state$5.position = position;
5383
+ state$3.position = position;
4632
5384
  };
4633
5385
 
4634
5386
  // TODO first change cursor position, then run go to definition
@@ -4675,7 +5427,7 @@ const handleSingleClickWithCtrl = async (editor, position) => {
4675
5427
  };
4676
5428
 
4677
5429
  const Ctrl = 1;
4678
- const Alt$1 = 2;
5430
+ const Alt = 2;
4679
5431
 
4680
5432
  const handleSingleClickDefault = (editor, position) => {
4681
5433
  setPosition$1(position);
@@ -4685,37 +5437,86 @@ const handleSingleClickDefault = (editor, position) => {
4685
5437
  focused: true
4686
5438
  };
4687
5439
  };
4688
- const getClickHandler = modifier => {
4689
- switch (modifier) {
4690
- case Alt$1:
4691
- return handleSingleClickWithAlt;
4692
- case Ctrl:
4693
- return handleSingleClickWithCtrl;
4694
- default:
4695
- return handleSingleClickDefault;
4696
- }
5440
+ const getClickHandler = modifier => {
5441
+ switch (modifier) {
5442
+ case Alt:
5443
+ return handleSingleClickWithAlt;
5444
+ case Ctrl:
5445
+ return handleSingleClickWithCtrl;
5446
+ default:
5447
+ return handleSingleClickDefault;
5448
+ }
5449
+ };
5450
+
5451
+ const handleClickAtPosition = async (editor, modifier, rowIndex, columnIndex) => {
5452
+ object(editor);
5453
+ number(modifier);
5454
+ number(rowIndex);
5455
+ number(columnIndex);
5456
+ const fn = getClickHandler(modifier);
5457
+ const newEditor = await fn(editor, {
5458
+ rowIndex,
5459
+ columnIndex
5460
+ });
5461
+ return newEditor;
5462
+ };
5463
+
5464
+ const Editor = 3;
5465
+
5466
+ const handleContextMenu = async (editor, button, x, y) => {
5467
+ await invoke$9(/* ContextMenu.show */'ContextMenu.show', /* x */x, /* y */y, /* id */Editor);
5468
+ return editor;
5469
+ };
5470
+
5471
+ // @ts-ignore
5472
+
5473
+ // match all words, including umlauts, see https://stackoverflow.com/questions/5436824/matching-accented-characters-with-javascript-regexes/#answer-11550799
5474
+ const RE_WORD_START = /^[a-z\u00C0-\u017F\d]+/i;
5475
+ const RE_WORD_END = /[a-z\u00C0-\u017F\d]+$/i;
5476
+
5477
+ // @ts-ignore
5478
+ const getNewSelections$7 = (line, rowIndex, columnIndex) => {
5479
+ const before = line.slice(0, columnIndex);
5480
+ const after = line.slice(columnIndex);
5481
+ const beforeMatch = before.match(RE_WORD_END);
5482
+ const afterMatch = after.match(RE_WORD_START);
5483
+ const columnStart = columnIndex - (beforeMatch ? beforeMatch[0].length : 0);
5484
+ const columnEnd = columnIndex + (afterMatch ? afterMatch[0].length : 0);
5485
+ const newSelections = new Uint32Array([rowIndex, columnStart, rowIndex, columnEnd]);
5486
+ return newSelections;
5487
+ };
5488
+
5489
+ // @ts-ignore
5490
+ const selectWord = (editor, rowIndex, columnIndex) => {
5491
+ const line = getLine(editor, rowIndex);
5492
+ const newSelections = getNewSelections$7(line, rowIndex, columnIndex);
5493
+ return scheduleSelections(editor, newSelections);
5494
+ };
5495
+
5496
+ const handleDoubleClick = (editor, modifier, x, y) => {
5497
+ const position = at(editor, x, y);
5498
+ return selectWord(editor, position.rowIndex, position.columnIndex);
5499
+ };
5500
+
5501
+ const WhenExpressionEditorText = 12;
5502
+ const handleFocus$1 = editor => {
5503
+ // TODO make change events functional,
5504
+ // when rendering, send focus changes to renderer worker
5505
+ invoke$9('Focus.setFocus', WhenExpressionEditorText);
5506
+ return editor;
4697
5507
  };
4698
5508
 
5509
+ const Single = 1;
5510
+ const Double = 2;
5511
+ const Triple = 3;
5512
+
4699
5513
  const handleSingleClick = async (editor, modifier, x, y) => {
4700
5514
  object(editor);
4701
5515
  number(modifier);
4702
5516
  number(x);
4703
5517
  number(y);
4704
5518
  const position = at(editor, x, y);
4705
- const fn = getClickHandler(modifier);
4706
- const newEditor = await fn(editor, position);
4707
- // switch (newEditor.completionState) {
4708
- // case EditorCompletionState.None:
4709
- // case EditorCompletionState.Visible:
4710
- // case EditorCompletionState.Loading:
4711
- // return {
4712
- // newState: newEditor,
4713
- // commands: [],
4714
- // }
4715
- // default:
4716
- // break
4717
- // }
4718
- return newEditor;
5519
+ return handleClickAtPosition(editor, modifier, position.rowIndex, position.columnIndex);
4719
5520
  };
4720
5521
 
4721
5522
  // @ts-ignore
@@ -4762,20 +5563,20 @@ const handleMouseDown = (state, modifier, x, y, detail) => {
4762
5563
  }
4763
5564
  };
4764
5565
 
4765
- const state$4 = {
5566
+ const state$2 = {
4766
5567
  timeout: -1,
4767
5568
  x: 0,
4768
5569
  y: 0,
4769
5570
  editor: undefined
4770
5571
  };
4771
- const get$3 = () => {
4772
- return state$4;
5572
+ const get = () => {
5573
+ return state$2;
4773
5574
  };
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;
5575
+ const set = (editor, timeout, x, y) => {
5576
+ state$2.editor = editor;
5577
+ state$2.timeout = timeout;
5578
+ state$2.x = x;
5579
+ state$2.y = y;
4779
5580
  };
4780
5581
 
4781
5582
  const showHover$1 = async (editor, position) => {
@@ -4797,7 +5598,7 @@ const onHoverIdle = async () => {
4797
5598
  x,
4798
5599
  y,
4799
5600
  editor
4800
- } = get$3();
5601
+ } = get();
4801
5602
  at(editor, x, y);
4802
5603
  await showHover$1();
4803
5604
  };
@@ -4808,12 +5609,12 @@ const handleMouseMove = (editor, x, y) => {
4808
5609
  if (!editor.hoverEnabled) {
4809
5610
  return editor;
4810
5611
  }
4811
- const oldState = get$3();
5612
+ const oldState = get();
4812
5613
  if (oldState.timeout !== -1) {
4813
5614
  clearTimeout(oldState.timeout);
4814
5615
  }
4815
5616
  const timeout = setTimeout(onHoverIdle, hoverDelay);
4816
- set$4(editor, timeout, x, y);
5617
+ set(editor, timeout, x, y);
4817
5618
  return editor;
4818
5619
  };
4819
5620
 
@@ -4920,7 +5721,7 @@ const editorHandleNativeSelectionChange = (editor, range) => {
4920
5721
  return scheduleSelections(editor, selections);
4921
5722
  };
4922
5723
 
4923
- const state$3 = {
5724
+ const state$1 = {
4924
5725
  /**
4925
5726
  * @type {any}
4926
5727
  */
@@ -4934,26 +5735,26 @@ const state$3 = {
4934
5735
 
4935
5736
  // @ts-ignore
4936
5737
  const setEditor = editor => {
4937
- state$3.currentEditor = editor;
4938
- state$3.hasListener = true;
5738
+ state$1.currentEditor = editor;
5739
+ state$1.hasListener = true;
4939
5740
  };
4940
5741
  const clearEditor = () => {
4941
- state$3.currentEditor = undefined;
4942
- state$3.hasListener = false;
5742
+ state$1.currentEditor = undefined;
5743
+ state$1.hasListener = false;
4943
5744
  };
4944
5745
 
4945
5746
  // @ts-ignore
4946
5747
  const setPosition = position => {
4947
- state$3.position = position;
5748
+ state$1.position = position;
4948
5749
  };
4949
5750
  const getEditor$1 = () => {
4950
- return state$3.currentEditor;
5751
+ return state$1.currentEditor;
4951
5752
  };
4952
5753
  const getPosition = () => {
4953
- return state$3.position;
5754
+ return state$1.position;
4954
5755
  };
4955
5756
  const hasListener = () => {
4956
- return state$3.hasListener;
5757
+ return state$1.hasListener;
4957
5758
  };
4958
5759
 
4959
5760
  // @ts-ignore
@@ -5136,7 +5937,7 @@ const handleTouchEnd = (editor, touchEvent) => {
5136
5937
  // }
5137
5938
  };
5138
5939
 
5139
- const state$2 = {
5940
+ const state = {
5140
5941
  touchOffsetY: 0,
5141
5942
  deltaY: 0
5142
5943
  };
@@ -5147,8 +5948,8 @@ const handleTouchStart = (editor, touchEvent) => {
5147
5948
  return;
5148
5949
  }
5149
5950
  const firstTouch = touchEvent.touches[0];
5150
- state$2.touchOffsetY = firstTouch.y;
5151
- state$2.deltaY = editor.deltaY;
5951
+ state.touchOffsetY = firstTouch.y;
5952
+ state.deltaY = editor.deltaY;
5152
5953
  // const position = EditorPosition.at(editor, firstTouch.x, firstTouch.y)
5153
5954
  // EditorMoveSelection.state.position = position
5154
5955
  // state.date = Date.now()
@@ -5188,7 +5989,7 @@ const handleTouchMove = (editor, touchEvent) => {
5188
5989
  return;
5189
5990
  }
5190
5991
  const firstTouch = touchEvent.touches[0];
5191
- const offsetY = state$2.deltaY + (state$2.touchOffsetY - firstTouch.y);
5992
+ const offsetY = state.deltaY + (state.touchOffsetY - firstTouch.y);
5192
5993
  setDeltaYFixedValue(editor, offsetY);
5193
5994
  };
5194
5995
 
@@ -5624,7 +6425,7 @@ const getOrCreate$2 = () => {
5624
6425
  }
5625
6426
  return workerPromise$2;
5626
6427
  };
5627
- const invoke$5 = async (method, ...params) => {
6428
+ const invoke$4 = async (method, ...params) => {
5628
6429
  const worker = await getOrCreate$2();
5629
6430
  return await worker.invoke(method, ...params);
5630
6431
  };
@@ -5643,10 +6444,10 @@ const newStateGenerator$4 = async (state, parentUid) => {
5643
6444
  const {
5644
6445
  languageId
5645
6446
  } = 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);
6447
+ await invoke$4('Completions.create', uid, x, y, width, height, parentUid, languageId);
6448
+ await invoke$4('Completions.loadContent', uid);
6449
+ const diff = await invoke$4('Completions.diff2', uid);
6450
+ const commands = await invoke$4('Completions.render2', uid, diff);
5650
6451
  return {
5651
6452
  ...state,
5652
6453
  commands
@@ -5698,7 +6499,7 @@ const launch = async () => {
5698
6499
  const rpc = await launchFindWidgetWorker();
5699
6500
  set$c(rpcId, rpc);
5700
6501
  };
5701
- const invoke$4 = async (method, ...params) => {
6502
+ const invoke$3 = async (method, ...params) => {
5702
6503
  const rpc = get$6(rpcId);
5703
6504
  return await rpc.invoke(method, ...params);
5704
6505
  };
@@ -5737,10 +6538,10 @@ const loadContent$1 = async (state, parentUid) => {
5737
6538
  height
5738
6539
  } = editor;
5739
6540
  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);
6541
+ await invoke$3('FindWidget.create', uid, x, y, width, height, parentUid);
6542
+ await invoke$3('FindWidget.loadContent', uid);
6543
+ const diff = await invoke$3('FindWidget.diff2', uid);
6544
+ const commands = await invoke$3('FindWidget.render2', uid, diff);
5744
6545
  return {
5745
6546
  ...state,
5746
6547
  commands
@@ -5813,10 +6614,10 @@ const newStateGenerator$2 = async (state, parentUid) => {
5813
6614
  const {
5814
6615
  languageId
5815
6616
  } = 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);
6617
+ await invoke$5('Rename.create', uid, x, y, width, height, parentUid, languageId);
6618
+ await invoke$5('Rename.loadContent', uid);
6619
+ const diff = await invoke$5('Rename.diff2', uid);
6620
+ const commands = await invoke$5('Rename.render2', uid, diff);
5820
6621
  return {
5821
6622
  ...state,
5822
6623
  commands
@@ -6556,128 +7357,6 @@ const setDecorations = (editor, decorations, diagnostics) => {
6556
7357
  };
6557
7358
  };
6558
7359
 
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;
6570
-
6571
- /**
6572
- * @enum number
6573
- */
6574
- const State = {
6575
- TopLevelContent: 1
6576
- };
6577
-
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
- 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
7360
  // TODO add command to set language id
6682
7361
  // without needing to specify tokenizePath
6683
7362
  const setLanguageId = async (editor, languageId, tokenizePath) => {
@@ -6691,17 +7370,33 @@ const setLanguageId = async (editor, languageId, tokenizePath) => {
6691
7370
  await loadTokenizer(languageId, tokenizePath);
6692
7371
  const tokenizer = getTokenizer(languageId);
6693
7372
  const newTokenizerId = tokenizerId + 1;
6694
- set(newTokenizerId, tokenizer);
7373
+ set$2(newTokenizerId, tokenizer);
6695
7374
  const latest = getEditor(editor.uid);
6696
7375
  if (!latest) {
6697
7376
  return editor;
6698
7377
  }
7378
+ const syncIncremental = getEnabled();
7379
+ const {
7380
+ textInfos,
7381
+ differences
7382
+ } = await getVisible$1(editor, syncIncremental);
7383
+ const latest2 = getEditor(editor.uid);
7384
+ if (!latest2) {
7385
+ return editor;
7386
+ }
7387
+ const newEditor4 = {
7388
+ ...latest2,
7389
+ focused: true,
7390
+ textInfos,
7391
+ differences
7392
+ };
7393
+
6699
7394
  // TODO don't update editor if tokenizer was already loaded
6700
7395
  // TODO update syntax highlighting
6701
7396
  // TODO get edits
6702
7397
 
6703
7398
  return {
6704
- ...latest,
7399
+ ...newEditor4,
6705
7400
  languageId,
6706
7401
  invalidStartIndex: 0,
6707
7402
  tokenizerId: newTokenizerId
@@ -7404,7 +8099,7 @@ const type = (editor, text) => {
7404
8099
  return scheduleDocumentAndCursorsSelections(editor, changes);
7405
8100
  };
7406
8101
 
7407
- const Slash$1 = '/';
8102
+ const Slash = '/';
7408
8103
 
7409
8104
  const CurlyOpen = '{';
7410
8105
  const CurlyClose = '}';
@@ -7519,7 +8214,7 @@ const typeWithAutoClosing = async (editor, text) => {
7519
8214
  }
7520
8215
  break;
7521
8216
  // case AutoClosing.ClosingAngleBracket: // TODO support auto closing when typing closing angle bracket of start tag
7522
- case Slash$1:
8217
+ case Slash:
7523
8218
  if (isAutoClosingTagsEnabled) {
7524
8219
  return typeWithAutoClosingTag(editor, text);
7525
8220
  }
@@ -7746,11 +8441,11 @@ const getWidgetInvoke = widgetId => {
7746
8441
  case ColorPicker$1:
7747
8442
  return invoke$8;
7748
8443
  case Completion:
7749
- return invoke$5;
7750
- case Find:
7751
8444
  return invoke$4;
8445
+ case Find:
8446
+ return invoke$3;
7752
8447
  case Rename$1:
7753
- return invoke$6;
8448
+ return invoke$5;
7754
8449
  case SourceAction$1:
7755
8450
  return invoke$1;
7756
8451
  case Hover:
@@ -8017,15 +8712,7 @@ const measureTextBlockHeight = async (text, fontFamily, fontSize, lineHeight, wi
8017
8712
  return 100;
8018
8713
  };
8019
8714
 
8020
- const deepCopy = value => {
8021
- return structuredClone(value);
8022
- };
8023
-
8024
- const getInitialLineState = initialLineState => {
8025
- return deepCopy(initialLineState);
8026
- };
8027
-
8028
- const getLineInfo$1 = (line, tokens, TokenMap) => {
8715
+ const getLineInfo = (line, tokens, TokenMap) => {
8029
8716
  const tokensLength = tokens.length;
8030
8717
  let end = 0;
8031
8718
  let start = 0;
@@ -8043,45 +8730,6 @@ const getLineInfo$1 = (line, tokens, TokenMap) => {
8043
8730
  return lineInfo;
8044
8731
  };
8045
8732
 
8046
- const state = {
8047
- warned: []
8048
- };
8049
- const flattenTokensArray = tokens => {
8050
- const flattened = [];
8051
- for (const token of tokens) {
8052
- object(token);
8053
- flattened.push(token.type, token.length);
8054
- }
8055
- return flattened;
8056
- };
8057
- const warnDeprecatedArrayReturn = (languageId, fn) => {
8058
- if (state.warned.includes(fn)) {
8059
- return;
8060
- }
8061
- state.warned.push(fn);
8062
- console.warn(`tokenizers without hasArrayReturn=false are deprecated (language ${languageId})`);
8063
- };
8064
- const safeTokenizeLine = (languageId, tokenizeLine, line, lineStateAtStart, hasArrayReturn) => {
8065
- try {
8066
- const lineState = tokenizeLine(line, lineStateAtStart);
8067
- if (!lineState?.tokens || !lineState.state) {
8068
- throw new Error('invalid tokenization result');
8069
- }
8070
- if (!hasArrayReturn) {
8071
- warnDeprecatedArrayReturn(languageId, tokenizeLine);
8072
- // workaround for old tokenizers
8073
- lineState.tokens = flattenTokensArray(lineState.tokens);
8074
- }
8075
- return lineState;
8076
- } catch (error) {
8077
- console.error(error);
8078
- return {
8079
- tokens: [/* type */0, /* length */line.length],
8080
- lineState: lineStateAtStart
8081
- };
8082
- }
8083
- };
8084
-
8085
8733
  const getLineInfos = (lines, tokenizer, languageId) => {
8086
8734
  const lineInfos = [];
8087
8735
  const {
@@ -8096,7 +8744,7 @@ const getLineInfos = (lines, tokenizer, languageId) => {
8096
8744
  const {
8097
8745
  tokens
8098
8746
  } = result;
8099
- const lineInfo = getLineInfo$1(line, tokens, TokenMap);
8747
+ const lineInfo = getLineInfo(line, tokens, TokenMap);
8100
8748
  lineInfos.push(lineInfo);
8101
8749
  currentLineState = result;
8102
8750
  }
@@ -8698,71 +9346,34 @@ const getFonts = () => {
8698
9346
 
8699
9347
  const loadFont = async (fontName, fontUrl) => {
8700
9348
  try {
8701
- string(fontName);
8702
- string(fontUrl);
8703
- if (fontName.startsWith("'")) {
8704
- throw new Error('font name is not allowed start with quotes');
8705
- }
8706
- const fontFace = new FontFace(fontName, fontUrl, {});
8707
- await fontFace.load();
8708
- const fonts = getFonts();
8709
- // @ts-ignore
8710
- fonts.add(fontFace);
8711
- } catch (error) {
8712
- throw new VError(error, `Failed to load font ${fontName}`);
8713
- }
8714
- };
8715
-
8716
- const ensure = async (fontName, fontUrl) => {
8717
- if (isLoaded(fontName)) {
8718
- return;
8719
- }
8720
- if (hasPending(fontName)) {
8721
- return getPending(fontName);
8722
- }
8723
- const promise = loadFont(fontName, fontUrl);
8724
- setPending(fontName, promise);
8725
- await promise;
8726
- removePending(fontName);
8727
- setLoaded(fontName);
8728
- };
8729
-
8730
- const Backspace = 1;
8731
- const Tab = 2;
8732
- const Enter = 3;
8733
- const Escape = 8;
8734
- const Space = 9;
8735
- const End = 255;
8736
- const Home = 12;
8737
- const LeftArrow = 13;
8738
- const UpArrow = 14;
8739
- const RightArrow = 15;
8740
- const DownArrow = 16;
8741
- const Delete = 18;
8742
- const KeyA = 29;
8743
- const KeyC = 31;
8744
- const KeyD = 32;
8745
- const KeyF = 34;
8746
- const KeyH = 36;
8747
- const KeyJ = 38;
8748
- const KeyK = 39;
8749
- const KeyL = 40;
8750
- const KeyO = 43;
8751
- const KeyV = 50;
8752
- const KeyX = 52;
8753
- const KeyZ = 54;
8754
- const F2 = 58;
8755
- const F3 = 59;
8756
- const F4 = 60;
8757
- const F12 = 68;
8758
- const Period = 87;
8759
- const Slash = 88;
8760
- const BracketLeft = 90;
8761
- const BracketRight = 92;
9349
+ string(fontName);
9350
+ string(fontUrl);
9351
+ if (fontName.startsWith("'")) {
9352
+ throw new Error('font name is not allowed start with quotes');
9353
+ }
9354
+ const fontFace = new FontFace(fontName, fontUrl, {});
9355
+ await fontFace.load();
9356
+ const fonts = getFonts();
9357
+ // @ts-ignore
9358
+ fonts.add(fontFace);
9359
+ } catch (error) {
9360
+ throw new VError(error, `Failed to load font ${fontName}`);
9361
+ }
9362
+ };
8762
9363
 
8763
- const CtrlCmd = 1 << 11 >>> 0;
8764
- const Shift = 1 << 10 >>> 0;
8765
- const Alt = 1 << 9 >>> 0;
9364
+ const ensure = async (fontName, fontUrl) => {
9365
+ if (isLoaded(fontName)) {
9366
+ return;
9367
+ }
9368
+ if (hasPending(fontName)) {
9369
+ return getPending(fontName);
9370
+ }
9371
+ const promise = loadFont(fontName, fontUrl);
9372
+ setPending(fontName, promise);
9373
+ await promise;
9374
+ removePending(fontName);
9375
+ setLoaded(fontName);
9376
+ };
8766
9377
 
8767
9378
  const getKeyBindings = () => {
8768
9379
  return [{
@@ -8806,59 +9417,59 @@ const getKeyBindings = () => {
8806
9417
  command: 'FindWidget.focusNext',
8807
9418
  when: FocusFindWidget
8808
9419
  }, {
8809
- key: Shift | Tab,
9420
+ key: Shift | Tab$1,
8810
9421
  command: 'FindWidget.focusToggleReplace',
8811
9422
  when: FocusFindWidget
8812
9423
  }, {
8813
- key: Tab,
9424
+ key: Tab$1,
8814
9425
  command: 'FindWidget.focusReplace',
8815
9426
  when: FocusFindWidget
8816
9427
  }, {
8817
- key: Tab,
9428
+ key: Tab$1,
8818
9429
  command: 'FindWidget.focusPreviousMatchButton',
8819
9430
  when: FocusFindWidgetReplace
8820
9431
  }, {
8821
- key: Alt | CtrlCmd | Enter,
9432
+ key: Alt$1 | CtrlCmd | Enter,
8822
9433
  command: 'FindWidget.replaceAll',
8823
9434
  when: FocusFindWidgetReplace
8824
9435
  }, {
8825
- key: Tab,
9436
+ key: Tab$1,
8826
9437
  command: 'FindWidget.focusNextMatchButton',
8827
9438
  when: FocusFindWidgetPreviousMatchButton
8828
9439
  }, {
8829
- key: Shift | Tab,
9440
+ key: Shift | Tab$1,
8830
9441
  command: 'FindWidget.focusReplace',
8831
9442
  when: FocusFindWidgetPreviousMatchButton
8832
9443
  }, {
8833
- key: Shift | Tab,
9444
+ key: Shift | Tab$1,
8834
9445
  command: 'FindWidget.focusPreviousMatchButton',
8835
9446
  when: FocusFindWidgetNextMatchButton
8836
9447
  }, {
8837
- key: Tab,
9448
+ key: Tab$1,
8838
9449
  command: 'FindWidget.focusCloseButton',
8839
9450
  when: FocusFindWidgetNextMatchButton
8840
9451
  }, {
8841
- key: Shift | Tab,
9452
+ key: Shift | Tab$1,
8842
9453
  command: 'FindWidget.focusNextMatchButton',
8843
9454
  when: FocusFindWidgetCloseButton
8844
9455
  }, {
8845
- key: Tab,
9456
+ key: Tab$1,
8846
9457
  command: 'FindWidget.focusReplaceButton',
8847
9458
  when: FocusFindWidgetCloseButton
8848
9459
  }, {
8849
- key: Shift | Tab,
9460
+ key: Shift | Tab$1,
8850
9461
  command: 'FindWidget.focusFind',
8851
9462
  when: FocusFindWidgetReplace
8852
9463
  }, {
8853
- key: Tab,
9464
+ key: Tab$1,
8854
9465
  command: 'FindWidget.focusReplaceAllButton',
8855
9466
  when: FocusFindWidgetReplaceButton
8856
9467
  }, {
8857
- key: Shift | Tab,
9468
+ key: Shift | Tab$1,
8858
9469
  command: 'FindWidget.focusCloseButton',
8859
9470
  when: FocusFindWidgetReplaceButton
8860
9471
  }, {
8861
- key: Shift | Tab,
9472
+ key: Shift | Tab$1,
8862
9473
  command: 'FindWidget.focusReplaceButton',
8863
9474
  when: FocusFindWidgetReplaceAllButton
8864
9475
  }, {
@@ -8886,7 +9497,7 @@ const getKeyBindings = () => {
8886
9497
  command: 'EditorCompletion.focusFirst',
8887
9498
  when: FocusEditorCompletions
8888
9499
  }, {
8889
- key: CtrlCmd | Space,
9500
+ key: CtrlCmd | Space$1,
8890
9501
  command: 'EditorCompletion.toggleDetails',
8891
9502
  when: FocusEditorCompletions
8892
9503
  }, {
@@ -8898,11 +9509,11 @@ const getKeyBindings = () => {
8898
9509
  command: 'Editor.cursorWordLeft',
8899
9510
  when: FocusEditorText
8900
9511
  }, {
8901
- key: Alt | Backspace,
9512
+ key: Alt$1 | Backspace,
8902
9513
  command: 'Editor.deleteWordPartLeft',
8903
9514
  when: FocusEditorText
8904
9515
  }, {
8905
- key: Alt | Delete,
9516
+ key: Alt$1 | Delete,
8906
9517
  command: 'Editor.deleteWordPartRight',
8907
9518
  when: FocusEditorText
8908
9519
  }, {
@@ -8926,11 +9537,11 @@ const getKeyBindings = () => {
8926
9537
  command: 'Editor.showSourceActions3',
8927
9538
  when: FocusEditorText
8928
9539
  }, {
8929
- key: Tab,
9540
+ key: Tab$1,
8930
9541
  command: 'Editor.handleTab',
8931
9542
  when: FocusEditorText
8932
9543
  }, {
8933
- key: Shift | Tab,
9544
+ key: Shift | Tab$1,
8934
9545
  command: 'Editor.unindent',
8935
9546
  when: FocusEditorText
8936
9547
  }, {
@@ -9038,7 +9649,7 @@ const getKeyBindings = () => {
9038
9649
  command: 'Editor.moveLineUp',
9039
9650
  when: FocusEditorText
9040
9651
  }, {
9041
- key: CtrlCmd | Space,
9652
+ key: CtrlCmd | Space$1,
9042
9653
  command: 'Editor.openCompletion',
9043
9654
  when: FocusEditorText
9044
9655
  }, {
@@ -9062,7 +9673,7 @@ const getKeyBindings = () => {
9062
9673
  command: 'Editor.cursorEnd',
9063
9674
  when: FocusEditorText
9064
9675
  }, {
9065
- key: CtrlCmd | Slash,
9676
+ key: CtrlCmd | Slash$1,
9066
9677
  command: 'Editor.toggleComment',
9067
9678
  when: FocusEditorText
9068
9679
  }, {
@@ -9086,35 +9697,35 @@ const getKeyBindings = () => {
9086
9697
  command: 'Editor.paste',
9087
9698
  when: FocusEditorText
9088
9699
  }, {
9089
- key: Alt | LeftArrow,
9700
+ key: Alt$1 | LeftArrow,
9090
9701
  command: 'Editor.cursorWordPartLeft',
9091
9702
  when: FocusEditorText
9092
9703
  }, {
9093
- key: Alt | RightArrow,
9704
+ key: Alt$1 | RightArrow,
9094
9705
  command: 'Editor.cursorWordPartRight',
9095
9706
  when: FocusEditorText
9096
9707
  }, {
9097
- key: Alt | F3,
9708
+ key: Alt$1 | F3,
9098
9709
  command: 'Editor.selectAllOccurrences',
9099
9710
  when: FocusEditorText
9100
9711
  }, {
9101
- key: Alt | Shift | UpArrow,
9712
+ key: Alt$1 | Shift | UpArrow,
9102
9713
  command: 'Editor.addCursorAbove',
9103
9714
  when: FocusEditorText
9104
9715
  }, {
9105
- key: Alt | Shift | DownArrow,
9716
+ key: Alt$1 | Shift | DownArrow,
9106
9717
  command: 'Editor.addCursorBelow',
9107
9718
  when: FocusEditorText
9108
9719
  }, {
9109
- key: Alt | Shift | F12,
9720
+ key: Alt$1 | Shift | F12,
9110
9721
  command: 'Editor.findAllReferences',
9111
9722
  when: FocusEditorText
9112
9723
  }, {
9113
- key: Alt | Shift | KeyO,
9724
+ key: Alt$1 | Shift | KeyO,
9114
9725
  command: 'Editor.organizeImports',
9115
9726
  when: FocusEditorText
9116
9727
  }, {
9117
- key: CtrlCmd | Shift | Space,
9728
+ key: CtrlCmd | Shift | Space$1,
9118
9729
  command: 'Editor.selectionGrow',
9119
9730
  when: FocusEditor
9120
9731
  }];
@@ -9211,776 +9822,282 @@ const getQuickPickMenuEntries = () => {
9211
9822
  }, {
9212
9823
  id: 'Editor.showSourceActions2',
9213
9824
  label: sourceAction()
9214
- }];
9215
- };
9216
-
9217
- const getSelections = editorUid => {
9218
- const editor = getEditor(editorUid);
9219
- const {
9220
- selections
9221
- } = editor;
9222
- return selections;
9223
- };
9224
-
9225
- const getText = editorUid => {
9226
- number(editorUid);
9227
- const editor = getEditor(editorUid);
9228
- const {
9229
- lines
9230
- } = editor;
9231
- return lines.join(NewLine);
9232
- };
9233
-
9234
- const InsertText = 'insertText';
9235
-
9236
- const handleBeforeInput = (editor, inputType, data) => {
9237
- switch (inputType) {
9238
- case InsertText:
9239
- return typeWithAutoClosing(editor, data);
9240
- default:
9241
- return editor;
9242
- }
9243
- };
9244
-
9245
- const handleMessagePort = async (port, rpcId) => {
9246
- const rpc = await PlainMessagePortRpcParent.create({
9247
- messagePort: port,
9248
- commandMap: {}
9249
- });
9250
- if (rpcId) {
9251
- set$c(rpcId, rpc);
9252
- }
9253
- };
9254
-
9255
- const applyTabCompletion = (editor, result) => {
9256
- return editorSnippet(editor, result);
9257
- };
9258
-
9259
- const handleTab = async editor => {
9260
- const result = await getTabCompletion(editor);
9261
- if (!result) {
9262
- // TODO enter tab or two spaces
9263
- return editor;
9264
- }
9265
- return applyTabCompletion(editor, result);
9266
- };
9267
-
9268
- const relaunchWorkers = async () => {
9269
- await dispose();
9270
- await launch();
9271
- };
9272
-
9273
- const getWidgetName = widgetId => {
9274
- switch (widgetId) {
9275
- case Find:
9276
- return `FindWidget`;
9277
- default:
9278
- return '';
9279
- }
9280
- };
9281
- const saveWidgetState = async keys => {
9282
- const savedStates = Object.create(null);
9283
- for (const key of keys) {
9284
- const editor = get$4(parseInt(key));
9285
- const {
9286
- widgets
9287
- } = editor.newState;
9288
- for (const widget of widgets) {
9289
- const invoke = getWidgetInvoke(widget.id);
9290
- const fullKey = `${key}:${widget.newState.uid}`;
9291
- const name = getWidgetName(widget.id);
9292
- const savedState = await invoke(`${name}.saveState`, widget.newState.uid);
9293
- savedStates[fullKey] = savedState;
9294
- }
9295
- }
9296
- return savedStates;
9297
- };
9298
-
9299
- const restoreWidgetState = async (keys, savedStates) => {
9300
- const newEditors = [];
9301
- for (const key of keys) {
9302
- const editorUid = parseInt(key);
9303
- const editor = get$4(editorUid);
9304
- const {
9305
- widgets
9306
- } = editor.newState;
9307
- const newWidgets = [];
9308
- for (const widget of widgets) {
9309
- const invoke = getWidgetInvoke(widget.id);
9310
- const fullKey = `${key}:${widget.newState.uid}`;
9311
- const savedState = savedStates[fullKey] || {};
9312
- const name = getWidgetName(widget.id);
9313
- await invoke(`${name}.create`, widget.newState.uid, widget.newState.x, widget.newState.y, widget.newState.width, widget.newState.height, editorUid);
9314
- await invoke(`${name}.loadContent`, widget.newState.uid, savedState);
9315
- const diffResult = await invoke(`${name}.diff2`, widget.newState.uid);
9316
- const commands = await invoke(`${name}.render2`, widget.newState.uid, diffResult);
9317
- const newWidget = {
9318
- ...widget,
9319
- newState: {
9320
- ...widget.newState,
9321
- commands
9322
- }
9323
- };
9324
- newWidgets.push(newWidget);
9325
- }
9326
- newEditors.push({
9327
- ...editor,
9328
- newState: {
9329
- ...editor.newState,
9330
- widgets: newWidgets
9331
- }
9332
- });
9333
- }
9334
- return newEditors;
9335
- };
9336
-
9337
- let isReloading = false;
9338
- const hotReload = async () => {
9339
- if (isReloading) {
9340
- return;
9341
- }
9342
- isReloading = true;
9343
-
9344
- // TODO use getEditors
9345
- const keys = getKeys$1();
9346
- const savedStates = await saveWidgetState(keys);
9347
- await relaunchWorkers();
9348
- const newEditors = await restoreWidgetState(keys, savedStates);
9349
- for (const editor of newEditors) {
9350
- set$6(editor.newState.uid, editor.oldState, editor.newState);
9351
- }
9352
-
9353
- // TODO ask renderer worker to rerender all editors
9354
- // @ts-ignore
9355
- await invoke$9(`Editor.rerender`);
9356
- isReloading = false;
9357
- };
9358
-
9359
- const sendMessagePortToExtensionHostWorker2 = async (port, initialCommand, rpcId) => {
9360
- await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToExtensionHostWorker', port, initialCommand, rpcId);
9361
- };
9362
-
9363
- const createExtensionHostRpc = async () => {
9364
- try {
9365
- const {
9366
- port1,
9367
- port2
9368
- } = getPortTuple();
9369
- const initialCommand = 'HandleMessagePort.handleMessagePort2';
9370
- // TODO use transfer rpc
9371
- await sendMessagePortToExtensionHostWorker2(port2, initialCommand, EditorWorker);
9372
- const rpc = await PlainMessagePortRpcParent.create({
9373
- commandMap: {},
9374
- messagePort: port1
9375
- });
9376
- return rpc;
9377
- } catch (error) {
9378
- throw new VError(error, `Failed to create extension host rpc`);
9379
- }
9380
- };
9381
-
9382
- const initializeExtensionHost = async () => {
9383
- const extensionHostRpc = await createExtensionHostRpc();
9384
- set$5(extensionHostRpc);
9385
- };
9386
-
9387
- const sendMessagePortToSyntaxHighlightingWorker = async () => {
9388
- try {
9389
- const {
9390
- port1,
9391
- port2
9392
- } = getPortTuple();
9393
- await invokeAndTransfer(
9394
- // @ts-ignore
9395
- 'SendMessagePortToSyntaxHighlightingWorker.sendMessagePortToSyntaxHighlightingWorker', port1, 'HandleMessagePort.handleMessagePort2');
9396
- return port2;
9397
- } catch {
9398
- const {
9399
- port1,
9400
- port2
9401
- } = getPortTuple();
9402
- await invokeAndTransfer(
9403
- // @ts-ignore
9404
- 'SendMessagePortToSyntaxHighlightingWorker.sendMessagePortToSyntaxHighlightingWorker', port1, 'HandleMessagePort.handleMessagePort');
9405
- return port2;
9406
- }
9407
- };
9408
-
9409
- const createSyntaxHighlightingWorkerRpc = async () => {
9410
- try {
9411
- const port = await sendMessagePortToSyntaxHighlightingWorker();
9412
- const rpc = await PlainMessagePortRpcParent.create({
9413
- commandMap: {},
9414
- messagePort: port
9415
- });
9416
- return rpc;
9417
- } catch (error) {
9418
- throw new VError(error, `Failed to create syntax highlighting worker rpc`);
9419
- }
9420
- };
9421
-
9422
- let enabled = false;
9423
- const setEnabled = value => {
9424
- enabled = value;
9425
- };
9426
- const getEnabled = () => {
9427
- return enabled;
9428
- };
9429
-
9430
- const initializeSyntaxHighlighting = async (syntaxHighlightingEnabled, syncIncremental) => {
9431
- if (syntaxHighlightingEnabled) {
9432
- setEnabled$1(true);
9433
- const syntaxRpc = await createSyntaxHighlightingWorkerRpc();
9434
- set$3(syntaxRpc);
9435
- }
9436
- if (syncIncremental) {
9437
- setEnabled(true);
9438
- }
9439
- };
9440
-
9441
- const intialize = async (syntaxHighlightingEnabled, syncIncremental) => {
9442
- await Promise.all([initializeSyntaxHighlighting(syntaxHighlightingEnabled, syncIncremental), initializeExtensionHost()]);
9825
+ }];
9443
9826
  };
9444
9827
 
9445
- // TODO move cursor
9446
- // TODO multiple cursors -> vscode removes multiple cursors
9447
- // TODO with selection -> vscode moves whole selection
9448
- const moveLineDown = editor => {
9449
- // const rowIndex = editor.cursor.rowIndex
9450
- // if (rowIndex === editor.lines.length - 1) {
9451
- // return
9452
- // }
9453
- // const documentEdits = [
9454
- // {
9455
- // type: /* splice */ 2,
9456
- // rowIndex: rowIndex,
9457
- // count: 2,
9458
- // newLines: [TextDocument.getLine(editor.textDocument, rowIndex + 1), TextDocument.getLine(editor.textDocument, rowIndex)],
9459
- // },
9460
- // ]
9461
- // // @ts-ignore
9462
- // const cursorEdits = Editor.moveCursors(editor, (editor, cursor) => {
9463
- // return {
9464
- // rowIndex: cursor.rowIndex + 1,
9465
- // columnIndex: cursor.columnIndex,
9466
- // }
9467
- // })
9468
- // @ts-ignore
9469
- // Editor.scheduleDocumentAndCursors(editor, documentEdits, cursorEdits)
9470
- return editor;
9828
+ const getSelections = editorUid => {
9829
+ const editor = getEditor(editorUid);
9830
+ const {
9831
+ selections
9832
+ } = editor;
9833
+ return selections;
9471
9834
  };
9472
9835
 
9473
- // TODO handle multiple cursors
9474
- const moveLineUp = editor => {
9475
- // const rowIndex = editor.cursor.rowIndex
9476
- // if (rowIndex === 0) {
9477
- // return
9478
- // }
9479
- // const documentEdits = [
9480
- // {
9481
- // type: /* splice */ 2,
9482
- // rowIndex: rowIndex - 1,
9483
- // count: 2,
9484
- // newLines: [TextDocument.getLine(editor.textDocument, rowIndex), TextDocument.getLine(editor.textDocument, rowIndex - 1)],
9485
- // },
9486
- // ]
9487
- // // @ts-ignore
9488
- // const cursorEdits = Editor.moveCursors(editor, (editor, cursor) => {
9489
- // return {
9490
- // // TODO handle bottom 0
9491
- // rowIndex: cursor.rowIndex - 1,
9492
- // columnIndex: cursor.columnIndex,
9493
- // }
9494
- // })
9495
- // // @ts-ignore
9496
- // Editor.scheduleDocumentAndCursors(editor, documentEdits, cursorEdits)
9497
- return editor;
9836
+ const getText = editorUid => {
9837
+ number(editorUid);
9838
+ const editor = getEditor(editorUid);
9839
+ const {
9840
+ lines
9841
+ } = editor;
9842
+ return lines.join(NewLine);
9498
9843
  };
9499
9844
 
9500
- const Link$1 = 'Link';
9501
- const Function = 'Function';
9502
- const Parameter = 'Parameter';
9503
- const Type = 'Type';
9504
- const VariableName = 'VariableName';
9505
- const Class = 'Class';
9506
-
9507
- const Link = 1;
9508
- const Ts2816 = 2816;
9509
- const Ts2817 = 2817;
9510
- const Ts2824 = 2824;
9511
- const Ts2825 = 2825;
9512
- const Ts2856 = 2956;
9513
- const Ts2857 = 2857;
9514
- const Ts3072 = 3072;
9515
- const Ts3073 = 3073;
9516
- const Ts3077 = 3077;
9517
- const Ts3088 = 3088;
9518
- const Ts1792 = 1792;
9519
- const Ts1793 = 1793;
9520
- const Ts512 = 512;
9521
- const Ts513 = 513;
9522
- const Ts769 = 769;
9523
- const Ts1024 = 1024;
9524
- const Ts1536 = 1536;
9525
- const Ts1537 = 1537;
9526
- const Ts1544 = 1544;
9527
- const Ts1545 = 1545;
9528
- const Ts2048 = 2048;
9529
- const Ts2049 = 2049;
9530
- const Ts2056 = 2056;
9531
- const Ts2057 = 2057;
9532
- const Ts2064 = 2064;
9533
- const Ts2080 = 2080;
9534
- const Ts2081 = 2081;
9535
- const Ts2088 = 2088;
9536
- const Ts2089 = 2089;
9537
- const Ts2313 = 2313;
9538
- const Ts2560 = 2560;
9539
- const Ts2561 = 2561;
9540
- const Ts2569 = 2569;
9541
- const Ts2584 = 2584;
9542
- const Ts256 = 256;
9543
- const Ts257 = 257;
9544
- const Ts272 = 272;
9845
+ const InsertText = 'insertText';
9545
9846
 
9546
- const getDecorationClassName = type => {
9547
- switch (type) {
9548
- case Link:
9549
- return Link$1;
9550
- case Ts2816:
9551
- case Ts2817:
9552
- case Ts2824:
9553
- case Ts2825:
9554
- case Ts2856:
9555
- case Ts2857:
9556
- case Ts3072:
9557
- case Ts3073:
9558
- case Ts3077:
9559
- case Ts3088:
9560
- return Function;
9561
- case Ts1792:
9562
- case Ts1793:
9563
- return Parameter;
9564
- case Ts512:
9565
- case Ts513:
9566
- case Ts769:
9567
- case Ts1024:
9568
- case Ts1536:
9569
- case Ts1537:
9570
- case Ts1544:
9571
- case Ts1545:
9572
- return Type;
9573
- case Ts2048:
9574
- case Ts2049:
9575
- case Ts2056:
9576
- case Ts2057:
9577
- case Ts2064:
9578
- case Ts2080:
9579
- case Ts2081:
9580
- case Ts2088:
9581
- case Ts2089:
9582
- case Ts2313:
9583
- case Ts2560:
9584
- case Ts2561:
9585
- case Ts2569:
9586
- case Ts2584:
9587
- return VariableName;
9588
- case Ts256:
9589
- case Ts257:
9590
- case Ts272:
9591
- return Class;
9847
+ const handleBeforeInput = (editor, inputType, data) => {
9848
+ switch (inputType) {
9849
+ case InsertText:
9850
+ return typeWithAutoClosing(editor, data);
9592
9851
  default:
9593
- return `Unknown-${type}`;
9852
+ return editor;
9594
9853
  }
9595
9854
  };
9596
9855
 
9597
- const getTokensViewportEmbedded = (langageId, lines, lineCache, linesWithEmbed) => {
9598
- const tokenizersToLoad = [];
9599
- const embeddedResults = [];
9600
- let topContext;
9601
- for (const index of linesWithEmbed) {
9602
- const result = lineCache[index + 1];
9603
- const line = lines[index];
9604
- if (result.embeddedLanguage) {
9605
- const {
9606
- embeddedLanguage,
9607
- embeddedLanguageStart,
9608
- embeddedLanguageEnd
9609
- } = result;
9610
- const embeddedTokenizer = getTokenizer(embeddedLanguage);
9611
- if (embeddedLanguageStart !== line.length && embeddedTokenizer && embeddedTokenizer !== TokenizePlainText) {
9612
- const isFull = embeddedLanguageStart === 0 && embeddedLanguageEnd === line.length;
9613
- const partialLine = line.slice(embeddedLanguageStart, embeddedLanguageEnd);
9614
- const embedResult = safeTokenizeLine(langageId, embeddedTokenizer.tokenizeLine, partialLine, topContext || getInitialLineState(embeddedTokenizer.initialLineState), embeddedTokenizer.hasArrayReturn);
9615
- topContext = embedResult;
9616
- result.embeddedResultIndex = embeddedResults.length;
9617
- embeddedResults.push({
9618
- result: embedResult,
9619
- TokenMap: embeddedTokenizer.TokenMap,
9620
- isFull
9621
- });
9622
- } else if (line.length === 0) {
9623
- const embedResult = {
9624
- tokens: []
9625
- };
9626
- result.embeddedResultIndex = embeddedResults.length;
9627
- embeddedResults.push({
9628
- result: embedResult,
9629
- isFull: true,
9630
- TokenMap: []
9631
- });
9632
- } else {
9633
- tokenizersToLoad.push(embeddedLanguage);
9634
- embeddedResults.push({
9635
- result: {},
9636
- isFull: false,
9637
- TokenMap: []
9638
- });
9639
- topContext = undefined;
9640
- }
9641
- } else {
9642
- topContext = undefined;
9643
- }
9856
+ const handleMessagePort = async (port, rpcId) => {
9857
+ const rpc = await PlainMessagePortRpcParent.create({
9858
+ messagePort: port,
9859
+ commandMap: {}
9860
+ });
9861
+ if (rpcId) {
9862
+ set$c(rpcId, rpc);
9644
9863
  }
9645
- return {
9646
- tokenizersToLoad,
9647
- embeddedResults
9648
- };
9649
9864
  };
9650
- const getTokenizeEndIndex = (invalidStartIndex, endLineIndex, tokenizeStartIndex) => {
9651
- return invalidStartIndex < endLineIndex ? endLineIndex : tokenizeStartIndex;
9865
+
9866
+ const applyTabCompletion = (editor, result) => {
9867
+ return editorSnippet(editor, result);
9652
9868
  };
9653
9869
 
9654
- // TODO only send changed lines to renderer process instead of all lines in viewport
9655
- const getTokensViewport = (editor, startLineIndex, endLineIndex) => {
9656
- const {
9657
- invalidStartIndex,
9658
- lineCache,
9659
- tokenizerId,
9660
- lines,
9661
- languageId
9662
- } = editor;
9663
- const tokenizer = get(tokenizerId);
9664
- const {
9665
- hasArrayReturn,
9666
- tokenizeLine,
9667
- initialLineState
9668
- } = tokenizer;
9669
- const tokenizeStartIndex = invalidStartIndex;
9670
- const tokenizeEndIndex = getTokenizeEndIndex(invalidStartIndex, endLineIndex, tokenizeStartIndex);
9671
- const tokenizersToLoad = [];
9672
- const embeddedResults = [];
9673
- const linesWithEmbed = [];
9674
- for (let i = tokenizeStartIndex; i < tokenizeEndIndex; i++) {
9675
- const lineState = i === 0 ? getInitialLineState(initialLineState) : lineCache[i];
9676
- const line = lines[i];
9677
- const result = safeTokenizeLine(languageId, tokenizeLine, line, lineState, hasArrayReturn);
9678
- // TODO if lineCacheEnd matches the one before, skip tokenizing lines after
9679
- lineCache[i + 1] = result;
9680
- if (result.embeddedLanguage) {
9681
- result.embeddedResultIndex = linesWithEmbed.length;
9682
- linesWithEmbed.push(i);
9683
- }
9870
+ const handleTab = async editor => {
9871
+ const result = await getTabCompletion(editor);
9872
+ if (!result) {
9873
+ // TODO enter tab or two spaces
9874
+ return editor;
9684
9875
  }
9685
- const visibleLines = lineCache.slice(startLineIndex + 1, endLineIndex + 1);
9686
- if (linesWithEmbed.length > 0) {
9876
+ return applyTabCompletion(editor, result);
9877
+ };
9878
+
9879
+ const relaunchWorkers = async () => {
9880
+ await dispose();
9881
+ await launch();
9882
+ };
9883
+
9884
+ const getWidgetName = widgetId => {
9885
+ switch (widgetId) {
9886
+ case Find:
9887
+ return `FindWidget`;
9888
+ default:
9889
+ return '';
9890
+ }
9891
+ };
9892
+ const saveWidgetState = async keys => {
9893
+ const savedStates = Object.create(null);
9894
+ for (const key of keys) {
9895
+ const editor = get$4(parseInt(key));
9687
9896
  const {
9688
- tokenizersToLoad,
9689
- embeddedResults
9690
- } = getTokensViewportEmbedded(languageId, lines, lineCache, linesWithEmbed);
9691
- // TODO support lineCache with embedded content
9692
- editor.invalidStartIndex = 0;
9693
- return {
9694
- tokens: visibleLines,
9695
- tokenizersToLoad,
9696
- embeddedResults
9697
- };
9897
+ widgets
9898
+ } = editor.newState;
9899
+ for (const widget of widgets) {
9900
+ const invoke = getWidgetInvoke(widget.id);
9901
+ const fullKey = `${key}:${widget.newState.uid}`;
9902
+ const name = getWidgetName(widget.id);
9903
+ const savedState = await invoke(`${name}.saveState`, widget.newState.uid);
9904
+ savedStates[fullKey] = savedState;
9905
+ }
9698
9906
  }
9699
- editor.invalidStartIndex = Math.max(invalidStartIndex, tokenizeEndIndex);
9700
- return {
9701
- tokens: visibleLines,
9702
- tokenizersToLoad,
9703
- embeddedResults
9704
- };
9907
+ return savedStates;
9705
9908
  };
9706
9909
 
9707
- const sentLines = Object.create(null);
9708
-
9709
- // TODO only send changed lines to renderer process instead of all lines in viewport
9710
- const getTokensViewport2 = async (editor, startLineIndex, endLineIndex, syncIncremental) => {
9711
- if (getEnabled$1()) {
9712
- if (syncIncremental) {
9713
- const {
9714
- invalidStartIndex,
9715
- lines,
9716
- languageId,
9717
- id
9718
- } = editor;
9719
- let hasLinesToSend = true;
9720
- let linesToSend = lines;
9721
- if (sentLines[id] === lines) {
9722
- hasLinesToSend = false;
9723
- linesToSend = [];
9724
- } else {
9725
- sentLines[id] = lines;
9726
- }
9727
- const slimEditor = {
9728
- languageId,
9729
- invalidStartIndex
9910
+ const restoreWidgetState = async (keys, savedStates) => {
9911
+ const newEditors = [];
9912
+ for (const key of keys) {
9913
+ const editorUid = parseInt(key);
9914
+ const editor = get$4(editorUid);
9915
+ const {
9916
+ widgets
9917
+ } = editor.newState;
9918
+ const newWidgets = [];
9919
+ for (const widget of widgets) {
9920
+ const invoke = getWidgetInvoke(widget.id);
9921
+ const fullKey = `${key}:${widget.newState.uid}`;
9922
+ const savedState = savedStates[fullKey] || {};
9923
+ const name = getWidgetName(widget.id);
9924
+ await invoke(`${name}.create`, widget.newState.uid, widget.newState.x, widget.newState.y, widget.newState.width, widget.newState.height, editorUid);
9925
+ await invoke(`${name}.loadContent`, widget.newState.uid, savedState);
9926
+ const diffResult = await invoke(`${name}.diff2`, widget.newState.uid);
9927
+ const commands = await invoke(`${name}.render2`, widget.newState.uid, diffResult);
9928
+ const newWidget = {
9929
+ ...widget,
9930
+ newState: {
9931
+ ...widget.newState,
9932
+ commands
9933
+ }
9730
9934
  };
9731
- return invoke$3('GetTokensViewport.getTokensViewport', slimEditor,
9732
- // @ts-ignore
9733
- startLineIndex, endLineIndex, hasLinesToSend, id, linesToSend);
9935
+ newWidgets.push(newWidget);
9734
9936
  }
9735
- // TODO only send needed lines of text
9736
- // @ts-ignore
9737
- return invoke$3('GetTokensViewport.getTokensViewport', editor, startLineIndex, endLineIndex, true, editor.id, editor.lines);
9937
+ newEditors.push({
9938
+ ...editor,
9939
+ newState: {
9940
+ ...editor.newState,
9941
+ widgets: newWidgets
9942
+ }
9943
+ });
9738
9944
  }
9739
- return getTokensViewport(editor, startLineIndex, endLineIndex);
9945
+ return newEditors;
9740
9946
  };
9741
9947
 
9742
- const loadTokenizers = async languageIds => {
9743
- for (const languageId of languageIds) {
9744
- // @ts-ignore
9745
- await loadTokenizer(languageId);
9948
+ let isReloading = false;
9949
+ const hotReload = async () => {
9950
+ if (isReloading) {
9951
+ return;
9746
9952
  }
9747
- };
9953
+ isReloading = true;
9748
9954
 
9749
- // const getTokensIncremental = (editor, min, max) => {
9750
- // const currentLength = editor.lineStateCache.length
9751
- // const tokens = []
9752
- // const lines = editor.lines
9753
- // let lineState = editor.tokenizer.initialLineState
9754
- // for (let i = currentLength; i < max; i++) {
9755
- // const line = lines[i]
9756
- // try {
9757
- // lineState = editor.tokenizer.tokenizeLine(line, lineState)
9758
- // if (!lineState || !lineState.tokens || !lineState.state) {
9759
- // throw new Error('invalid tokenization result')
9760
- // }
9761
- // } catch (error) {
9762
- // tokens.push([{ length: line.length, type: 0 }])
9763
- // console.error(error)
9764
- // // renderWithoutSyntaxHighlighting(state, firstRow, lastRow)
9765
- // continue
9766
- // }
9767
- // const newTokens = lineState.tokens
9768
- // tokens.push(newTokens)
9769
- // }
9770
- // return tokens
9771
- // }
9955
+ // TODO use getEditors
9956
+ const keys = getKeys$1();
9957
+ const savedStates = await saveWidgetState(keys);
9958
+ await relaunchWorkers();
9959
+ const newEditors = await restoreWidgetState(keys, savedStates);
9960
+ for (const editor of newEditors) {
9961
+ set$6(editor.newState.uid, editor.oldState, editor.newState);
9962
+ }
9772
9963
 
9773
- // const getLineInfosIncremental = (editor, tokens, minLineY, maxLineY) => {
9774
- // const result = []
9775
- // const lines = editor.lines
9776
- // const TokenMap = editor.tokenizer.TokenMap
9777
- // for (let i = minLineY; i < maxLineY; i++) {
9778
- // result.push(getLineInfo(lines[i], tokens[i], TokenMap))
9779
- // }
9780
- // return result
9781
- // }
9964
+ // TODO ask renderer worker to rerender all editors
9965
+ // @ts-ignore
9966
+ await invoke$9(`Editor.rerender`);
9967
+ isReloading = false;
9968
+ };
9782
9969
 
9783
- const getStartDefaults = (tokens, minOffset) => {
9784
- let start = 0;
9785
- let end = 0;
9786
- let startIndex = 0;
9787
- const tokensLength = tokens.length;
9788
- for (let i = 0; i < tokensLength; i += 2) {
9789
- const tokenLength = tokens[i + 1];
9790
- end += tokenLength;
9791
- start = end;
9792
- if (start >= minOffset) {
9793
- start -= tokenLength;
9794
- end -= tokenLength;
9795
- startIndex = i;
9796
- break;
9797
- }
9970
+ const sendMessagePortToExtensionHostWorker2 = async (port, initialCommand, rpcId) => {
9971
+ await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToExtensionHostWorker', port, initialCommand, rpcId);
9972
+ };
9973
+
9974
+ const createExtensionHostRpc = async () => {
9975
+ try {
9976
+ const {
9977
+ port1,
9978
+ port2
9979
+ } = getPortTuple();
9980
+ const initialCommand = 'HandleMessagePort.handleMessagePort2';
9981
+ // TODO use transfer rpc
9982
+ await sendMessagePortToExtensionHostWorker2(port2, initialCommand, EditorWorker);
9983
+ const rpc = await PlainMessagePortRpcParent.create({
9984
+ commandMap: {},
9985
+ messagePort: port1
9986
+ });
9987
+ return rpc;
9988
+ } catch (error) {
9989
+ throw new VError(error, `Failed to create extension host rpc`);
9798
9990
  }
9799
- return {
9800
- start,
9801
- end,
9802
- startIndex
9803
- };
9804
9991
  };
9805
- const getLineInfoEmbeddedFull = (embeddedResults, tokenResults, line, normalize, tabSize, width, deltaX, averageCharWidth, minOffset, maxOffset) => {
9806
- const lineInfo = [];
9807
- const embeddedResult = embeddedResults[tokenResults.embeddedResultIndex];
9808
- const embeddedTokens = embeddedResult.result.tokens;
9809
- const embeddedTokenMap = embeddedResult.TokenMap;
9810
- const tokensLength = embeddedTokens.length;
9811
- let {
9812
- startIndex,
9813
- start,
9814
- end
9815
- } = getStartDefaults(embeddedTokens, minOffset);
9816
- const difference = getDifference(start, averageCharWidth, deltaX);
9817
- for (let i = startIndex; i < tokensLength; i += 2) {
9818
- const tokenType = embeddedTokens[i];
9819
- const tokenLength = embeddedTokens[i + 1];
9820
- end += tokenLength;
9821
- const className = `Token ${embeddedTokenMap[tokenType] || 'Unknown'}`;
9822
- const text = line.slice(start, end);
9823
- const normalizedText = normalizeText(text, normalize, tabSize);
9824
- lineInfo.push(normalizedText, className);
9825
- start = end;
9826
- if (end >= maxOffset) {
9827
- break;
9828
- }
9992
+
9993
+ const initializeExtensionHost = async () => {
9994
+ const extensionHostRpc = await createExtensionHostRpc();
9995
+ set$1(extensionHostRpc);
9996
+ };
9997
+
9998
+ const sendMessagePortToSyntaxHighlightingWorker = async () => {
9999
+ try {
10000
+ const {
10001
+ port1,
10002
+ port2
10003
+ } = getPortTuple();
10004
+ await invokeAndTransfer(
10005
+ // @ts-ignore
10006
+ 'SendMessagePortToSyntaxHighlightingWorker.sendMessagePortToSyntaxHighlightingWorker', port1, 'HandleMessagePort.handleMessagePort2');
10007
+ return port2;
10008
+ } catch {
10009
+ const {
10010
+ port1,
10011
+ port2
10012
+ } = getPortTuple();
10013
+ await invokeAndTransfer(
10014
+ // @ts-ignore
10015
+ 'SendMessagePortToSyntaxHighlightingWorker.sendMessagePortToSyntaxHighlightingWorker', port1, 'HandleMessagePort.handleMessagePort');
10016
+ return port2;
9829
10017
  }
9830
- return {
9831
- lineInfo,
9832
- difference
9833
- };
9834
10018
  };
9835
- const getOffsets = (deltaX, width, averageCharWidth) => {
9836
- // TODO accurately measure char widths using offscreen canvas
9837
- // and use fast measurements for monospace ascii text
9838
- if (deltaX === 0) {
9839
- return {
9840
- minOffset: 0,
9841
- maxOffset: Math.ceil(width / averageCharWidth)
9842
- };
10019
+
10020
+ const createSyntaxHighlightingWorkerRpc = async () => {
10021
+ try {
10022
+ const port = await sendMessagePortToSyntaxHighlightingWorker();
10023
+ const rpc = await PlainMessagePortRpcParent.create({
10024
+ commandMap: {},
10025
+ messagePort: port
10026
+ });
10027
+ return rpc;
10028
+ } catch (error) {
10029
+ throw new VError(error, `Failed to create syntax highlighting worker rpc`);
9843
10030
  }
9844
- const minOffset = Math.ceil(deltaX / averageCharWidth);
9845
- const maxOffset = minOffset + Math.ceil(width / averageCharWidth);
9846
- return {
9847
- minOffset,
9848
- maxOffset
9849
- };
9850
- };
9851
- const getDifference = (start, averageCharWidth, deltaX) => {
9852
- const beforeWidth = start * averageCharWidth;
9853
- const difference = beforeWidth - deltaX;
9854
- return difference;
9855
10031
  };
9856
- const getLineInfoDefault = (line, tokenResults, embeddedResults, decorations, TokenMap, lineOffset, normalize, tabSize, width, deltaX, averageCharWidth, minOffset, maxOffset) => {
9857
- const lineInfo = [];
9858
- let decorationIndex = 0;
9859
- for (; decorationIndex < decorations.length; decorationIndex += 3) {
9860
- const decorationOffset = decorations[decorationIndex];
9861
- if (decorationOffset >= lineOffset) {
9862
- break;
9863
- }
9864
- }
9865
- const {
9866
- tokens
9867
- } = tokenResults;
9868
- let {
9869
- startIndex,
9870
- start,
9871
- end
9872
- } = getStartDefaults(tokens, minOffset);
9873
- const difference = getDifference(start, averageCharWidth, deltaX);
9874
- const tokensLength = tokens.length;
9875
- for (let i = startIndex; i < tokensLength; i += 2) {
9876
- const tokenType = tokens[i];
9877
- const tokenLength = tokens[i + 1];
9878
- const decorationOffset = decorations[decorationIndex];
9879
- let extraClassName = '';
9880
- if (decorationOffset !== undefined && decorationOffset - lineOffset === start) {
9881
- // @ts-ignore
9882
- decorations[++decorationIndex];
9883
- const decorationType = decorations[++decorationIndex];
9884
- // @ts-ignore
9885
- decorations[++decorationIndex];
9886
- // decorationIndex,
9887
- // decorationLength,
9888
- // decorationType,
9889
- // decorationModifiers,
9890
- // })
9891
- extraClassName = getDecorationClassName(decorationType);
9892
- }
9893
- end += tokenLength;
9894
- const text = line.slice(start, end);
9895
- const className = `Token ${extraClassName || TokenMap[tokenType] || 'Unknown'}`;
9896
- const normalizedText = normalizeText(text, normalize, tabSize);
9897
- lineInfo.push(normalizedText, className);
9898
- start = end;
9899
- if (end >= maxOffset) {
9900
- break;
9901
- }
10032
+
10033
+ const initializeSyntaxHighlighting = async (syntaxHighlightingEnabled, syncIncremental) => {
10034
+ if (syntaxHighlightingEnabled) {
10035
+ setEnabled$1(true);
10036
+ const syntaxRpc = await createSyntaxHighlightingWorkerRpc();
10037
+ set$5(syntaxRpc);
9902
10038
  }
9903
- return {
9904
- lineInfo,
9905
- difference
9906
- };
9907
- };
9908
- const getLineInfo = (line, tokenResults, embeddedResults, decorations, TokenMap, lineOffset, normalize, tabSize, width, deltaX, averageCharWidth) => {
9909
- const {
9910
- minOffset,
9911
- maxOffset
9912
- } = getOffsets(deltaX, width, averageCharWidth);
9913
- if (embeddedResults.length > 0 && tokenResults.embeddedResultIndex !== undefined) {
9914
- const embeddedResult = embeddedResults[tokenResults.embeddedResultIndex];
9915
- if (embeddedResult?.isFull) {
9916
- return getLineInfoEmbeddedFull(embeddedResults, tokenResults, line, normalize, tabSize, width, deltaX, averageCharWidth, minOffset, maxOffset);
9917
- }
10039
+ if (syncIncremental) {
10040
+ setEnabled(true);
9918
10041
  }
9919
- return getLineInfoDefault(line, tokenResults, embeddedResults, decorations, TokenMap, lineOffset, normalize, tabSize, width, deltaX, averageCharWidth, minOffset, maxOffset);
9920
10042
  };
9921
10043
 
9922
- // TODO need lots of tests for this
9923
- const getLineInfosViewport = (editor, tokens, embeddedResults, minLineY, maxLineY, minLineOffset, width, deltaX, averageCharWidth) => {
9924
- const result = [];
9925
- const differences = [];
9926
- const {
9927
- lines,
9928
- decorations,
9929
- languageId
9930
- } = editor;
9931
- const tokenMap = get$1(languageId);
9932
- let offset = minLineOffset;
9933
- const tabSize = 2;
9934
- for (let i = minLineY; i < maxLineY; i++) {
9935
- const line = lines[i];
9936
- const normalize = shouldNormalizeText(line);
9937
- const {
9938
- lineInfo,
9939
- difference
9940
- } = getLineInfo(line, tokens[i - minLineY], embeddedResults, decorations, tokenMap, offset, normalize, tabSize, width, deltaX, averageCharWidth);
9941
- result.push(lineInfo);
9942
- differences.push(difference);
9943
- offset += line.length + 1;
9944
- }
9945
- return {
9946
- result,
9947
- differences
9948
- };
10044
+ const intialize = async (syntaxHighlightingEnabled, syncIncremental) => {
10045
+ await Promise.all([initializeSyntaxHighlighting(syntaxHighlightingEnabled, syncIncremental), initializeExtensionHost()]);
9949
10046
  };
9950
- const getVisible = async (editor, syncIncremental) => {
9951
- // TODO should separate rendering from business logic somehow
9952
- // currently hard to test because need to mock editor height, top, left,
9953
- // invalidStartIndex, lineCache, etc. just for testing editorType
9954
- // editor.invalidStartIndex = changes[0].start.rowIndex
9955
- // @ts-ignore
9956
- const {
9957
- minLineY,
9958
- numberOfVisibleLines,
9959
- lines,
9960
- width,
9961
- deltaX,
9962
- charWidth
9963
- } = editor;
9964
- const maxLineY = Math.min(minLineY + numberOfVisibleLines, lines.length);
10047
+
10048
+ // TODO move cursor
10049
+ // TODO multiple cursors -> vscode removes multiple cursors
10050
+ // TODO with selection -> vscode moves whole selection
10051
+ const moveLineDown = editor => {
10052
+ // const rowIndex = editor.cursor.rowIndex
10053
+ // if (rowIndex === editor.lines.length - 1) {
10054
+ // return
10055
+ // }
10056
+ // const documentEdits = [
10057
+ // {
10058
+ // type: /* splice */ 2,
10059
+ // rowIndex: rowIndex,
10060
+ // count: 2,
10061
+ // newLines: [TextDocument.getLine(editor.textDocument, rowIndex + 1), TextDocument.getLine(editor.textDocument, rowIndex)],
10062
+ // },
10063
+ // ]
10064
+ // // @ts-ignore
10065
+ // const cursorEdits = Editor.moveCursors(editor, (editor, cursor) => {
10066
+ // return {
10067
+ // rowIndex: cursor.rowIndex + 1,
10068
+ // columnIndex: cursor.columnIndex,
10069
+ // }
10070
+ // })
9965
10071
  // @ts-ignore
9966
- const {
9967
- tokens,
9968
- tokenizersToLoad,
9969
- embeddedResults
9970
- } = await getTokensViewport2(editor, minLineY, maxLineY, syncIncremental);
9971
- const minLineOffset = offsetAtSync(editor, minLineY, 0);
9972
- const averageCharWidth = charWidth;
9973
- const {
9974
- result,
9975
- differences
9976
- } = getLineInfosViewport(editor, tokens, embeddedResults, minLineY, maxLineY, minLineOffset, width, deltaX, averageCharWidth);
9977
- if (tokenizersToLoad.length > 0) {
9978
- loadTokenizers(tokenizersToLoad);
9979
- }
9980
- return {
9981
- textInfos: result,
9982
- differences
9983
- };
10072
+ // Editor.scheduleDocumentAndCursors(editor, documentEdits, cursorEdits)
10073
+ return editor;
10074
+ };
10075
+
10076
+ // TODO handle multiple cursors
10077
+ const moveLineUp = editor => {
10078
+ // const rowIndex = editor.cursor.rowIndex
10079
+ // if (rowIndex === 0) {
10080
+ // return
10081
+ // }
10082
+ // const documentEdits = [
10083
+ // {
10084
+ // type: /* splice */ 2,
10085
+ // rowIndex: rowIndex - 1,
10086
+ // count: 2,
10087
+ // newLines: [TextDocument.getLine(editor.textDocument, rowIndex), TextDocument.getLine(editor.textDocument, rowIndex - 1)],
10088
+ // },
10089
+ // ]
10090
+ // // @ts-ignore
10091
+ // const cursorEdits = Editor.moveCursors(editor, (editor, cursor) => {
10092
+ // return {
10093
+ // // TODO handle bottom 0
10094
+ // rowIndex: cursor.rowIndex - 1,
10095
+ // columnIndex: cursor.columnIndex,
10096
+ // }
10097
+ // })
10098
+ // // @ts-ignore
10099
+ // Editor.scheduleDocumentAndCursors(editor, documentEdits, cursorEdits)
10100
+ return editor;
9984
10101
  };
9985
10102
 
9986
10103
  const getCursorsVirtualDom = cursors => {
@@ -10079,36 +10196,6 @@ const getEditorRowsVirtualDom = (textInfos, differences, lineNumbers = true, hig
10079
10196
  return dom;
10080
10197
  };
10081
10198
 
10082
- const getIncrementalEdits = async (oldState, newState) => {
10083
- if (!newState.undoStack) {
10084
- return undefined;
10085
- }
10086
- const lastChanges = newState.undoStack.at(-1);
10087
- if (lastChanges && lastChanges.length === 1) {
10088
- const lastChange = lastChanges[0];
10089
- if (lastChange.origin === EditorType) {
10090
- const {
10091
- rowIndex
10092
- } = lastChange.start;
10093
- const {
10094
- lines
10095
- } = newState;
10096
- const oldLine = oldState.lines[rowIndex];
10097
- const newLine = lines[rowIndex];
10098
- // @ts-ignore
10099
- const incrementalEdits = await invoke$3(
10100
- // @ts-ignore
10101
- 'TokenizeIncremental.tokenizeIncremental', newState.uid,
10102
- // @ts-ignore
10103
- newState.languageId, oldLine, newLine, rowIndex, newState.minLineY);
10104
- if (incrementalEdits && incrementalEdits.length === 1) {
10105
- return incrementalEdits;
10106
- }
10107
- }
10108
- }
10109
- return undefined;
10110
- };
10111
-
10112
10199
  const getSelectionsVirtualDom = selections => {
10113
10200
  const dom = [];
10114
10201
  for (let i = 0; i < selections.length; i += 4) {
@@ -10154,16 +10241,17 @@ const renderLines = {
10154
10241
  isEqual(oldState, newState) {
10155
10242
  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;
10156
10243
  },
10157
- async apply(oldState, newState) {
10158
- const incrementalEdits = await getIncrementalEdits(oldState, newState);
10159
- if (incrementalEdits) {
10244
+ apply(oldState, newState) {
10245
+ const {
10246
+ incrementalEdits
10247
+ } = newState;
10248
+ if (incrementalEdits !== emptyIncrementalEdits) {
10160
10249
  return [/* method */'setIncrementalEdits', /* incrementalEdits */incrementalEdits];
10161
10250
  }
10162
- const syncIncremental = getEnabled();
10163
10251
  const {
10164
10252
  textInfos,
10165
10253
  differences
10166
- } = await getVisible(newState, syncIncremental);
10254
+ } = newState;
10167
10255
  newState.differences = differences;
10168
10256
  const {
10169
10257
  highlightedLine,
@@ -10182,7 +10270,7 @@ const renderSelections = {
10182
10270
  const {
10183
10271
  cursorInfos,
10184
10272
  selectionInfos
10185
- } = getVisible$1(newState);
10273
+ } = getVisible(newState);
10186
10274
  const cursorsDom = getCursorsVirtualDom(cursorInfos);
10187
10275
  const selectionsDom = getSelectionsVirtualDom(selectionInfos);
10188
10276
  return [/* method */'setSelections', cursorsDom, selectionsDom];
@@ -10308,7 +10396,7 @@ const renderWidgets = {
10308
10396
  multiple: true
10309
10397
  };
10310
10398
  const render$6 = [renderLines, renderSelections, renderScrollBarX, renderScrollBarY, renderFocus$1, renderDecorations, renderGutterInfo, renderWidgets];
10311
- const renderEditor = async id => {
10399
+ const renderEditor = id => {
10312
10400
  const instance = get$4(id);
10313
10401
  if (!instance) {
10314
10402
  return [];
@@ -10321,7 +10409,7 @@ const renderEditor = async id => {
10321
10409
  set$6(id, newState, newState);
10322
10410
  for (const item of render$6) {
10323
10411
  if (!item.isEqual(oldState, newState)) {
10324
- const result = await item.apply(oldState, newState);
10412
+ const result = item.apply(oldState, newState);
10325
10413
  // @ts-ignore
10326
10414
  if (item.multiple) {
10327
10415
  commands.push(...result);
@@ -10453,16 +10541,24 @@ const effects = [editorDiagnosticEffect];
10453
10541
  const wrapCommand = fn => async (editorUid, ...args) => {
10454
10542
  const oldInstance = get$4(editorUid);
10455
10543
  const newEditor = await fn(oldInstance.newState, ...args);
10544
+ if (oldInstance.newState === newEditor) {
10545
+ return newEditor;
10546
+ }
10456
10547
  for (const effect of effects) {
10457
10548
  if (effect.isActive(oldInstance.newState, newEditor)) {
10458
10549
  effect.apply(newEditor);
10459
10550
  }
10460
10551
  }
10552
+ // TODO if editor did not change, no need to update furthur
10553
+
10554
+ // TODO combine neweditor with latest editor?
10555
+
10461
10556
  set$6(editorUid, oldInstance.newState, newEditor);
10462
- // TODO if possible, rendering should be sync
10463
- const commands = await renderEditor(editorUid);
10464
- newEditor.commands = commands;
10465
- return newEditor;
10557
+ const commands = renderEditor(editorUid);
10558
+ return {
10559
+ ...newEditor,
10560
+ commands
10561
+ };
10466
10562
  };
10467
10563
  const wrapCommands = commands => {
10468
10564
  for (const [key, value] of Object.entries(commands)) {
@@ -10497,6 +10593,7 @@ const commandMap = {
10497
10593
  'Editor.compositionEnd': compositionEnd,
10498
10594
  'Editor.compositionStart': compositionStart,
10499
10595
  'Editor.compositionUpdate': compositionUpdate,
10596
+ 'Editor.handleClickAtPosition': handleClickAtPosition,
10500
10597
  'Editor.applyDocumentEdits': applyDocumentEdits,
10501
10598
  'Editor.contextMenu': handleContextMenu,
10502
10599
  'Editor.copy': copy,