@lvce-editor/file-search-worker 5.9.0 → 5.10.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.
@@ -1003,7 +1003,7 @@ const create = (uid, uri, listItemHeight, x, y, width, height, platform, args, w
1003
1003
  width: 600,
1004
1004
  ...create$1({
1005
1005
  itemHeight: listItemHeight,
1006
- headerHeight: 30,
1006
+ headerHeight: 38,
1007
1007
  minimumSliderSize: minimumSliderSize
1008
1008
  }),
1009
1009
  inputSource: User,
@@ -1084,19 +1084,19 @@ const focusPick$1 = async pick => {
1084
1084
  };
1085
1085
 
1086
1086
  const ColorTheme$1 = 0;
1087
- const Commands$1 = 2;
1088
- const Custom = 3;
1089
- const EveryThing$1 = 4;
1090
- const File$2 = 5;
1091
- const GoToLine$2 = 6;
1092
- const Help$2 = 7;
1093
- const Recent$1 = 8;
1094
- const Symbol$2 = 9;
1095
- const View$3 = 10;
1096
- const WorkspaceSymbol$2 = 11;
1087
+ const Commands$1 = 1;
1088
+ const Custom = 2;
1089
+ const File$2 = 3;
1090
+ const GoToLine$2 = 4;
1091
+ const Help$2 = 5;
1092
+ const Recent$1 = 6;
1093
+ const Symbol$2 = 7;
1094
+ const View$3 = 8;
1095
+ const WorkspaceSymbol$2 = 9;
1096
+ const EveryThing$1 = 100;
1097
1097
 
1098
1098
  const noop$2 = async () => {};
1099
- const getFn$2 = id => {
1099
+ const getFn$3 = id => {
1100
1100
  switch (id) {
1101
1101
  case ColorTheme$1:
1102
1102
  return focusPick$1;
@@ -1105,7 +1105,7 @@ const getFn$2 = id => {
1105
1105
  }
1106
1106
  };
1107
1107
  const focusPick = (id, pick) => {
1108
- const fn = getFn$2(id);
1108
+ const fn = getFn$3(id);
1109
1109
  return fn(pick);
1110
1110
  };
1111
1111
 
@@ -1695,7 +1695,7 @@ const getFilterValueEverything = value => {
1695
1695
  const prefixLength = prefix.length;
1696
1696
  return value.slice(prefixLength).trim();
1697
1697
  };
1698
- const getFn$1 = id => {
1698
+ const getFn$2 = id => {
1699
1699
  switch (id) {
1700
1700
  case EveryThing$1:
1701
1701
  return getFilterValueEverything;
@@ -1704,1307 +1704,1279 @@ const getFn$1 = id => {
1704
1704
  }
1705
1705
  };
1706
1706
  const getFilterValue = (id, value) => {
1707
- const fn = getFn$1(id);
1707
+ const fn = getFn$2(id);
1708
1708
  const filterValue = fn(value);
1709
1709
  return filterValue;
1710
1710
  };
1711
1711
 
1712
- const select = Object.create(null);
1713
- const getPick$1 = Object.create(null);
1714
- const registerSelect = modules => {
1715
- Object.assign(select, modules);
1716
- };
1717
- const registerGetPick = modules => {
1718
- Object.assign(getPick$1, modules);
1712
+ const getColorThemeNames = async () => {
1713
+ return invoke$1(/* Ajax.getJson */'ColorTheme.getColorThemeNames');
1719
1714
  };
1720
- const getPicks$d = id => {
1721
- const fn = getPick$1[id];
1722
- return fn;
1715
+
1716
+ const toProtoVisibleItem$2 = name => {
1717
+ const pick = {
1718
+ label: name,
1719
+ description: '',
1720
+ fileIcon: '',
1721
+ icon: '',
1722
+ matches: [],
1723
+ direntType: 0,
1724
+ uri: ''
1725
+ };
1726
+ return pick;
1723
1727
  };
1724
- const getSelect = id => {
1725
- const fn = select[id];
1726
- return fn;
1728
+ const getPicks$c = async searchValue => {
1729
+ const colorThemeNames = await getColorThemeNames();
1730
+ const picks = colorThemeNames.map(toProtoVisibleItem$2);
1731
+ return picks;
1727
1732
  };
1728
1733
 
1729
- const getPicks$c = (id, searchValue) => {
1730
- const fn = getPicks$d(id);
1731
- return fn(searchValue);
1734
+ const handleError = async (error, notify = true, prefix = '') => {
1735
+ console.error(error);
1736
+ };
1737
+ const showErrorDialog = async error => {
1738
+ const code = error.code;
1739
+ const message = error.message;
1740
+ const stack = error.stack;
1741
+ const name = error.name;
1742
+ const errorInfo = {
1743
+ code,
1744
+ message,
1745
+ stack,
1746
+ name
1747
+ };
1748
+ await invoke$1('ErrorHandling.showErrorDialog', errorInfo);
1749
+ };
1750
+ const warn = (...args) => {
1751
+ console.warn(...args);
1732
1752
  };
1733
1753
 
1734
- const getQuickPickSubProviderId = prefix => {
1735
- switch (prefix) {
1736
- case Command:
1737
- return Commands$1;
1738
- case Symbol$1:
1739
- return Symbol$2;
1740
- case WorkspaceSymbol$1:
1741
- return WorkspaceSymbol$2;
1742
- case GoToLine$1:
1743
- return GoToLine$2;
1744
- case View$2:
1745
- return View$3;
1746
- case Help$1:
1747
- return Help$2;
1748
- default:
1749
- return File$2;
1750
- }
1754
+ const state$2 = {
1755
+ menuEntries: []
1756
+ };
1757
+ const getAll = () => {
1758
+ return state$2.menuEntries;
1759
+ };
1760
+ const add = menuEntries => {
1761
+ state$2.menuEntries = [...state$2.menuEntries, ...menuEntries];
1751
1762
  };
1752
1763
 
1753
- // TODO when user types letters -> no need to query provider again -> just filter existing results
1754
- const setValue = async (state, newValue) => {
1755
- const {
1756
- providerId,
1757
- value,
1758
- minLineY,
1759
- maxLineY,
1760
- fileIconCache
1761
- } = state;
1762
- if (value === newValue) {
1763
- return state;
1764
+ // TODO combine Ajax with cache (specify strategy: cacheFirst, networkFirst)
1765
+ const getBuiltinPicks = async () => {
1766
+ const builtinPicks = getAll();
1767
+ return builtinPicks;
1768
+ };
1769
+ const prefixIdWithExt = item => {
1770
+ if (!item.label) {
1771
+ warn('[QuickPick] item has missing label', item);
1772
+ }
1773
+ if (!item.id) {
1774
+ warn('[QuickPick] item has missing id', item);
1764
1775
  }
1765
- const prefix = getQuickPickPrefix(newValue);
1766
- const subId = getQuickPickSubProviderId(prefix);
1767
- const newPicks = await getPicks$c(subId, newValue);
1768
- const filterValue = getFilterValue(providerId, newValue);
1769
- const items = filterQuickPickItems(newPicks, filterValue);
1770
- const focusedIndex = items.length === 0 ? -1 : 0;
1771
- const sliced = items.slice(minLineY, maxLineY);
1772
- const {
1773
- newFileIconCache,
1774
- icons
1775
- } = await getQuickPickFileIcons(sliced, fileIconCache);
1776
1776
  return {
1777
- ...state,
1778
- picks: newPicks,
1779
- items,
1780
- focusedIndex,
1781
- inputSource: Script,
1782
- value: newValue,
1783
- icons,
1784
- fileIconCache: newFileIconCache
1777
+ ...item,
1778
+ id: `ext.${item.id}`,
1779
+ label: item.label || item.id
1785
1780
  };
1786
1781
  };
1787
-
1788
- // TODO when user types letters -> no need to query provider again -> just filter existing results
1789
- const handleInput = async (state, newValue, cursorOffset, inputSource = Script) => {
1790
- if (state.value === newValue) {
1791
- return state;
1782
+ const getExtensionPicks = async () => {
1783
+ try {
1784
+ // TODO don't call this every time
1785
+ const extensionPicks = await invoke$1('ExtensionHost.getCommands');
1786
+ if (!extensionPicks) {
1787
+ return [];
1788
+ }
1789
+ const mappedPicks = extensionPicks.map(prefixIdWithExt);
1790
+ return mappedPicks;
1791
+ } catch (error) {
1792
+ console.error(`Failed to get extension picks: ${error}`);
1793
+ return [];
1792
1794
  }
1793
- const newState = await setValue(state, newValue);
1794
- return {
1795
- ...newState,
1796
- cursorOffset,
1797
- inputSource
1795
+ };
1796
+ const toProtoVisibleItem$1 = item => {
1797
+ const pick = {
1798
+ label: item.label,
1799
+ description: '',
1800
+ fileIcon: '',
1801
+ icon: '',
1802
+ matches: [],
1803
+ direntType: 0,
1804
+ uri: ''
1798
1805
  };
1806
+ // @ts-ignore
1807
+ pick.id = item.id;
1808
+ return pick;
1799
1809
  };
1800
-
1801
- const handleBeforeInput = (state, inputType, data, selectionStart, selectionEnd) => {
1802
- string(inputType);
1803
- number(selectionStart);
1804
- number(selectionEnd);
1805
- const {
1806
- value
1807
- } = state;
1808
- const {
1809
- newValue,
1810
- cursorOffset
1811
- } = getNewValue(value, inputType, data, selectionStart, selectionEnd);
1812
- return handleInput(state, newValue, cursorOffset, User);
1810
+ const getPicks$b = async () => {
1811
+ // TODO get picks in parallel
1812
+ const builtinPicks = await getBuiltinPicks();
1813
+ const extensionPicks = await getExtensionPicks();
1814
+ const allPicks = [...builtinPicks, ...extensionPicks];
1815
+ const converted = allPicks.map(toProtoVisibleItem$1);
1816
+ return converted;
1813
1817
  };
1814
1818
 
1815
- const handleBlur = async state => {
1816
- // TODO fix virtual dom diffing so that input isn't destroyed and loses focus when rerendering
1817
- // await CloseWidget.closeWidget(state.uid)
1818
- return state;
1819
+ const state$1 = {
1820
+ args: []
1819
1821
  };
1820
1822
 
1821
- const getPick = (items, index) => {
1822
- array(items);
1823
- number(index);
1824
- // if (index < state.recentPicks.length) {
1825
- // return state.recentPicks[index]
1826
- // }
1827
- // index -= state.recentPicks.length
1828
- if (index < items.length) {
1829
- return items[index];
1830
- }
1831
- console.warn('no pick matching index', index);
1832
- return undefined;
1823
+ const getPicks$a = async searchValue => {
1824
+ const items = state$1.args[1] || [];
1825
+ return items;
1833
1826
  };
1834
1827
 
1835
- const Hide = 'hide';
1836
- const KeepOpen = '';
1837
-
1838
- const selectIndex = async (state, index, button = /* left */0) => {
1839
- const {
1840
- minLineY,
1841
- items,
1842
- value
1843
- } = state;
1844
- const actualIndex = index + minLineY;
1845
- const pick = getPick(items, actualIndex);
1846
- if (!pick) {
1847
- return state;
1848
- }
1849
- const prefix = getQuickPickPrefix(value);
1850
- const subId = getQuickPickSubProviderId(prefix);
1851
- const fn = getSelect(subId);
1852
- const selectPickResult = await fn(pick);
1853
- object(selectPickResult);
1854
- string(selectPickResult.command);
1855
- const {
1856
- command
1857
- } = selectPickResult;
1858
- switch (command) {
1859
- case Hide:
1860
- await closeWidget(state.uid);
1861
- return state;
1862
- default:
1863
- return state;
1864
- }
1828
+ const emptyMatches = [];
1865
1829
 
1866
- // TODO recent picks should be per provider
1867
- // if (!state.recentPickIds.has(pick.id)) {
1868
- // state.recentPicks.unshift(pick)
1869
- // state.recentPickIds.add(pick.id)
1870
- // }
1871
- // if (state.recentPicks.length > RECENT_PICKS_MAX_SIZE) {
1872
- // const last = state.recentPicks.pop()
1873
- // state.recentPickIds.delete(last.id)
1874
- // }
1830
+ const getWorkspacePath = async () => {
1831
+ return invoke$1('Workspace.getPath');
1875
1832
  };
1876
1833
 
1877
- const handleClickAt = (state, x, y) => {
1878
- const {
1879
- top,
1880
- headerHeight,
1881
- itemHeight
1882
- } = state;
1883
- const relativeY = y - top - headerHeight;
1884
- const index = Math.floor(relativeY / itemHeight);
1885
- return selectIndex(state, index);
1834
+ const RE_PROTOCOL = /^([a-z-]+):\/\//;
1835
+ const getProtocol = uri => {
1836
+ const protocolMatch = uri.match(RE_PROTOCOL);
1837
+ if (protocolMatch) {
1838
+ return protocolMatch[1];
1839
+ }
1840
+ return '';
1886
1841
  };
1887
1842
 
1888
- const setFocus = async focusKey => {
1889
- await invoke$1('Focus.setFocus', focusKey);
1843
+ const state = Object.create(null);
1844
+ const register = modules => {
1845
+ Object.assign(state, modules);
1846
+ };
1847
+ const getFn$1 = protocol => {
1848
+ return state[protocol];
1890
1849
  };
1891
1850
 
1892
- const handleFocus = async state => {
1893
- // TODO fix virtual dom diffing so that input isn't destroyed and loses focus when rerendering
1894
- await setFocus(FocusQuickPickInput);
1895
- // await CloseWidget.closeWidget(state.uid)
1896
- return state;
1851
+ const searchFile$5 = async (path, value, prepare, assetDir) => {
1852
+ const protocol = getProtocol(path);
1853
+ // TODO call different providers depending on protocol
1854
+ const fn = getFn$1(protocol);
1855
+ const result = await fn(path, value, prepare, assetDir);
1856
+ return result;
1897
1857
  };
1898
1858
 
1899
- const getDefaultValue = id => {
1900
- switch (id) {
1901
- case EveryThing$1:
1902
- return Command;
1903
- default:
1904
- return '';
1905
- }
1859
+ // TODO this should be in FileSystem module
1860
+ const pathBaseName = path => {
1861
+ return path.slice(path.lastIndexOf('/') + 1);
1906
1862
  };
1907
1863
 
1908
- const Commands = 'quickPick://commands';
1909
- const EveryThing = 'quickPick://everything';
1910
- const Recent = 'quickPick://recent';
1911
- const ColorTheme = 'quickPick://color-theme';
1912
- const Symbol = 'quickPick://symbol';
1913
- const View$1 = 'quickPick://view';
1914
- const Help = 'quickPick://help';
1915
- const WorkspaceSymbol = 'quickPick://workspace-symbol';
1916
- const GoToLine = 'quickPick://go-to-line';
1917
-
1918
- const getQuickPickProviderId = prefix => {
1919
- switch (prefix) {
1920
- case Commands:
1921
- case Symbol:
1922
- case WorkspaceSymbol:
1923
- case EveryThing:
1924
- case GoToLine:
1925
- case View$1:
1926
- case Help:
1927
- return EveryThing$1;
1928
- case ColorTheme:
1929
- return ColorTheme$1;
1930
- case Recent:
1931
- return Recent$1;
1932
- default:
1933
- return File$2;
1864
+ // TODO this should be in FileSystem module
1865
+ const pathDirName = path => {
1866
+ const pathSeparator = '/';
1867
+ const index = path.lastIndexOf(pathSeparator);
1868
+ if (index === -1) {
1869
+ return '';
1934
1870
  }
1871
+ return path.slice(0, index);
1935
1872
  };
1936
1873
 
1937
- const state$3 = {
1938
- args: []
1874
+ const searchFile$4 = async (path, value) => {
1875
+ const prepare = true;
1876
+ const files = await searchFile$5(/* path */path, /* searchTerm */value, prepare, '');
1877
+ return files;
1939
1878
  };
1940
-
1941
- const noop = args => {};
1942
- const setArgsCustom = args => {
1943
- state$3.args = args;
1879
+ const convertToPick = uri => {
1880
+ const baseName = pathBaseName(uri);
1881
+ const dirName = pathDirName(uri);
1882
+ return {
1883
+ description: dirName,
1884
+ direntType: File$1,
1885
+ fileIcon: '',
1886
+ icon: '',
1887
+ label: baseName,
1888
+ matches: emptyMatches,
1889
+ uri
1890
+ };
1944
1891
  };
1945
- const getFn = id => {
1946
- switch (id) {
1947
- case Custom:
1948
- return setArgsCustom;
1949
- default:
1950
- return noop;
1892
+
1893
+ // TODO handle files differently
1894
+ // e.g. when there are many files, don't need
1895
+ // to compute the fileIcon for all files
1896
+
1897
+ const getPicks$9 = async searchValue => {
1898
+ // TODO cache workspace path
1899
+ const workspace = await getWorkspacePath();
1900
+ if (!workspace) {
1901
+ return [];
1951
1902
  }
1903
+ const files = await searchFile$4(workspace, searchValue);
1904
+ const picks = files.map(convertToPick);
1905
+ return picks;
1952
1906
  };
1953
- const setArgs = (id, args) => {
1954
- const fn = getFn(id);
1955
- return fn(args);
1907
+
1908
+ const getPicks$8 = async () => {
1909
+ const picks = [{
1910
+ label: '1',
1911
+ description: '',
1912
+ icon: '',
1913
+ fileIcon: '',
1914
+ matches: [],
1915
+ direntType: None$2,
1916
+ uri: ''
1917
+ }, {
1918
+ label: '2',
1919
+ description: '',
1920
+ icon: '',
1921
+ fileIcon: '',
1922
+ matches: [],
1923
+ direntType: None$2,
1924
+ uri: ''
1925
+ }, {
1926
+ label: '3',
1927
+ description: '',
1928
+ icon: '',
1929
+ fileIcon: '',
1930
+ matches: [],
1931
+ direntType: None$2,
1932
+ uri: ''
1933
+ }, {
1934
+ label: '4',
1935
+ description: '',
1936
+ icon: '',
1937
+ fileIcon: '',
1938
+ matches: [],
1939
+ direntType: None$2,
1940
+ uri: ''
1941
+ }, {
1942
+ label: '5',
1943
+ description: '',
1944
+ icon: '',
1945
+ fileIcon: '',
1946
+ matches: [],
1947
+ direntType: None$2,
1948
+ uri: ''
1949
+ }, {
1950
+ label: '6',
1951
+ description: '',
1952
+ icon: '',
1953
+ fileIcon: '',
1954
+ matches: [],
1955
+ direntType: None$2,
1956
+ uri: ''
1957
+ }];
1958
+ return picks;
1956
1959
  };
1957
1960
 
1958
- const loadContent = async state => {
1959
- const {
1960
- uri,
1961
- args,
1962
- fileIconCache
1963
- } = state;
1964
- const id = getQuickPickProviderId(uri);
1965
- const value = getDefaultValue(id);
1966
- const prefix = getQuickPickPrefix(value);
1967
- const subId = getQuickPickSubProviderId(prefix);
1968
- setArgs(subId, args);
1969
- const newPicks = await getPicks$c(subId, value);
1970
- array(newPicks);
1971
- const filterValue = getFilterValue(id, value);
1972
- const items = filterQuickPickItems(newPicks, filterValue);
1973
- const minLineY = 0;
1974
- const maxLineY = Math.min(minLineY + state.maxVisibleItems, newPicks.length);
1975
- const sliced = newPicks.slice(minLineY, maxLineY);
1976
- const {
1977
- newFileIconCache,
1978
- icons
1979
- } = await getQuickPickFileIcons(sliced, fileIconCache);
1980
- return {
1981
- ...state,
1982
- picks: newPicks,
1983
- items,
1984
- focusedIndex: 0,
1985
- state: Finished,
1986
- minLineY,
1987
- maxLineY,
1988
- value,
1989
- cursorOffset: value.length,
1990
- inputSource: Script,
1991
- focused: true,
1992
- fileIconCache: newFileIconCache,
1993
- icons,
1994
- providerId: id
1961
+ const DotDotDot = '...';
1962
+ const Colon = ':';
1963
+ const Percent = '%';
1964
+ const AngleBracket = '>';
1965
+ const View$1 = 'view';
1966
+
1967
+ const emptyObject = {};
1968
+ const RE_PLACEHOLDER = /\{(PH\d+)\}/g;
1969
+ const i18nString = (key, placeholders = emptyObject) => {
1970
+ if (placeholders === emptyObject) {
1971
+ return key;
1972
+ }
1973
+ const replacer = (match, rest) => {
1974
+ return placeholders[rest];
1995
1975
  };
1976
+ return key.replaceAll(RE_PLACEHOLDER, replacer);
1996
1977
  };
1997
1978
 
1998
- const state$2 = {
1999
- menuEntries: []
1979
+ const GoToFile = 'Go to file';
1980
+ const GoToLineColumn = 'Go to Line / Column';
1981
+ const GoToSymbolInEditor = 'Go to Symbol in Editor';
1982
+ const NoResults = 'No Results';
1983
+ const OpenView = 'Open View';
1984
+ const QuickOpen = 'Quick open';
1985
+ const SearchForText = 'Search for text';
1986
+ const ShowAndRunCommands = 'Show And Run Commands';
1987
+ const TypeNameOfCommandToRun = 'Type the name of a command to run.';
1988
+
1989
+ const typeNameofCommandToRun = () => {
1990
+ return i18nString(TypeNameOfCommandToRun);
2000
1991
  };
2001
- const getAll = () => {
2002
- return state$2.menuEntries;
1992
+ const showAndRunCommands = () => {
1993
+ return i18nString(ShowAndRunCommands);
2003
1994
  };
2004
- const add = menuEntries => {
2005
- state$2.menuEntries = [...state$2.menuEntries, ...menuEntries];
1995
+ const goToFile = () => {
1996
+ return i18nString(GoToFile);
2006
1997
  };
2007
-
2008
- const getVisible$1 = (items, minLineY, maxLineY, icons) => {
2009
- const range = items.slice(minLineY, maxLineY);
2010
- const protoVisibleItems = range.map((item, index) => {
2011
- return {
2012
- ...item,
2013
- fileIcon: icons[index]
2014
- };
2015
- });
2016
- return protoVisibleItems;
1998
+ const noResults = () => {
1999
+ return i18nString(NoResults);
2000
+ };
2001
+ const quickOpen = () => {
2002
+ return i18nString(QuickOpen);
2003
+ };
2004
+ const goToLineColumn = () => {
2005
+ return i18nString(GoToLineColumn);
2006
+ };
2007
+ const goToSymbolInEditor = () => {
2008
+ return i18nString(GoToSymbolInEditor);
2009
+ };
2010
+ const searchForText = () => {
2011
+ return i18nString(SearchForText);
2012
+ };
2013
+ const openView = () => {
2014
+ return i18nString(OpenView);
2017
2015
  };
2018
2016
 
2019
- const emptyHighlightSections = [];
2020
-
2021
- const getHighlightSections = (highlights, label) => {
2022
- if (highlights.length === 0) {
2023
- return emptyHighlightSections;
2024
- }
2025
- const sections = [];
2026
- let position = 0;
2027
- for (let i = 0; i < highlights.length; i += 2) {
2028
- const highlightStart = highlights[i];
2029
- const highlightEnd = highlights[i + 1];
2030
- if (position < highlightStart) {
2031
- const beforeText = label.slice(position, highlightStart);
2032
- sections.push({
2033
- highlighted: false,
2034
- text: beforeText
2035
- });
2036
- }
2037
- const highlightText = label.slice(highlightStart, highlightEnd);
2038
- sections.push({
2039
- highlighted: true,
2040
- text: highlightText
2041
- });
2042
- position = highlightEnd;
2043
- }
2044
- if (position < label.length) {
2045
- const afterText = label.slice(position);
2046
- sections.push({
2047
- highlighted: false,
2048
- text: afterText
2049
- });
2050
- }
2051
- return sections;
2017
+ const getPicks$7 = async () => {
2018
+ return [{
2019
+ description: goToFile(),
2020
+ direntType: None$2,
2021
+ fileIcon: '',
2022
+ icon: '',
2023
+ label: DotDotDot,
2024
+ matches: [],
2025
+ uri: ''
2026
+ }, {
2027
+ description: goToLineColumn(),
2028
+ direntType: None$2,
2029
+ fileIcon: '',
2030
+ icon: '',
2031
+ label: ':',
2032
+ matches: [],
2033
+ uri: ''
2034
+ }, {
2035
+ description: goToSymbolInEditor(),
2036
+ direntType: None$2,
2037
+ fileIcon: '',
2038
+ icon: '',
2039
+ label: Colon,
2040
+ matches: [],
2041
+ uri: ''
2042
+ }, {
2043
+ description: searchForText(),
2044
+ direntType: None$2,
2045
+ fileIcon: '',
2046
+ icon: '',
2047
+ label: Percent,
2048
+ matches: [],
2049
+ uri: ''
2050
+ }, {
2051
+ description: showAndRunCommands(),
2052
+ direntType: None$2,
2053
+ fileIcon: '',
2054
+ icon: '',
2055
+ label: AngleBracket,
2056
+ matches: [],
2057
+ uri: ''
2058
+ }, {
2059
+ description: openView(),
2060
+ direntType: None$2,
2061
+ fileIcon: '',
2062
+ icon: '',
2063
+ label: View$1,
2064
+ matches: [],
2065
+ uri: ''
2066
+ }];
2052
2067
  };
2053
2068
 
2054
- const getVisible = (setSize, protoVisibleItems, minLineY, focusedIndex) => {
2055
- const visibleItems = protoVisibleItems.map((visibleItem, i) => {
2056
- const highlights = visibleItem.matches.slice(1);
2057
- const sections = getHighlightSections(highlights, visibleItem.label);
2058
- return {
2059
- ...visibleItem,
2060
- posInSet: minLineY + i + 1,
2061
- setSize,
2062
- isActive: i === focusedIndex,
2063
- highlights: sections
2064
- };
2065
- });
2066
- return visibleItems;
2069
+ const getRecentlyOpened = () => {
2070
+ return invoke$1(/* RecentlyOpened.getRecentlyOpened */'RecentlyOpened.getRecentlyOpened');
2067
2071
  };
2068
2072
 
2069
- const createQuickPickViewModel = (oldState, newState) => {
2070
- const protoVisibleItems = getVisible$1(newState.items, newState.minLineY, newState.maxLineY, newState.icons);
2071
- const visibleItems = getVisible(newState.items.length, protoVisibleItems, newState.minLineY, newState.focusedIndex);
2072
- const oldFocusedIndex = oldState.focusedIndex - oldState.minLineY;
2073
- const newFocusedIndex = newState.focusedIndex - newState.minLineY;
2074
- const maxLineY = Math.min(newState.maxLineY, newState.items.length);
2075
- const itemCount = maxLineY - newState.minLineY;
2076
- const height = itemCount * newState.itemHeight;
2073
+ const toProtoVisibleItem = uri => {
2077
2074
  return {
2078
- visibleItems,
2079
- value: newState.value,
2080
- cursorOffset: newState.cursorOffset,
2081
- focused: newState.focused,
2082
- height,
2083
- oldFocusedIndex,
2084
- newFocusedIndex,
2085
- uid: newState.uid
2075
+ label: uri,
2076
+ description: '',
2077
+ fileIcon: '',
2078
+ icon: '',
2079
+ matches: [],
2080
+ direntType: Directory,
2081
+ uri: uri
2086
2082
  };
2087
2083
  };
2088
-
2089
- const SetCursorOffset = 'setCursorOffset';
2090
- const SetFocusedIndex = 'setFocusedIndex';
2091
- const SetItemsHeight = 'setItemsHeight';
2092
- const SetValue = 'setValue';
2093
-
2094
- const renderCursorOffset = newState => {
2095
- return ['Viewlet.send', newState.uid, /* method */SetCursorOffset, /* cursorOffset */newState.cursorOffset];
2084
+ const getPicks$6 = async () => {
2085
+ const recentlyOpened = await getRecentlyOpened();
2086
+ const picks = recentlyOpened.map(toProtoVisibleItem);
2087
+ return picks;
2096
2088
  };
2097
2089
 
2098
- const QuickPickInput = 'QuickPickInput';
2099
-
2100
- const renderFocus = newState => {
2101
- return ['Viewlet.focusElementByName', QuickPickInput];
2090
+ const getPicks$5 = async () => {
2091
+ const picks = [];
2092
+ return picks;
2102
2093
  };
2103
2094
 
2104
- const renderFocusedIndex = newState => {
2105
- return ['Viewlet.send', newState.uid, /* method */SetFocusedIndex, /* oldFocusedIndex */newState.oldFocusedIndex, /* newFocusedIndex */newState.newFocusedIndex];
2095
+ const getPicks$4 = async () => {
2096
+ return [];
2106
2097
  };
2107
2098
 
2108
- const renderHeight = newState => {
2109
- if (newState.height === 0) {
2110
- return ['Viewlet.send', newState.uid, /* method */SetItemsHeight, /* height */20];
2111
- }
2112
- return ['Viewlet.send', newState.uid, /* method */SetItemsHeight, /* height */newState.height];
2099
+ const getPicks$3 = async () => {
2100
+ const picks = [];
2101
+ return picks;
2113
2102
  };
2114
2103
 
2115
- const ComboBox = 'combobox';
2116
- const ListBox = 'listbox';
2117
- const None = 'none';
2118
- const Option = 'option';
2119
-
2120
- const FileIcon = 'FileIcon';
2121
- const InputBox = 'InputBox';
2122
- const Label = 'Label';
2123
- const MaskIcon = 'MaskIcon';
2124
- const QuickPick$1 = 'QuickPick';
2125
- const QuickPickHeader = 'QuickPickHeader';
2126
- const QuickPickHighlight = 'QuickPickHighlight';
2127
- const QuickPickItem = 'QuickPickItem';
2128
- const QuickPickItemActive$1 = 'QuickPickItemActive';
2129
- const QuickPickItemDescription = 'QuickPickItemDescription';
2130
- const QuickPickItemLabel = 'QuickPickItemLabel';
2131
- const QuickPickItems$1 = 'QuickPickItems';
2132
- const QuickPickMaskIcon = 'QuickPickMaskIcon';
2133
- const QuickPickStatus = 'QuickPickStatus';
2134
- const Viewlet = 'Viewlet';
2135
-
2136
- const HandleBeforeInput = 'handleBeforeInput';
2137
- const HandleBlur = 'handleBlur';
2138
- const HandleFocus = 'handleFocus';
2139
- const HandleInput = 'handleInput';
2140
- const HandlePointerDown = 'handlePointerDown';
2141
- const HandleWheel = 'handleWheel';
2142
-
2143
- const QuickPick = 'QuickPick';
2144
- const QuickPickItems = 'QuickPickItems';
2145
- const QuickPickItemActive = 'QuickPickItemActive';
2104
+ const Hide = 'hide';
2105
+ const KeepOpen = '';
2146
2106
 
2147
- const emptyObject = {};
2148
- const RE_PLACEHOLDER = /\{(PH\d+)\}/g;
2149
- const i18nString = (key, placeholders = emptyObject) => {
2150
- if (placeholders === emptyObject) {
2151
- return key;
2152
- }
2153
- const replacer = (match, rest) => {
2154
- return placeholders[rest];
2107
+ const selectPick$9 = async pick => {
2108
+ const id = pick.label;
2109
+ await setColorTheme(/* colorThemeId */id);
2110
+ return {
2111
+ command: Hide
2155
2112
  };
2156
- return key.replaceAll(RE_PLACEHOLDER, replacer);
2157
2113
  };
2158
2114
 
2159
- const GoToFile = 'Go to file';
2160
- const GoToLineColumn = 'Go to Line / Column';
2161
- const GoToSymbolInEditor = 'Go to Symbol in Editor';
2162
- const NoResults = 'No Results';
2163
- const OpenView = 'Open View';
2164
- const QuickOpen = 'Quick open';
2165
- const SearchForText = 'Search for text';
2166
- const ShowAndRunCommands = 'Show And Run Commands';
2167
- const TypeNameOfCommandToRun = 'Type the name of a command to run.';
2168
-
2169
- const typeNameofCommandToRun = () => {
2170
- return i18nString(TypeNameOfCommandToRun);
2171
- };
2172
- const showAndRunCommands = () => {
2173
- return i18nString(ShowAndRunCommands);
2174
- };
2175
- const goToFile = () => {
2176
- return i18nString(GoToFile);
2177
- };
2178
- const noResults = () => {
2179
- return i18nString(NoResults);
2115
+ const shouldHide = item => {
2116
+ if (item.id === 'Viewlet.openWidget' && item.args[0] === 'QuickPick') {
2117
+ return false;
2118
+ }
2119
+ return true;
2180
2120
  };
2181
- const quickOpen = () => {
2182
- return i18nString(QuickOpen);
2121
+ const selectPickBuiltin = async item => {
2122
+ const args = item.args || [];
2123
+ // TODO ids should be all numbers for efficiency -> also directly can call command
2124
+ await invoke$1(item.id, ...args);
2125
+ if (shouldHide(item)) {
2126
+ return {
2127
+ command: Hide
2128
+ };
2129
+ }
2130
+ return {
2131
+ command: KeepOpen
2132
+ };
2183
2133
  };
2184
- const goToLineColumn = () => {
2185
- return i18nString(GoToLineColumn);
2134
+ const selectPickExtension = async item => {
2135
+ const id = item.id.slice(4); // TODO lots of string allocation with 'ext.' find a better way to separate builtin commands from extension commands
2136
+ try {
2137
+ await invoke$1('ExtensionHost.executeCommand', id);
2138
+ } catch (error) {
2139
+ await handleError(error, false);
2140
+ await showErrorDialog(error);
2141
+ }
2142
+ return {
2143
+ command: Hide
2144
+ };
2186
2145
  };
2187
- const goToSymbolInEditor = () => {
2188
- return i18nString(GoToSymbolInEditor);
2146
+ const selectPick$8 = async item => {
2147
+ // @ts-ignore
2148
+ const id = item.id;
2149
+ if (id.startsWith('ext.')) {
2150
+ return selectPickExtension(item);
2151
+ }
2152
+ return selectPickBuiltin(item);
2189
2153
  };
2190
- const searchForText = () => {
2191
- return i18nString(SearchForText);
2154
+
2155
+ const selectPick$7 = async pick => {
2156
+ const {
2157
+ args
2158
+ } = state$1;
2159
+ const resolve = args[2];
2160
+ resolve(pick);
2161
+ return {
2162
+ command: Hide
2163
+ };
2192
2164
  };
2193
- const openView = () => {
2194
- return i18nString(OpenView);
2165
+
2166
+ const openUri = async uri => {
2167
+ await invoke$1(/* Main.openUri */'Main.openUri', /* uri */uri);
2195
2168
  };
2196
2169
 
2197
- const Div = 4;
2198
- const Input = 6;
2199
- const Span = 8;
2200
- const Img = 17;
2201
-
2202
- const getQuickPickInputVirtualDom = () => {
2203
- const ariaLabel = typeNameofCommandToRun();
2170
+ const selectPick$6 = async pick => {
2171
+ const description = pick.description;
2172
+ const fileName = pick.label;
2173
+ const workspace = await getWorkspacePath();
2174
+ const absolutePath = `${workspace}/${description}/${fileName}`;
2175
+ await openUri(absolutePath);
2204
2176
  return {
2205
- type: Input,
2206
- className: InputBox,
2207
- spellcheck: false,
2208
- autocapitalize: 'off',
2209
- inputType: 'text',
2210
- childCount: 0,
2211
- role: ComboBox,
2212
- name: QuickPickInput,
2213
- onBeforeInput: HandleBeforeInput,
2214
- onBlur: HandleBlur,
2215
- onInput: HandleInput,
2216
- onFocus: HandleFocus,
2217
- ariaLabel: ariaLabel,
2218
- ariaAutoComplete: 'list',
2219
- ariaExpanded: true,
2220
- autocomplete: 'off'
2177
+ command: Hide
2221
2178
  };
2222
2179
  };
2223
2180
 
2224
- const getQuickPickHeaderVirtualDom = () => {
2225
- return [{
2226
- type: Div,
2227
- className: QuickPickHeader,
2228
- childCount: 1
2229
- }, getQuickPickInputVirtualDom()];
2181
+ const execute = async (method, ...params) => {
2182
+ // TODO
2230
2183
  };
2231
2184
 
2232
- const getFileIconVirtualDom = icon => {
2185
+ const selectPick$5 = async item => {
2186
+ const rowIndex = Number.parseInt(item.label);
2187
+ const position = {
2188
+ rowIndex,
2189
+ columnIndex: 5
2190
+ };
2191
+ await execute(/* EditorSetCursor.editorSetCursor */'TODO', /* position */position);
2192
+ // TODO put cursor onto that line
2233
2193
  return {
2234
- type: Img,
2235
- className: FileIcon,
2236
- src: icon,
2237
- role: None,
2238
- childCount: 0
2194
+ command: Hide
2239
2195
  };
2240
2196
  };
2241
2197
 
2242
- const mergeClassNames = (...classNames) => {
2243
- return classNames.filter(Boolean).join(' ');
2244
- };
2245
- const Text = 12;
2246
- const text = data => {
2198
+ const selectPick$4 = async item => {
2199
+ // Command.execute(/* openView */ 549, /* viewName */ item.label)
2247
2200
  return {
2248
- type: Text,
2249
- text: data,
2250
- childCount: 0
2201
+ command: Hide
2251
2202
  };
2252
2203
  };
2253
2204
 
2254
- const quickPickHighlight = {
2255
- type: Span,
2256
- className: QuickPickHighlight,
2257
- childCount: 1
2205
+ const openWorkspaceFolder = uri => {
2206
+ return invoke$1(/* Workspace.setPath */'Workspace.setPath', /* path */uri);
2258
2207
  };
2259
- const getHighlights = (sections, label) => {
2260
- const labelDom = {
2261
- type: Div,
2262
- className: QuickPickItemLabel,
2263
- childCount: 0
2208
+
2209
+ // TODO selectPick should be independent of show/hide
2210
+ const selectPick$3 = async pick => {
2211
+ const path = `${pick.description}/${pick.label}`;
2212
+ await openWorkspaceFolder(path);
2213
+ return {
2214
+ command: Hide
2264
2215
  };
2265
- const nodes = [labelDom];
2266
- if (sections.length === 0) {
2267
- labelDom.childCount++;
2268
- nodes.push(text(label));
2269
- } else {
2270
- for (const section of sections) {
2271
- if (section.highlighted) {
2272
- labelDom.childCount++;
2273
- nodes.push(quickPickHighlight, text(section.text));
2274
- } else {
2275
- labelDom.childCount++;
2276
- nodes.push(text(section.text));
2277
- }
2278
- }
2279
- }
2280
- return nodes;
2281
2216
  };
2282
2217
 
2283
- const getQuickPickItemVirtualDom = visibleItem => {
2284
- const {
2285
- posInSet,
2286
- label,
2287
- setSize,
2288
- isActive,
2289
- description,
2290
- icon,
2291
- highlights,
2292
- fileIcon
2293
- } = visibleItem;
2294
- const dom = [];
2295
- dom.push({
2296
- type: Div,
2297
- className: QuickPickItem,
2298
- role: Option,
2299
- ariaPosInSet: posInSet,
2300
- ariaSetSize: setSize,
2301
- childCount: 1
2302
- });
2303
- const parent = dom[0];
2304
- if (isActive) {
2305
- // @ts-ignore
2306
- parent.id = QuickPickItemActive;
2307
- parent.className += ' ' + QuickPickItemActive$1;
2308
- }
2309
- if (fileIcon) {
2310
- parent.childCount++;
2311
- dom.push(getFileIconVirtualDom(fileIcon));
2312
- } else if (icon) {
2313
- parent.childCount++;
2314
- dom.push({
2315
- type: Div,
2316
- className: mergeClassNames(QuickPickMaskIcon, MaskIcon, `MaskIcon${icon}`),
2317
- childCount: 0
2318
- });
2319
- }
2320
- const highlightDom = getHighlights(highlights, label);
2321
- dom.push(...highlightDom);
2322
- if (description) {
2323
- parent.childCount++;
2324
- dom.push({
2325
- type: Div,
2326
- className: QuickPickItemDescription,
2327
- childCount: 1
2328
- }, text(description));
2329
- }
2330
- return dom;
2218
+ const selectPick$2 = async item => {
2219
+ return {
2220
+ command: Hide
2221
+ };
2331
2222
  };
2332
2223
 
2333
- const getQuickPickNoResultsVirtualDom = () => {
2334
- const noResults$1 = noResults();
2335
- return [{
2336
- type: Div,
2337
- className: mergeClassNames(QuickPickItem, QuickPickItemActive$1, QuickPickStatus),
2338
- childCount: 1
2339
- }, {
2340
- type: Div,
2341
- className: Label,
2342
- childCount: 1
2343
- }, text(noResults$1)];
2224
+ const selectPick$1 = async item => {
2225
+ // Command.execute(/* openView */ 549, /* viewName */ item.label)
2226
+ return {
2227
+ command: Hide
2228
+ };
2344
2229
  };
2345
2230
 
2346
- const getQuickPickItemsVirtualDom = visibleItems => {
2347
- if (visibleItems.length === 0) {
2348
- return getQuickPickNoResultsVirtualDom();
2349
- }
2350
- const dom = visibleItems.flatMap(getQuickPickItemVirtualDom);
2351
- return dom;
2231
+ const selectPick = async item => {
2232
+ return {
2233
+ command: Hide
2234
+ };
2352
2235
  };
2353
2236
 
2354
- const getQuickPickVirtualDom = visibleItems => {
2355
- const quickOpen$1 = quickOpen();
2356
- return [{
2357
- type: Div,
2358
- className: mergeClassNames(Viewlet, QuickPick$1),
2359
- childCount: 2,
2360
- id: QuickPick,
2361
- ariaLabel: quickOpen$1
2362
- }, ...getQuickPickHeaderVirtualDom(), {
2363
- type: Div,
2364
- className: QuickPickItems$1,
2365
- id: QuickPickItems,
2366
- role: ListBox,
2367
- ariaActivedescendant: QuickPickItemActive,
2368
- onWheel: HandleWheel,
2369
- childCount: visibleItems.length
2370
- }, ...getQuickPickItemsVirtualDom(visibleItems)];
2371
- };
2237
+ const selectPicks = [selectPick$9, selectPick$8, selectPick$7, selectPick$6, selectPick$5, selectPick$4, selectPick$3, selectPick$2, selectPick$1, selectPick];
2238
+ const getPicks$2 = [getPicks$c, getPicks$b, getPicks$a, getPicks$9, getPicks$8, getPicks$7, getPicks$6, getPicks$5, getPicks$4, getPicks$3];
2372
2239
 
2373
- const renderItems = newState => {
2374
- const dom = getQuickPickVirtualDom(newState.visibleItems);
2375
- return ['Viewlet.setDom2', dom];
2240
+ const select = selectPicks;
2241
+ const getPick$1 = getPicks$2;
2242
+ const getPicks$1 = id => {
2243
+ const fn = getPick$1[id];
2244
+ return fn;
2376
2245
  };
2377
-
2378
- const renderValue = newState => {
2379
- return ['Viewlet.send', newState.uid, /* method */SetValue, /* value */newState.value];
2246
+ const getSelect = id => {
2247
+ const fn = select[id];
2248
+ return fn;
2380
2249
  };
2381
2250
 
2382
- const getRenderer = diffType => {
2383
- switch (diffType) {
2384
- case RenderValue:
2385
- return renderValue;
2386
- case RenderCursorOffset:
2387
- return renderCursorOffset;
2388
- case RenderItems:
2389
- return renderItems;
2390
- case RenderFocusedIndex:
2391
- return renderFocusedIndex;
2392
- case Height:
2393
- return renderHeight;
2394
- case RenderFocus:
2395
- return renderFocus;
2396
- default:
2397
- throw new Error('unknown renderer');
2398
- }
2251
+ const getPicks = (id, searchValue) => {
2252
+ const fn = getPicks$1(id);
2253
+ return fn(searchValue);
2399
2254
  };
2400
2255
 
2401
- const applyRender = (oldState, newState, diffResult) => {
2402
- const commands = [];
2403
- const viewModel = createQuickPickViewModel(oldState, newState);
2404
- for (const item of diffResult) {
2405
- if (item === Height) {
2406
- continue;
2407
- }
2408
- if (item === RenderFocusedIndex) {
2409
- continue;
2410
- }
2411
- const fn = getRenderer(item);
2412
- commands.push(fn(viewModel));
2256
+ const getQuickPickSubProviderId = prefix => {
2257
+ switch (prefix) {
2258
+ case Command:
2259
+ return Commands$1;
2260
+ case Symbol$1:
2261
+ return Symbol$2;
2262
+ case WorkspaceSymbol$1:
2263
+ return WorkspaceSymbol$2;
2264
+ case GoToLine$1:
2265
+ return GoToLine$2;
2266
+ case View$2:
2267
+ return View$3;
2268
+ case Help$1:
2269
+ return Help$2;
2270
+ default:
2271
+ return File$2;
2413
2272
  }
2414
- return commands;
2415
2273
  };
2416
2274
 
2417
- const render2 = (uid, diffResult) => {
2275
+ // TODO when user types letters -> no need to query provider again -> just filter existing results
2276
+ const setValue = async (state, newValue) => {
2418
2277
  const {
2419
- oldState,
2420
- newState
2421
- } = get(uid);
2422
- if (oldState === newState) {
2423
- return [];
2278
+ providerId,
2279
+ value,
2280
+ minLineY,
2281
+ maxLineY,
2282
+ fileIconCache
2283
+ } = state;
2284
+ if (value === newValue) {
2285
+ return state;
2424
2286
  }
2425
- set(uid, newState, newState);
2426
- const commands = applyRender(oldState, newState, diffResult);
2427
- return commands;
2287
+ const prefix = getQuickPickPrefix(newValue);
2288
+ const subId = getQuickPickSubProviderId(prefix);
2289
+ const newPicks = await getPicks(subId, newValue);
2290
+ const filterValue = getFilterValue(providerId, newValue);
2291
+ const items = filterQuickPickItems(newPicks, filterValue);
2292
+ const focusedIndex = items.length === 0 ? -1 : 0;
2293
+ const sliced = items.slice(minLineY, maxLineY);
2294
+ const {
2295
+ newFileIconCache,
2296
+ icons
2297
+ } = await getQuickPickFileIcons(sliced, fileIconCache);
2298
+ return {
2299
+ ...state,
2300
+ picks: newPicks,
2301
+ items,
2302
+ focusedIndex,
2303
+ inputSource: Script,
2304
+ value: newValue,
2305
+ icons,
2306
+ fileIconCache: newFileIconCache
2307
+ };
2428
2308
  };
2429
2309
 
2430
- const renderEventListeners = () => {
2431
- return [{
2432
- name: HandlePointerDown,
2433
- params: ['handlePointerDown', 'event.clientX', 'event.clientY'],
2434
- preventDefault: true
2435
- }, {
2436
- name: HandleWheel,
2437
- params: ['handleWheel', 'event.deltaMode', 'event.deltaY']
2438
- }, {
2439
- name: HandleBlur,
2440
- params: ['handleBlur']
2441
- }, {
2442
- name: HandleBeforeInput,
2443
- params: ['handleBeforeInput']
2444
- }, {
2445
- name: HandleInput,
2446
- params: ['handleInput', 'event.target.value']
2447
- }, {
2448
- name: HandleFocus,
2449
- params: ['handleFocus']
2450
- }];
2310
+ // TODO when user types letters -> no need to query provider again -> just filter existing results
2311
+ const handleInput = async (state, newValue, cursorOffset, inputSource = Script) => {
2312
+ if (state.value === newValue) {
2313
+ return state;
2314
+ }
2315
+ const newState = await setValue(state, newValue);
2316
+ return {
2317
+ ...newState,
2318
+ cursorOffset,
2319
+ inputSource
2320
+ };
2451
2321
  };
2452
2322
 
2453
- const selectCurrentIndex = state => {
2454
- return selectIndex(state, state.focusedIndex);
2323
+ const handleBeforeInput = (state, inputType, data, selectionStart, selectionEnd) => {
2324
+ string(inputType);
2325
+ number(selectionStart);
2326
+ number(selectionEnd);
2327
+ const {
2328
+ value
2329
+ } = state;
2330
+ const {
2331
+ newValue,
2332
+ cursorOffset
2333
+ } = getNewValue(value, inputType, data, selectionStart, selectionEnd);
2334
+ return handleInput(state, newValue, cursorOffset, User);
2455
2335
  };
2456
2336
 
2457
- const findLabelIndex = (items, label) => {
2458
- for (let i = 0; i < items.length; i++) {
2459
- if (items[i].label === label) {
2460
- return i;
2461
- }
2337
+ const handleBlur = async state => {
2338
+ // TODO fix virtual dom diffing so that input isn't destroyed and loses focus when rerendering
2339
+ // await CloseWidget.closeWidget(state.uid)
2340
+ return state;
2341
+ };
2342
+
2343
+ const getIndex = (top, headerHeight, itemHeight, y) => {
2344
+ const relativeY = y - top - headerHeight;
2345
+ const index = Math.floor(relativeY / itemHeight);
2346
+ return index;
2347
+ };
2348
+
2349
+ const getPick = (items, index) => {
2350
+ array(items);
2351
+ number(index);
2352
+ // if (index < state.recentPicks.length) {
2353
+ // return state.recentPicks[index]
2354
+ // }
2355
+ // index -= state.recentPicks.length
2356
+ if (index < items.length) {
2357
+ return items[index];
2462
2358
  }
2463
- return -1;
2359
+ console.warn('no pick matching index', index);
2360
+ return undefined;
2464
2361
  };
2465
2362
 
2466
- const selectItem = async (state, label) => {
2467
- string(label);
2468
- const index = findLabelIndex(state.items, label);
2469
- if (index === -1) {
2363
+ const selectIndex = async (state, index, button = /* left */0) => {
2364
+ const {
2365
+ minLineY,
2366
+ items,
2367
+ value
2368
+ } = state;
2369
+ const actualIndex = index + minLineY;
2370
+ const pick = getPick(items, actualIndex);
2371
+ if (!pick) {
2470
2372
  return state;
2471
2373
  }
2472
- return selectIndex(state, index);
2374
+ const prefix = getQuickPickPrefix(value);
2375
+ const subId = getQuickPickSubProviderId(prefix);
2376
+ const fn = getSelect(subId);
2377
+ const selectPickResult = await fn(pick);
2378
+ object(selectPickResult);
2379
+ string(selectPickResult.command);
2380
+ const {
2381
+ command
2382
+ } = selectPickResult;
2383
+ switch (command) {
2384
+ case Hide:
2385
+ await closeWidget(state.uid);
2386
+ return state;
2387
+ default:
2388
+ return state;
2389
+ }
2390
+
2391
+ // TODO recent picks should be per provider
2392
+ // if (!state.recentPickIds.has(pick.id)) {
2393
+ // state.recentPicks.unshift(pick)
2394
+ // state.recentPickIds.add(pick.id)
2395
+ // }
2396
+ // if (state.recentPicks.length > RECENT_PICKS_MAX_SIZE) {
2397
+ // const last = state.recentPicks.pop()
2398
+ // state.recentPickIds.delete(last.id)
2399
+ // }
2473
2400
  };
2474
2401
 
2475
- const wrapCommand = fn => {
2476
- const wrapped = async (uid, ...args) => {
2477
- const {
2478
- newState
2479
- } = get(uid);
2480
- const newerState = await fn(newState, ...args);
2481
- if (newState === newerState) {
2482
- return;
2483
- }
2484
- const latest = get(uid);
2485
- set(uid, latest.oldState, newerState);
2486
- };
2487
- return wrapped;
2402
+ const handleClickAt = (state, x, y) => {
2403
+ const {
2404
+ top,
2405
+ headerHeight,
2406
+ itemHeight
2407
+ } = state;
2408
+ const index = getIndex(top, headerHeight, itemHeight, y);
2409
+ return selectIndex(state, index);
2488
2410
  };
2489
2411
 
2490
- const commandMap = {
2491
- 'QuickPick.addMenuEntries': add,
2492
- 'QuickPick.close': close,
2493
- 'QuickPick.create2': create,
2494
- 'QuickPick.diff2': diff2,
2495
- 'QuickPick.dispose': dispose,
2496
- 'QuickPick.focusFirst': wrapCommand(focusFirst),
2497
- 'QuickPick.focusIndex': wrapCommand(focusIndex),
2498
- 'QuickPick.focusLast': wrapCommand(focusLast),
2499
- 'QuickPick.focusNext': wrapCommand(focusNext),
2500
- 'QuickPick.focusPrevious': wrapCommand(focusPrevious),
2501
- 'QuickPick.getCommandIds': getCommandIds,
2502
- 'QuickPick.getKeyBindings': getKeyBindings,
2503
- 'QuickPick.handleBeforeInput': wrapCommand(handleBeforeInput),
2504
- 'QuickPick.handleBlur': wrapCommand(handleBlur),
2505
- 'QuickPick.handleClickAt': wrapCommand(handleClickAt),
2506
- 'QuickPick.handleFocus': wrapCommand(handleFocus),
2507
- 'QuickPick.handleInput': wrapCommand(handleInput),
2508
- 'QuickPick.handleWheel': wrapCommand(handleWheel),
2509
- 'QuickPick.loadContent': wrapCommand(loadContent),
2510
- 'QuickPick.render2': render2,
2511
- 'QuickPick.renderEventListeners': renderEventListeners,
2512
- 'QuickPick.selectCurrentIndex': wrapCommand(selectCurrentIndex),
2513
- 'QuickPick.selectIndex': wrapCommand(selectIndex),
2514
- 'QuickPick.selectItem': wrapCommand(selectItem),
2515
- 'QuickPick.setDeltaY': wrapCommand(setDeltaY),
2516
- 'QuickPick.setValue': wrapCommand(setValue)
2412
+ const setFocus = async focusKey => {
2413
+ await invoke$1('Focus.setFocus', focusKey);
2517
2414
  };
2518
2415
 
2519
- const getColorThemeNames = async () => {
2520
- return invoke$1(/* Ajax.getJson */'ColorTheme.getColorThemeNames');
2416
+ const handleFocus = async state => {
2417
+ // TODO fix virtual dom diffing so that input isn't destroyed and loses focus when rerendering
2418
+ await setFocus(FocusQuickPickInput);
2419
+ // await CloseWidget.closeWidget(state.uid)
2420
+ return state;
2521
2421
  };
2522
2422
 
2523
- const toProtoVisibleItem$2 = name => {
2524
- const pick = {
2525
- label: name,
2526
- description: '',
2527
- fileIcon: '',
2528
- icon: '',
2529
- matches: [],
2530
- direntType: 0,
2531
- uri: ''
2532
- };
2533
- return pick;
2423
+ const getDefaultValue = id => {
2424
+ switch (id) {
2425
+ case EveryThing$1:
2426
+ return Command;
2427
+ default:
2428
+ return '';
2429
+ }
2534
2430
  };
2535
- const getPicks$b = async searchValue => {
2536
- const colorThemeNames = await getColorThemeNames();
2537
- const picks = colorThemeNames.map(toProtoVisibleItem$2);
2538
- return picks;
2431
+
2432
+ const Commands = 'quickPick://commands';
2433
+ const EveryThing = 'quickPick://everything';
2434
+ const Recent = 'quickPick://recent';
2435
+ const ColorTheme = 'quickPick://color-theme';
2436
+ const Symbol = 'quickPick://symbol';
2437
+ const View = 'quickPick://view';
2438
+ const Help = 'quickPick://help';
2439
+ const WorkspaceSymbol = 'quickPick://workspace-symbol';
2440
+ const GoToLine = 'quickPick://go-to-line';
2441
+
2442
+ const getQuickPickProviderId = prefix => {
2443
+ switch (prefix) {
2444
+ case Commands:
2445
+ case Symbol:
2446
+ case WorkspaceSymbol:
2447
+ case EveryThing:
2448
+ case GoToLine:
2449
+ case View:
2450
+ case Help:
2451
+ return EveryThing$1;
2452
+ case ColorTheme:
2453
+ return ColorTheme$1;
2454
+ case Recent:
2455
+ return Recent$1;
2456
+ default:
2457
+ return File$2;
2458
+ }
2539
2459
  };
2540
2460
 
2541
- const handleError = async (error, notify = true, prefix = '') => {
2542
- console.error(error);
2461
+ const noop = args => {};
2462
+ const setArgsCustom = args => {
2463
+ state$1.args = args;
2543
2464
  };
2544
- const showErrorDialog = async error => {
2545
- const code = error.code;
2546
- const message = error.message;
2547
- const stack = error.stack;
2548
- const name = error.name;
2549
- const errorInfo = {
2550
- code,
2551
- message,
2552
- stack,
2553
- name
2554
- };
2555
- await invoke$1('ErrorHandling.showErrorDialog', errorInfo);
2465
+ const getFn = id => {
2466
+ switch (id) {
2467
+ case Custom:
2468
+ return setArgsCustom;
2469
+ default:
2470
+ return noop;
2471
+ }
2556
2472
  };
2557
- const warn = (...args) => {
2558
- console.warn(...args);
2473
+ const setArgs = (id, args) => {
2474
+ const fn = getFn(id);
2475
+ return fn(args);
2559
2476
  };
2560
2477
 
2561
- // TODO combine Ajax with cache (specify strategy: cacheFirst, networkFirst)
2562
- const getBuiltinPicks = async () => {
2563
- const builtinPicks = getAll();
2564
- return builtinPicks;
2565
- };
2566
- const prefixIdWithExt = item => {
2567
- if (!item.label) {
2568
- warn('[QuickPick] item has missing label', item);
2569
- }
2570
- if (!item.id) {
2571
- warn('[QuickPick] item has missing id', item);
2572
- }
2478
+ const loadContent = async state => {
2479
+ const {
2480
+ uri,
2481
+ args,
2482
+ fileIconCache
2483
+ } = state;
2484
+ const id = getQuickPickProviderId(uri);
2485
+ const value = getDefaultValue(id);
2486
+ const prefix = getQuickPickPrefix(value);
2487
+ const subId = getQuickPickSubProviderId(prefix);
2488
+ setArgs(subId, args);
2489
+ const newPicks = await getPicks(subId, value);
2490
+ array(newPicks);
2491
+ const filterValue = getFilterValue(id, value);
2492
+ const items = filterQuickPickItems(newPicks, filterValue);
2493
+ const minLineY = 0;
2494
+ const maxLineY = Math.min(minLineY + state.maxVisibleItems, newPicks.length);
2495
+ const sliced = newPicks.slice(minLineY, maxLineY);
2496
+ const {
2497
+ newFileIconCache,
2498
+ icons
2499
+ } = await getQuickPickFileIcons(sliced, fileIconCache);
2573
2500
  return {
2574
- ...item,
2575
- id: `ext.${item.id}`,
2576
- label: item.label || item.id
2577
- };
2578
- };
2579
- const getExtensionPicks = async () => {
2580
- try {
2581
- // TODO don't call this every time
2582
- const extensionPicks = await invoke$1('ExtensionHost.getCommands');
2583
- if (!extensionPicks) {
2584
- return [];
2585
- }
2586
- const mappedPicks = extensionPicks.map(prefixIdWithExt);
2587
- return mappedPicks;
2588
- } catch (error) {
2589
- console.error(`Failed to get extension picks: ${error}`);
2590
- return [];
2591
- }
2592
- };
2593
- const toProtoVisibleItem$1 = item => {
2594
- const pick = {
2595
- label: item.label,
2596
- description: '',
2597
- fileIcon: '',
2598
- icon: '',
2599
- matches: [],
2600
- direntType: 0,
2601
- uri: ''
2501
+ ...state,
2502
+ picks: newPicks,
2503
+ items,
2504
+ focusedIndex: 0,
2505
+ state: Finished,
2506
+ minLineY,
2507
+ maxLineY,
2508
+ value,
2509
+ cursorOffset: value.length,
2510
+ inputSource: Script,
2511
+ focused: true,
2512
+ fileIconCache: newFileIconCache,
2513
+ icons,
2514
+ providerId: id
2602
2515
  };
2603
- // @ts-ignore
2604
- pick.id = item.id;
2605
- return pick;
2606
- };
2607
- const getPicks$a = async () => {
2608
- // TODO get picks in parallel
2609
- const builtinPicks = await getBuiltinPicks();
2610
- const extensionPicks = await getExtensionPicks();
2611
- const allPicks = [...builtinPicks, ...extensionPicks];
2612
- const converted = allPicks.map(toProtoVisibleItem$1);
2613
- return converted;
2614
- };
2615
-
2616
- const getPicks$9 = async searchValue => {
2617
- const items = state$3.args[1] || [];
2618
- return items;
2619
2516
  };
2620
2517
 
2621
- const state$1 = {
2622
- provider: File$2,
2623
- prefix: 'string-that-should-never-match-another-string'
2518
+ const getVisible$1 = (items, minLineY, maxLineY, icons) => {
2519
+ const range = items.slice(minLineY, maxLineY);
2520
+ const protoVisibleItems = range.map((item, index) => {
2521
+ return {
2522
+ ...item,
2523
+ fileIcon: icons[index]
2524
+ };
2525
+ });
2526
+ return protoVisibleItems;
2624
2527
  };
2625
2528
 
2626
- const getPicks$8 = async value => {
2627
- const prefix = getQuickPickPrefix(value);
2628
- const providerId = getQuickPickProviderId(prefix);
2529
+ const emptyHighlightSections = [];
2629
2530
 
2630
- // TODO race condition
2631
- if (state$1.prefix !== prefix) {
2632
- state$1.prefix = prefix;
2633
- state$1.provider = providerId;
2531
+ const getHighlightSections = (highlights, label) => {
2532
+ if (highlights.length === 0) {
2533
+ return emptyHighlightSections;
2634
2534
  }
2635
- // TODO this line is a bit duplicated with getFilterValue
2636
- const slicedValue = value.slice(prefix.length).trimStart();
2637
- const picks = await getPicks$c(providerId, slicedValue);
2638
- return picks;
2535
+ const sections = [];
2536
+ let position = 0;
2537
+ for (let i = 0; i < highlights.length; i += 2) {
2538
+ const highlightStart = highlights[i];
2539
+ const highlightEnd = highlights[i + 1];
2540
+ if (position < highlightStart) {
2541
+ const beforeText = label.slice(position, highlightStart);
2542
+ sections.push({
2543
+ highlighted: false,
2544
+ text: beforeText
2545
+ });
2546
+ }
2547
+ const highlightText = label.slice(highlightStart, highlightEnd);
2548
+ sections.push({
2549
+ highlighted: true,
2550
+ text: highlightText
2551
+ });
2552
+ position = highlightEnd;
2553
+ }
2554
+ if (position < label.length) {
2555
+ const afterText = label.slice(position);
2556
+ sections.push({
2557
+ highlighted: false,
2558
+ text: afterText
2559
+ });
2560
+ }
2561
+ return sections;
2639
2562
  };
2640
2563
 
2641
- const emptyMatches = [];
2642
-
2643
- const getWorkspacePath = async () => {
2644
- return invoke$1('Workspace.getPath');
2564
+ const getVisible = (setSize, protoVisibleItems, minLineY, focusedIndex) => {
2565
+ const visibleItems = protoVisibleItems.map((visibleItem, i) => {
2566
+ const highlights = visibleItem.matches.slice(1);
2567
+ const sections = getHighlightSections(highlights, visibleItem.label);
2568
+ return {
2569
+ ...visibleItem,
2570
+ posInSet: minLineY + i + 1,
2571
+ setSize,
2572
+ isActive: i === focusedIndex,
2573
+ highlights: sections
2574
+ };
2575
+ });
2576
+ return visibleItems;
2645
2577
  };
2646
2578
 
2647
- const RE_PROTOCOL = /^([a-z-]+):\/\//;
2648
- const getProtocol = uri => {
2649
- const protocolMatch = uri.match(RE_PROTOCOL);
2650
- if (protocolMatch) {
2651
- return protocolMatch[1];
2652
- }
2653
- return '';
2579
+ const createQuickPickViewModel = (oldState, newState) => {
2580
+ const protoVisibleItems = getVisible$1(newState.items, newState.minLineY, newState.maxLineY, newState.icons);
2581
+ const visibleItems = getVisible(newState.items.length, protoVisibleItems, newState.minLineY, newState.focusedIndex);
2582
+ const oldFocusedIndex = oldState.focusedIndex - oldState.minLineY;
2583
+ const newFocusedIndex = newState.focusedIndex - newState.minLineY;
2584
+ const maxLineY = Math.min(newState.maxLineY, newState.items.length);
2585
+ const itemCount = maxLineY - newState.minLineY;
2586
+ const height = itemCount * newState.itemHeight;
2587
+ return {
2588
+ visibleItems,
2589
+ value: newState.value,
2590
+ cursorOffset: newState.cursorOffset,
2591
+ focused: newState.focused,
2592
+ height,
2593
+ oldFocusedIndex,
2594
+ newFocusedIndex,
2595
+ uid: newState.uid
2596
+ };
2654
2597
  };
2655
2598
 
2656
- const state = Object.create(null);
2657
- const register = modules => {
2658
- Object.assign(state, modules);
2659
- };
2660
- const getModule = protocol => {
2661
- return state[protocol];
2662
- };
2599
+ const SetCursorOffset = 'setCursorOffset';
2600
+ const SetFocusedIndex = 'setFocusedIndex';
2601
+ const SetItemsHeight = 'setItemsHeight';
2663
2602
 
2664
- const searchFile$5 = async (path, value, prepare, assetDir) => {
2665
- const protocol = getProtocol(path);
2666
- // TODO call different providers depending on protocol
2667
- const fn = getModule(protocol);
2668
- const result = await fn(path, value, prepare, assetDir);
2669
- return result;
2603
+ const renderCursorOffset = newState => {
2604
+ return ['Viewlet.send', newState.uid, /* method */SetCursorOffset, /* cursorOffset */newState.cursorOffset];
2670
2605
  };
2671
2606
 
2672
- // TODO this should be in FileSystem module
2673
- const pathBaseName = path => {
2674
- return path.slice(path.lastIndexOf('/') + 1);
2675
- };
2607
+ const QuickPickInput = 'QuickPickInput';
2676
2608
 
2677
- // TODO this should be in FileSystem module
2678
- const pathDirName = path => {
2679
- const pathSeparator = '/';
2680
- const index = path.lastIndexOf(pathSeparator);
2681
- if (index === -1) {
2682
- return '';
2683
- }
2684
- return path.slice(0, index);
2609
+ const renderFocus = newState => {
2610
+ return ['Viewlet.focusElementByName', QuickPickInput];
2685
2611
  };
2686
2612
 
2687
- const searchFile$4 = async (path, value) => {
2688
- const prepare = true;
2689
- const files = await searchFile$5(/* path */path, /* searchTerm */value, prepare, '');
2690
- return files;
2613
+ const renderFocusedIndex = newState => {
2614
+ return ['Viewlet.send', newState.uid, /* method */SetFocusedIndex, /* oldFocusedIndex */newState.oldFocusedIndex, /* newFocusedIndex */newState.newFocusedIndex];
2691
2615
  };
2692
- const convertToPick = uri => {
2693
- const baseName = pathBaseName(uri);
2694
- const dirName = pathDirName(uri);
2695
- return {
2696
- description: dirName,
2697
- direntType: File$1,
2698
- fileIcon: '',
2699
- icon: '',
2700
- label: baseName,
2701
- matches: emptyMatches,
2702
- uri
2703
- };
2616
+
2617
+ const renderHeight = newState => {
2618
+ if (newState.height === 0) {
2619
+ return ['Viewlet.send', newState.uid, /* method */SetItemsHeight, /* height */20];
2620
+ }
2621
+ return ['Viewlet.send', newState.uid, /* method */SetItemsHeight, /* height */newState.height];
2704
2622
  };
2705
2623
 
2706
- // TODO handle files differently
2707
- // e.g. when there are many files, don't need
2708
- // to compute the fileIcon for all files
2624
+ const ComboBox = 'combobox';
2625
+ const ListBox = 'listbox';
2626
+ const None = 'none';
2627
+ const Option = 'option';
2709
2628
 
2710
- const getPicks$7 = async searchValue => {
2711
- // TODO cache workspace path
2712
- const workspace = await getWorkspacePath();
2713
- if (!workspace) {
2714
- return [];
2715
- }
2716
- const files = await searchFile$4(workspace, searchValue);
2717
- const picks = files.map(convertToPick);
2718
- return picks;
2719
- };
2629
+ const FileIcon = 'FileIcon';
2630
+ const InputBox = 'InputBox';
2631
+ const Label = 'Label';
2632
+ const MaskIcon = 'MaskIcon';
2633
+ const QuickPick$1 = 'QuickPick';
2634
+ const QuickPickHeader = 'QuickPickHeader';
2635
+ const QuickPickHighlight = 'QuickPickHighlight';
2636
+ const QuickPickItem = 'QuickPickItem';
2637
+ const QuickPickItemActive$1 = 'QuickPickItemActive';
2638
+ const QuickPickItemDescription = 'QuickPickItemDescription';
2639
+ const QuickPickItemLabel = 'QuickPickItemLabel';
2640
+ const QuickPickItems$1 = 'QuickPickItems';
2641
+ const QuickPickMaskIcon = 'QuickPickMaskIcon';
2642
+ const QuickPickStatus = 'QuickPickStatus';
2643
+ const Viewlet = 'Viewlet';
2720
2644
 
2721
- const getPicks$6 = async () => {
2722
- const picks = [{
2723
- label: '1',
2724
- description: '',
2725
- icon: '',
2726
- fileIcon: '',
2727
- matches: [],
2728
- direntType: None$2,
2729
- uri: ''
2730
- }, {
2731
- label: '2',
2732
- description: '',
2733
- icon: '',
2734
- fileIcon: '',
2735
- matches: [],
2736
- direntType: None$2,
2737
- uri: ''
2738
- }, {
2739
- label: '3',
2740
- description: '',
2741
- icon: '',
2742
- fileIcon: '',
2743
- matches: [],
2744
- direntType: None$2,
2745
- uri: ''
2746
- }, {
2747
- label: '4',
2748
- description: '',
2749
- icon: '',
2750
- fileIcon: '',
2751
- matches: [],
2752
- direntType: None$2,
2753
- uri: ''
2754
- }, {
2755
- label: '5',
2756
- description: '',
2757
- icon: '',
2758
- fileIcon: '',
2759
- matches: [],
2760
- direntType: None$2,
2761
- uri: ''
2762
- }, {
2763
- label: '6',
2764
- description: '',
2765
- icon: '',
2766
- fileIcon: '',
2767
- matches: [],
2768
- direntType: None$2,
2769
- uri: ''
2770
- }];
2771
- return picks;
2772
- };
2645
+ const HandleWheel = 'handleWheel';
2646
+ const HandlePointerDown = 'handlePointerDown';
2647
+ const HandleBeforeInput = 'handleBeforeInput';
2648
+ const HandleBlur = 'handleBlur';
2649
+ const HandleFocus = 'handleFocus';
2650
+ const HandleInput = 'handleInput';
2773
2651
 
2774
- const DotDotDot = '...';
2775
- const Colon = ':';
2776
- const Percent = '%';
2777
- const AngleBracket = '>';
2778
- const View = 'view';
2652
+ const QuickPick = 'QuickPick';
2653
+ const QuickPickItems = 'QuickPickItems';
2654
+ const QuickPickItemActive = 'QuickPickItemActive';
2779
2655
 
2780
- const getPicks$5 = async () => {
2781
- return [{
2782
- description: goToFile(),
2783
- direntType: None$2,
2784
- fileIcon: '',
2785
- icon: '',
2786
- label: DotDotDot,
2787
- matches: [],
2788
- uri: ''
2789
- }, {
2790
- description: goToLineColumn(),
2791
- direntType: None$2,
2792
- fileIcon: '',
2793
- icon: '',
2794
- label: ':',
2795
- matches: [],
2796
- uri: ''
2797
- }, {
2798
- description: goToSymbolInEditor(),
2799
- direntType: None$2,
2800
- fileIcon: '',
2801
- icon: '',
2802
- label: Colon,
2803
- matches: [],
2804
- uri: ''
2805
- }, {
2806
- description: searchForText(),
2807
- direntType: None$2,
2808
- fileIcon: '',
2809
- icon: '',
2810
- label: Percent,
2811
- matches: [],
2812
- uri: ''
2813
- }, {
2814
- description: showAndRunCommands(),
2815
- direntType: None$2,
2816
- fileIcon: '',
2817
- icon: '',
2818
- label: AngleBracket,
2819
- matches: [],
2820
- uri: ''
2821
- }, {
2822
- description: openView(),
2823
- direntType: None$2,
2824
- fileIcon: '',
2825
- icon: '',
2826
- label: View,
2827
- matches: [],
2828
- uri: ''
2829
- }];
2656
+ const Div = 4;
2657
+ const Input = 6;
2658
+ const Span = 8;
2659
+ const Img = 17;
2660
+
2661
+ const getQuickPickInputVirtualDom = () => {
2662
+ const ariaLabel = typeNameofCommandToRun();
2663
+ return {
2664
+ type: Input,
2665
+ className: InputBox,
2666
+ spellcheck: false,
2667
+ autocapitalize: 'off',
2668
+ inputType: 'text',
2669
+ childCount: 0,
2670
+ role: ComboBox,
2671
+ name: QuickPickInput,
2672
+ onBeforeInput: HandleBeforeInput,
2673
+ onBlur: HandleBlur,
2674
+ onInput: HandleInput,
2675
+ onFocus: HandleFocus,
2676
+ ariaLabel: ariaLabel,
2677
+ ariaAutoComplete: 'list',
2678
+ ariaExpanded: true,
2679
+ autocomplete: 'off'
2680
+ };
2830
2681
  };
2831
2682
 
2832
- const getRecentlyOpened = () => {
2833
- return invoke$1(/* RecentlyOpened.getRecentlyOpened */'RecentlyOpened.getRecentlyOpened');
2683
+ const getQuickPickHeaderVirtualDom = () => {
2684
+ return [{
2685
+ type: Div,
2686
+ className: QuickPickHeader,
2687
+ childCount: 1
2688
+ }, getQuickPickInputVirtualDom()];
2834
2689
  };
2835
2690
 
2836
- const toProtoVisibleItem = uri => {
2691
+ const getFileIconVirtualDom = icon => {
2837
2692
  return {
2838
- label: uri,
2839
- description: '',
2840
- fileIcon: '',
2841
- icon: '',
2842
- matches: [],
2843
- direntType: Directory,
2844
- uri: uri
2693
+ type: Img,
2694
+ className: FileIcon,
2695
+ src: icon,
2696
+ role: None,
2697
+ childCount: 0
2845
2698
  };
2846
2699
  };
2847
- const getPicks$4 = async () => {
2848
- const recentlyOpened = await getRecentlyOpened();
2849
- const picks = recentlyOpened.map(toProtoVisibleItem);
2850
- return picks;
2851
- };
2852
2700
 
2853
- const getPicks$3 = async () => {
2854
- const picks = [];
2855
- return picks;
2701
+ const mergeClassNames = (...classNames) => {
2702
+ return classNames.filter(Boolean).join(' ');
2856
2703
  };
2857
-
2858
- const getPicks$2 = async () => {
2859
- return [];
2704
+ const Text = 12;
2705
+ const text = data => {
2706
+ return {
2707
+ type: Text,
2708
+ text: data,
2709
+ childCount: 0
2710
+ };
2860
2711
  };
2861
2712
 
2862
- const getPicks$1 = async () => {
2863
- const picks = [];
2864
- return picks;
2713
+ const quickPickHighlight = {
2714
+ type: Span,
2715
+ className: QuickPickHighlight,
2716
+ childCount: 1
2865
2717
  };
2866
-
2867
- const selectPick$a = async pick => {
2868
- const id = pick.label;
2869
- await setColorTheme(/* colorThemeId */id);
2870
- return {
2871
- command: Hide
2718
+ const getHighlights = (sections, label) => {
2719
+ const labelDom = {
2720
+ type: Div,
2721
+ className: QuickPickItemLabel,
2722
+ childCount: 0
2872
2723
  };
2724
+ const nodes = [labelDom];
2725
+ if (sections.length === 0) {
2726
+ labelDom.childCount++;
2727
+ nodes.push(text(label));
2728
+ } else {
2729
+ for (const section of sections) {
2730
+ if (section.highlighted) {
2731
+ labelDom.childCount++;
2732
+ nodes.push(quickPickHighlight, text(section.text));
2733
+ } else {
2734
+ labelDom.childCount++;
2735
+ nodes.push(text(section.text));
2736
+ }
2737
+ }
2738
+ }
2739
+ return nodes;
2873
2740
  };
2874
2741
 
2875
- const shouldHide = item => {
2876
- if (item.id === 'Viewlet.openWidget' && item.args[0] === 'QuickPick') {
2877
- return false;
2742
+ const getQuickPickItemVirtualDom = visibleItem => {
2743
+ const {
2744
+ posInSet,
2745
+ label,
2746
+ setSize,
2747
+ isActive,
2748
+ description,
2749
+ icon,
2750
+ highlights,
2751
+ fileIcon
2752
+ } = visibleItem;
2753
+ const dom = [];
2754
+ dom.push({
2755
+ type: Div,
2756
+ className: QuickPickItem,
2757
+ role: Option,
2758
+ ariaPosInSet: posInSet,
2759
+ ariaSetSize: setSize,
2760
+ childCount: 1
2761
+ });
2762
+ const parent = dom[0];
2763
+ if (isActive) {
2764
+ // @ts-ignore
2765
+ parent.id = QuickPickItemActive;
2766
+ parent.className += ' ' + QuickPickItemActive$1;
2767
+ }
2768
+ if (fileIcon) {
2769
+ parent.childCount++;
2770
+ dom.push(getFileIconVirtualDom(fileIcon));
2771
+ } else if (icon) {
2772
+ parent.childCount++;
2773
+ dom.push({
2774
+ type: Div,
2775
+ className: mergeClassNames(QuickPickMaskIcon, MaskIcon, `MaskIcon${icon}`),
2776
+ childCount: 0
2777
+ });
2878
2778
  }
2879
- return true;
2880
- };
2881
- const selectPickBuiltin = async item => {
2882
- const args = item.args || [];
2883
- // TODO ids should be all numbers for efficiency -> also directly can call command
2884
- await invoke$1(item.id, ...args);
2885
- if (shouldHide(item)) {
2886
- return {
2887
- command: Hide
2888
- };
2779
+ const highlightDom = getHighlights(highlights, label);
2780
+ dom.push(...highlightDom);
2781
+ if (description) {
2782
+ parent.childCount++;
2783
+ dom.push({
2784
+ type: Div,
2785
+ className: QuickPickItemDescription,
2786
+ childCount: 1
2787
+ }, text(description));
2889
2788
  }
2890
- return {
2891
- command: KeepOpen
2892
- };
2789
+ return dom;
2893
2790
  };
2894
- const selectPickExtension = async item => {
2895
- const id = item.id.slice(4); // TODO lots of string allocation with 'ext.' find a better way to separate builtin commands from extension commands
2896
- try {
2897
- await invoke$1('ExtensionHost.executeCommand', id);
2898
- } catch (error) {
2899
- await handleError(error, false);
2900
- await showErrorDialog(error);
2901
- }
2902
- return {
2903
- command: Hide
2904
- };
2791
+
2792
+ const getQuickPickNoResultsVirtualDom = () => {
2793
+ const noResults$1 = noResults();
2794
+ return [{
2795
+ type: Div,
2796
+ className: mergeClassNames(QuickPickItem, QuickPickItemActive$1, QuickPickStatus),
2797
+ childCount: 1
2798
+ }, {
2799
+ type: Div,
2800
+ className: Label,
2801
+ childCount: 1
2802
+ }, text(noResults$1)];
2905
2803
  };
2906
- const selectPick$9 = async item => {
2907
- // @ts-ignore
2908
- const id = item.id;
2909
- if (id.startsWith('ext.')) {
2910
- return selectPickExtension(item);
2804
+
2805
+ const getQuickPickItemsVirtualDom = visibleItems => {
2806
+ if (visibleItems.length === 0) {
2807
+ return getQuickPickNoResultsVirtualDom();
2911
2808
  }
2912
- return selectPickBuiltin(item);
2809
+ const dom = visibleItems.flatMap(getQuickPickItemVirtualDom);
2810
+ return dom;
2913
2811
  };
2914
2812
 
2915
- const selectPick$8 = async pick => {
2916
- const {
2917
- args
2918
- } = state$3;
2919
- const resolve = args[2];
2920
- resolve(pick);
2921
- return {
2922
- command: Hide
2923
- };
2813
+ const getQuickPickVirtualDom = visibleItems => {
2814
+ const quickOpen$1 = quickOpen();
2815
+ return [{
2816
+ type: Div,
2817
+ className: mergeClassNames(Viewlet, QuickPick$1),
2818
+ childCount: 2,
2819
+ id: QuickPick,
2820
+ ariaLabel: quickOpen$1
2821
+ }, ...getQuickPickHeaderVirtualDom(), {
2822
+ type: Div,
2823
+ className: QuickPickItems$1,
2824
+ id: QuickPickItems,
2825
+ role: ListBox,
2826
+ ariaActivedescendant: QuickPickItemActive,
2827
+ onWheel: HandleWheel,
2828
+ onPointerDown: HandlePointerDown,
2829
+ childCount: visibleItems.length
2830
+ }, ...getQuickPickItemsVirtualDom(visibleItems)];
2924
2831
  };
2925
2832
 
2926
- const selectPick$7 = item => {
2927
- const {
2928
- provider
2929
- } = state$1;
2930
- const fn = getSelect(provider);
2931
- return fn(item);
2833
+ const renderItems = newState => {
2834
+ const dom = getQuickPickVirtualDom(newState.visibleItems);
2835
+ return ['Viewlet.setDom2', dom];
2932
2836
  };
2933
2837
 
2934
- const openUri = async uri => {
2935
- await invoke$1(/* Main.openUri */'Main.openUri', /* uri */uri);
2838
+ const renderValue = newState => {
2839
+ return ['Viewlet.setValueByName', QuickPickInput, /* value */newState.value];
2936
2840
  };
2937
2841
 
2938
- const selectPick$6 = async pick => {
2939
- const description = pick.description;
2940
- const fileName = pick.label;
2941
- const workspace = await getWorkspacePath();
2942
- const absolutePath = `${workspace}/${description}/${fileName}`;
2943
- await openUri(absolutePath);
2944
- return {
2945
- command: Hide
2946
- };
2842
+ const getRenderer = diffType => {
2843
+ switch (diffType) {
2844
+ case RenderValue:
2845
+ return renderValue;
2846
+ case RenderCursorOffset:
2847
+ return renderCursorOffset;
2848
+ case RenderItems:
2849
+ return renderItems;
2850
+ case RenderFocusedIndex:
2851
+ return renderFocusedIndex;
2852
+ case Height:
2853
+ return renderHeight;
2854
+ case RenderFocus:
2855
+ return renderFocus;
2856
+ default:
2857
+ throw new Error('unknown renderer');
2858
+ }
2947
2859
  };
2948
2860
 
2949
- const execute = async (method, ...params) => {
2950
- // TODO
2861
+ const applyRender = (oldState, newState, diffResult) => {
2862
+ const commands = [];
2863
+ const viewModel = createQuickPickViewModel(oldState, newState);
2864
+ for (const item of diffResult) {
2865
+ if (item === Height) {
2866
+ continue;
2867
+ }
2868
+ if (item === RenderFocusedIndex) {
2869
+ continue;
2870
+ }
2871
+ const fn = getRenderer(item);
2872
+ commands.push(fn(viewModel));
2873
+ }
2874
+ return commands;
2951
2875
  };
2952
2876
 
2953
- const selectPick$5 = async item => {
2954
- const rowIndex = Number.parseInt(item.label);
2955
- const position = {
2956
- rowIndex,
2957
- columnIndex: 5
2958
- };
2959
- await execute(/* EditorSetCursor.editorSetCursor */'TODO', /* position */position);
2960
- // TODO put cursor onto that line
2961
- return {
2962
- command: Hide
2963
- };
2877
+ const render2 = (uid, diffResult) => {
2878
+ const {
2879
+ oldState,
2880
+ newState
2881
+ } = get(uid);
2882
+ if (oldState === newState) {
2883
+ return [];
2884
+ }
2885
+ set(uid, newState, newState);
2886
+ const commands = applyRender(oldState, newState, diffResult);
2887
+ return commands;
2964
2888
  };
2965
2889
 
2966
- const selectPick$4 = async item => {
2967
- // Command.execute(/* openView */ 549, /* viewName */ item.label)
2968
- return {
2969
- command: Hide
2970
- };
2890
+ const renderEventListeners = () => {
2891
+ return [{
2892
+ name: HandlePointerDown,
2893
+ params: ['handleClickAt', 'event.clientX', 'event.clientY'],
2894
+ preventDefault: true
2895
+ }, {
2896
+ name: HandleWheel,
2897
+ params: ['handleWheel', 'event.deltaMode', 'event.deltaY'],
2898
+ passive: true
2899
+ }, {
2900
+ name: HandleBlur,
2901
+ params: ['handleBlur']
2902
+ }, {
2903
+ name: HandleBeforeInput,
2904
+ params: ['handleBeforeInput']
2905
+ }, {
2906
+ name: HandleInput,
2907
+ params: ['handleInput', 'event.target.value']
2908
+ }, {
2909
+ name: HandleFocus,
2910
+ params: ['handleFocus']
2911
+ }];
2971
2912
  };
2972
2913
 
2973
- const openWorkspaceFolder = uri => {
2974
- return invoke$1(/* Workspace.setPath */'Workspace.setPath', /* path */uri);
2914
+ const selectCurrentIndex = state => {
2915
+ return selectIndex(state, state.focusedIndex);
2975
2916
  };
2976
2917
 
2977
- // TODO selectPick should be independent of show/hide
2978
- const selectPick$3 = async pick => {
2979
- const path = `${pick.description}/${pick.label}`;
2980
- await openWorkspaceFolder(path);
2981
- return {
2982
- command: Hide
2983
- };
2918
+ const findLabelIndex = (items, label) => {
2919
+ for (let i = 0; i < items.length; i++) {
2920
+ if (items[i].label === label) {
2921
+ return i;
2922
+ }
2923
+ }
2924
+ return -1;
2984
2925
  };
2985
2926
 
2986
- const selectPick$2 = async item => {
2987
- return {
2988
- command: Hide
2989
- };
2927
+ const selectItem = async (state, label) => {
2928
+ string(label);
2929
+ const index = findLabelIndex(state.items, label);
2930
+ if (index === -1) {
2931
+ return state;
2932
+ }
2933
+ return selectIndex(state, index);
2990
2934
  };
2991
2935
 
2992
- const selectPick$1 = async item => {
2993
- // Command.execute(/* openView */ 549, /* viewName */ item.label)
2994
- return {
2995
- command: Hide
2936
+ const wrapCommand = fn => {
2937
+ const wrapped = async (uid, ...args) => {
2938
+ const {
2939
+ newState
2940
+ } = get(uid);
2941
+ const newerState = await fn(newState, ...args);
2942
+ if (newState === newerState) {
2943
+ return;
2944
+ }
2945
+ const latest = get(uid);
2946
+ set(uid, latest.oldState, newerState);
2996
2947
  };
2948
+ return wrapped;
2997
2949
  };
2998
2950
 
2999
- const selectPick = async item => {
3000
- return {
3001
- command: Hide
3002
- };
2951
+ const commandMap = {
2952
+ 'QuickPick.addMenuEntries': add,
2953
+ 'QuickPick.close': close,
2954
+ 'QuickPick.create2': create,
2955
+ 'QuickPick.diff2': diff2,
2956
+ 'QuickPick.dispose': dispose,
2957
+ 'QuickPick.focusFirst': wrapCommand(focusFirst),
2958
+ 'QuickPick.focusIndex': wrapCommand(focusIndex),
2959
+ 'QuickPick.focusLast': wrapCommand(focusLast),
2960
+ 'QuickPick.focusNext': wrapCommand(focusNext),
2961
+ 'QuickPick.focusPrevious': wrapCommand(focusPrevious),
2962
+ 'QuickPick.getCommandIds': getCommandIds,
2963
+ 'QuickPick.getKeyBindings': getKeyBindings,
2964
+ 'QuickPick.handleBeforeInput': wrapCommand(handleBeforeInput),
2965
+ 'QuickPick.handleBlur': wrapCommand(handleBlur),
2966
+ 'QuickPick.handleClickAt': wrapCommand(handleClickAt),
2967
+ 'QuickPick.handleFocus': wrapCommand(handleFocus),
2968
+ 'QuickPick.handleInput': wrapCommand(handleInput),
2969
+ 'QuickPick.handleWheel': wrapCommand(handleWheel),
2970
+ 'QuickPick.loadContent': wrapCommand(loadContent),
2971
+ 'QuickPick.render2': render2,
2972
+ 'QuickPick.renderEventListeners': renderEventListeners,
2973
+ 'QuickPick.selectCurrentIndex': wrapCommand(selectCurrentIndex),
2974
+ 'QuickPick.selectIndex': wrapCommand(selectIndex),
2975
+ 'QuickPick.selectItem': wrapCommand(selectItem),
2976
+ 'QuickPick.setDeltaY': wrapCommand(setDeltaY),
2977
+ 'QuickPick.setValue': wrapCommand(setValue)
3003
2978
  };
3004
2979
 
3005
- const selectPicks = [selectPick$a, selectPick$7, selectPick$9, selectPick$8, selectPick$7, selectPick$6, selectPick$5, selectPick$4, selectPick$3, selectPick$2, selectPick$1, selectPick];
3006
- const getPicks = [getPicks$b, getPicks$8, getPicks$a, getPicks$9, getPicks$8, getPicks$7, getPicks$6, getPicks$5, getPicks$4, getPicks$3, getPicks$2, getPicks$1];
3007
-
3008
2980
  const Memfs = 'memfs';
3009
2981
  const Html = 'html';
3010
2982
  const Fetch = 'fetch';
@@ -3066,8 +3038,6 @@ const searchModules = {
3066
3038
 
3067
3039
  const listen = async () => {
3068
3040
  register(searchModules);
3069
- registerSelect(selectPicks);
3070
- registerGetPick(getPicks);
3071
3041
  const rpc = await WebWorkerRpcClient.create({
3072
3042
  commandMap: commandMap
3073
3043
  });