@lvce-editor/explorer-view 1.0.0 → 1.2.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.
@@ -6,17 +6,17 @@ const create$4 = (method, params) => {
6
6
  params
7
7
  };
8
8
  };
9
- const state = {
9
+ const state$1 = {
10
10
  callbacks: Object.create(null)
11
11
  };
12
12
  const set = (id, fn) => {
13
- state.callbacks[id] = fn;
13
+ state$1.callbacks[id] = fn;
14
14
  };
15
15
  const get = id => {
16
- return state.callbacks[id];
16
+ return state$1.callbacks[id];
17
17
  };
18
18
  const remove$1 = id => {
19
- delete state.callbacks[id];
19
+ delete state$1.callbacks[id];
20
20
  };
21
21
  let id = 0;
22
22
  const create$3 = () => {
@@ -339,7 +339,7 @@ const send = (transport, method, ...params) => {
339
339
  const message = create$4(method, params);
340
340
  transport.send(message);
341
341
  };
342
- const invoke = (ipc, method, ...params) => {
342
+ const invoke$1 = (ipc, method, ...params) => {
343
343
  return invokeHelper(ipc, method, params, false);
344
344
  };
345
345
  const invokeAndTransfer = (ipc, method, ...params) => {
@@ -753,7 +753,7 @@ const createRpc = ipc => {
753
753
  send(ipc, method, ...params);
754
754
  },
755
755
  invoke(method, ...params) {
756
- return invoke(ipc, method, ...params);
756
+ return invoke$1(ipc, method, ...params);
757
757
  },
758
758
  invokeAndTransfer(method, ...params) {
759
759
  return invokeAndTransfer(ipc, method, ...params);
@@ -799,6 +799,16 @@ const WebWorkerRpcClient = {
799
799
  create: create$1
800
800
  };
801
801
 
802
+ const RE_CHARACTERS = /^[a-zA-Z.-]+$/;
803
+ const compareStringNumeric = (a, b) => {
804
+ if (RE_CHARACTERS.test(a) && RE_CHARACTERS.test(b)) {
805
+ return a < b ? -1 : 1;
806
+ }
807
+ return a.localeCompare(b, 'en', {
808
+ numeric: true
809
+ });
810
+ };
811
+
802
812
  const BlockDevice = 1;
803
813
  const CharacterDevice = 2;
804
814
  const Directory = 3;
@@ -811,6 +821,142 @@ const SymLinkFile = 10;
811
821
  const SymLinkFolder = 11;
812
822
  const Unknown = 12;
813
823
 
824
+ const priorityMapFoldersFirst = {
825
+ [Directory]: 1,
826
+ [SymLinkFolder]: 1,
827
+ [File]: 0,
828
+ [SymLinkFile]: 0,
829
+ [Unknown]: 0,
830
+ [Socket]: 0
831
+ };
832
+ const compareDirentType = (direntA, direntB) => {
833
+ return priorityMapFoldersFirst[direntB.type] - priorityMapFoldersFirst[direntA.type];
834
+ };
835
+ const compareDirentName = (direntA, direntB) => {
836
+ return compareStringNumeric(direntA.name, direntB.name);
837
+ };
838
+ const compareDirent = (direntA, direntB) => {
839
+ return compareDirentType(direntA, direntB) || compareDirentName(direntA, direntB);
840
+ };
841
+
842
+ const getFileIcon = ({
843
+ name
844
+ }) => {
845
+ return '';
846
+ };
847
+ const getIcon = dirent => {
848
+ return '';
849
+ };
850
+
851
+ // TODO use posInSet and setSize properties to compute more effectively
852
+ const computeExplorerRenamedDirent = (dirents, index, newName) => {
853
+ let startIndex = index;
854
+ let innerEndIndex = index + 1;
855
+ let insertIndex = -1;
856
+ let posInSet = -1;
857
+ const oldDirent = dirents[index];
858
+ const newDirent = {
859
+ ...oldDirent,
860
+ name: newName,
861
+ path: oldDirent.path.slice(0, -oldDirent.name.length) + newName,
862
+ icon: getFileIcon({
863
+ name: newName
864
+ })
865
+ };
866
+ const depth = newDirent.depth;
867
+ // TODO
868
+ for (; startIndex >= 0; startIndex--) {
869
+ const dirent = dirents[startIndex];
870
+ if (dirent.depth > depth) {
871
+ continue;
872
+ }
873
+ if (dirent.depth < depth) {
874
+ break;
875
+ }
876
+ if (compareDirent(dirent, newDirent) === 1) {
877
+ insertIndex = startIndex;
878
+ posInSet = dirent.posInSet;
879
+ // dirent.posInSet++
880
+ }
881
+ }
882
+ startIndex++;
883
+ for (; innerEndIndex < dirents.length; innerEndIndex++) {
884
+ const dirent = dirents[innerEndIndex];
885
+ if (dirent.depth <= depth) {
886
+ break;
887
+ }
888
+ dirent.path = newDirent.path + dirent.path.slice(oldDirent.path.length);
889
+ }
890
+ innerEndIndex--;
891
+ let endIndex = innerEndIndex + 1;
892
+ for (; endIndex < dirents.length; endIndex++) {
893
+ const dirent = dirents[endIndex];
894
+ if (dirent.depth > depth) {
895
+ continue;
896
+ }
897
+ if (dirent.depth < depth) {
898
+ break;
899
+ }
900
+ if (insertIndex === -1 && compareDirent(dirent, newDirent === -1)) {
901
+ for (; endIndex < dirents.length; endIndex++) {
902
+ }
903
+ insertIndex = endIndex;
904
+ posInSet = dirent.posInSet + 1;
905
+ }
906
+ }
907
+ endIndex--;
908
+ for (let j = startIndex; j < index; j++) {
909
+ const dirent = dirents[j];
910
+ if (dirent.depth === depth) {
911
+ dirent.posInSet++;
912
+ }
913
+ }
914
+ for (let j = index; j < endIndex; j++) {
915
+ const dirent = dirents[j];
916
+ if (dirent.depth === depth) {
917
+ dirent.posInSet--;
918
+ }
919
+ }
920
+
921
+ // for (let j = startIndex; j < index; j++) {
922
+ // const dirent = dirents[j]
923
+ // dirent.posInSet++
924
+ // }
925
+
926
+ if (insertIndex === -1) {
927
+ insertIndex = index;
928
+ return {
929
+ focusedIndex: index,
930
+ newDirents: [...dirents.slice(0, index), newDirent, ...dirents.slice(index + 1)]
931
+ };
932
+ }
933
+ newDirent.posInSet = posInSet;
934
+ const newDirents = [...dirents];
935
+ if (index < insertIndex) {
936
+ insertIndex--;
937
+ }
938
+ newDirents.splice(index, 1);
939
+ newDirents.splice(insertIndex, 0, newDirent);
940
+ return {
941
+ newDirents,
942
+ focusedIndex: insertIndex
943
+ };
944
+ };
945
+
946
+ const None$1 = 0;
947
+ const CreateFile = 1;
948
+ const CreateFolder = 2;
949
+ const Rename = 3;
950
+
951
+ const remove = async diren => {};
952
+ const readDirWithFileTypes = async uri => {};
953
+ const getPathSeparator$1 = async root => {};
954
+ const getRealPath = async path => {};
955
+ const stat = async dirent => {};
956
+ const createFile = async uri => {};
957
+ const mkdir = async uri => {};
958
+ const rename = async (oldUri, newUri) => {};
959
+
814
960
  class AssertionError extends Error {
815
961
  constructor(message) {
816
962
  super(message);
@@ -845,6 +991,12 @@ const object = value => {
845
991
  throw new AssertionError('expected value to be of type object');
846
992
  }
847
993
  };
994
+ const number = value => {
995
+ const type = getType(value);
996
+ if (type !== 'number') {
997
+ throw new AssertionError('expected value to be of type number');
998
+ }
999
+ };
848
1000
  const array = value => {
849
1001
  const type = getType(value);
850
1002
  if (type !== 'array') {
@@ -858,50 +1010,150 @@ const string = value => {
858
1010
  }
859
1011
  };
860
1012
 
861
- const ENOENT = 'ENOENT';
862
-
863
- const remove = async diren => {};
864
- const readDirWithFileTypes = async uri => {};
865
- const getPathSeparator$1 = async root => {};
866
- const getRealPath = async path => {};
867
- const stat = async dirent => {};
868
-
869
- const getFileIcon = ({
870
- name
871
- }) => {
872
- return '';
873
- };
874
- const getIcon = dirent => {
875
- return '';
876
- };
877
-
878
- const RE_CHARACTERS = /^[a-zA-Z.-]+$/;
879
- const compareStringNumeric = (a, b) => {
880
- if (RE_CHARACTERS.test(a) && RE_CHARACTERS.test(b)) {
881
- return a < b ? -1 : 1;
1013
+ const dirname = (pathSeparator, path) => {
1014
+ const index = path.lastIndexOf(pathSeparator);
1015
+ if (index === -1) {
1016
+ return path;
882
1017
  }
883
- return a.localeCompare(b, 'en', {
884
- numeric: true
885
- });
1018
+ return path.slice(0, index);
886
1019
  };
887
1020
 
888
- const priorityMapFoldersFirst = {
889
- [Directory]: 1,
890
- [SymLinkFolder]: 1,
891
- [File]: 0,
892
- [SymLinkFile]: 0,
893
- [Unknown]: 0,
894
- [Socket]: 0
1021
+ const getParentFolder = (dirents, index, root) => {
1022
+ if (index < 0) {
1023
+ return root;
1024
+ }
1025
+ return dirents[index].path;
895
1026
  };
896
- const compareDirentType = (direntA, direntB) => {
897
- return priorityMapFoldersFirst[direntB.type] - priorityMapFoldersFirst[direntA.type];
1027
+ const acceptCreate = async (state, newDirentType, createFn) => {
1028
+ const {
1029
+ focusedIndex,
1030
+ editingValue
1031
+ } = state;
1032
+ const newFileName = editingValue;
1033
+ if (!newFileName) {
1034
+ // TODO show error message that file name must not be empty
1035
+ // below input box
1036
+ // await ErrorHandling.showErrorDialog(new Error('file name must not be empty'))
1037
+ return state;
1038
+ }
1039
+ const parentFolder = getParentFolder(state.items, focusedIndex, state.root);
1040
+ const absolutePath = [parentFolder, newFileName].join(state.pathSeparator);
1041
+ // TODO better handle error
1042
+ try {
1043
+ await createFn(absolutePath);
1044
+ } catch (error) {
1045
+ // TODO display error
1046
+ return state;
1047
+ }
1048
+ const parentDirent = focusedIndex >= 0 ? state.items[focusedIndex] : {
1049
+ depth: 0,
1050
+ path: state.root
1051
+ };
1052
+ const depth = parentDirent.depth + 1;
1053
+ const newDirent = {
1054
+ path: absolutePath,
1055
+ posInSet: -1,
1056
+ setSize: 1,
1057
+ depth,
1058
+ name: newFileName,
1059
+ type: newDirentType,
1060
+ icon: ''
1061
+ };
1062
+ newDirent.icon = getIcon();
1063
+ let insertIndex = state.focusedIndex;
1064
+ let deltaPosInSet = 0;
1065
+ let posInSet = 1;
1066
+ let setSize = 1;
1067
+ let i = Math.max(state.focusedIndex, -1) + 1;
1068
+ const {
1069
+ items
1070
+ } = state;
1071
+ // TODO update posinset and setsize of all affected dirents
1072
+ for (; i < items.length; i++) {
1073
+ const dirent = items[i];
1074
+ if (dirent.depth !== depth) {
1075
+ break;
1076
+ }
1077
+ const compareResult = compareDirent(dirent, newDirent);
1078
+ if (compareResult === 1) {
1079
+ insertIndex = i - 1;
1080
+ deltaPosInSet = 1 - 1;
1081
+ break;
1082
+ } else {
1083
+ posInSet = dirent.posInSet + 1;
1084
+ setSize = dirent.setSize + 1;
1085
+ insertIndex = i;
1086
+ }
1087
+ dirent.setSize++;
1088
+ dirent.posInSet += deltaPosInSet;
1089
+ }
1090
+ newDirent.setSize = setSize;
1091
+ newDirent.posInSet = posInSet;
1092
+ items.splice(insertIndex + 1, 0, newDirent);
1093
+ const newDirents = [...items];
1094
+ const newMaxlineY = Math.max(state.maxLineY, newDirents.length);
1095
+ return {
1096
+ ...state,
1097
+ items: newDirents,
1098
+ editingIndex: -1,
1099
+ focusedIndex: insertIndex + 1,
1100
+ editingType: None$1,
1101
+ maxLineY: newMaxlineY
1102
+ };
898
1103
  };
899
- const compareDirentName = (direntA, direntB) => {
900
- return compareStringNumeric(direntA.name, direntB.name);
1104
+ const acceptRename = async state => {
1105
+ const {
1106
+ editingIndex,
1107
+ editingValue,
1108
+ items,
1109
+ pathSeparator
1110
+ } = state;
1111
+ const renamedDirent = items[editingIndex];
1112
+ try {
1113
+ // TODO this does not work with rename of nested file
1114
+ const oldAbsolutePath = renamedDirent.path;
1115
+ const oldParentPath = dirname(pathSeparator, oldAbsolutePath);
1116
+ const newAbsolutePath = [oldParentPath, editingValue].join(pathSeparator);
1117
+ await rename(oldAbsolutePath, newAbsolutePath);
1118
+ } catch (error) {
1119
+ // TODO
1120
+ // await ErrorHandling.showErrorDialog(error)
1121
+ return state;
1122
+ }
1123
+ const {
1124
+ newDirents,
1125
+ focusedIndex
1126
+ } = computeExplorerRenamedDirent(items, editingIndex, editingValue);
1127
+ // TODO move focused index
1128
+ state.items = newDirents;
1129
+ return {
1130
+ ...state,
1131
+ editingIndex: -1,
1132
+ editingValue: '',
1133
+ editingType: None$1,
1134
+ editingIcon: '',
1135
+ focusedIndex,
1136
+ focused: true
1137
+ };
901
1138
  };
902
- const compareDirent = (direntA, direntB) => {
903
- return compareDirentType(direntA, direntB) || compareDirentName(direntA, direntB);
1139
+ const acceptEdit = state => {
1140
+ const {
1141
+ editingType
1142
+ } = state;
1143
+ switch (editingType) {
1144
+ case CreateFile:
1145
+ return acceptCreate(state, File, createFile);
1146
+ case CreateFolder:
1147
+ return acceptCreate(state, Directory, mkdir);
1148
+ case Rename:
1149
+ return acceptRename(state);
1150
+ default:
1151
+ return state;
1152
+ }
904
1153
  };
1154
+
1155
+ const ENOENT = 'ENOENT';
1156
+
905
1157
  const sortExplorerItems = rawDirents => {
906
1158
  rawDirents.sort(compareDirent);
907
1159
  };
@@ -1095,13 +1347,108 @@ const expandAll = async state => {
1095
1347
  };
1096
1348
  };
1097
1349
 
1098
- const None$1 = 'none';
1350
+ const focusIndex = (state, index) => {
1351
+ const {
1352
+ minLineY,
1353
+ maxLineY
1354
+ } = state;
1355
+ if (index < minLineY) {
1356
+ if (index < 0) {
1357
+ return {
1358
+ ...state,
1359
+ focusedIndex: index,
1360
+ focused: true
1361
+ };
1362
+ }
1363
+ const diff = maxLineY - minLineY;
1364
+ return {
1365
+ ...state,
1366
+ focusedIndex: index,
1367
+ focused: true,
1368
+ minLineY: index,
1369
+ maxLineY: index + diff
1370
+ };
1371
+ }
1372
+ if (index >= maxLineY) {
1373
+ const diff = maxLineY - minLineY;
1374
+ return {
1375
+ ...state,
1376
+ focusedIndex: index,
1377
+ focused: true,
1378
+ minLineY: index + 1 - diff,
1379
+ maxLineY: index + 1
1380
+ };
1381
+ }
1382
+ return {
1383
+ ...state,
1384
+ focusedIndex: index,
1385
+ focused: true
1386
+ };
1387
+ };
1388
+
1389
+ const focusFirst = state => {
1390
+ const {
1391
+ focusedIndex,
1392
+ items
1393
+ } = state;
1394
+ if (items.length === 0 || focusedIndex === 0) {
1395
+ return state;
1396
+ }
1397
+ return focusIndex(state, 0);
1398
+ };
1399
+
1400
+ const lastIndex = array => {
1401
+ return array.length - 1;
1402
+ };
1403
+
1404
+ const focusLast = state => {
1405
+ const {
1406
+ focusedIndex,
1407
+ items
1408
+ } = state;
1409
+ const lastIndex$1 = lastIndex(items);
1410
+ if (items.length === 0 || focusedIndex === lastIndex$1) {
1411
+ return state;
1412
+ }
1413
+ return focusIndex(state, lastIndex$1);
1414
+ };
1415
+
1416
+ const focusNext = state => {
1417
+ const {
1418
+ focusedIndex,
1419
+ items
1420
+ } = state;
1421
+ if (focusedIndex === lastIndex(items)) {
1422
+ return state;
1423
+ }
1424
+ return focusIndex(state, focusedIndex + 1);
1425
+ };
1426
+
1427
+ const focusPrevious = state => {
1428
+ const {
1429
+ focusedIndex,
1430
+ items
1431
+ } = state;
1432
+ switch (focusedIndex) {
1433
+ case -1:
1434
+ if (items.length === 0) {
1435
+ return state;
1436
+ }
1437
+ return focusIndex(state, lastIndex(items));
1438
+ case 0:
1439
+ return state;
1440
+ default:
1441
+ return focusIndex(state, focusedIndex - 1);
1442
+ }
1443
+ };
1444
+
1445
+ const None = 'none';
1099
1446
  const Tree = 'tree';
1100
1447
  const TreeItem$1 = 'treeitem';
1101
1448
 
1102
1449
  const Button$1 = 'Button';
1103
1450
  const ButtonPrimary = 'ButtonPrimary';
1104
- const Explorer = 'Explorer';
1451
+ const Explorer$1 = 'Explorer';
1105
1452
  const FileIcon = 'FileIcon';
1106
1453
  const InputBox = 'InputBox';
1107
1454
  const Label = 'Label';
@@ -1176,7 +1523,7 @@ const getFileIconVirtualDom = icon => {
1176
1523
  type: Img,
1177
1524
  className: FileIcon,
1178
1525
  src: icon,
1179
- role: None$1,
1526
+ role: None,
1180
1527
  childCount: 0
1181
1528
  };
1182
1529
  };
@@ -1318,7 +1665,7 @@ const mergeClassNames = (...classNames) => {
1318
1665
  const getExplorerWelcomeVirtualDom = isWide => {
1319
1666
  return [{
1320
1667
  type: Div,
1321
- className: mergeClassNames(Viewlet, Explorer),
1668
+ className: mergeClassNames(Viewlet, Explorer$1),
1322
1669
  tabIndex: 0,
1323
1670
  childCount: 1
1324
1671
  }, {
@@ -1344,7 +1691,7 @@ const getExplorerVirtualDom = (visibleItems, focusedIndex, root, isWide) => {
1344
1691
  const dom = [];
1345
1692
  dom.push({
1346
1693
  type: Div,
1347
- className: mergeClassNames(Viewlet, Explorer),
1694
+ className: mergeClassNames(Viewlet, Explorer$1),
1348
1695
  tabIndex: 0,
1349
1696
  role: Tree,
1350
1697
  ariaLabel: filesExplorer(),
@@ -1458,9 +1805,6 @@ const getKeyBindings = () => {
1458
1805
  }];
1459
1806
  };
1460
1807
 
1461
- const None = 0;
1462
- const Rename = 3;
1463
-
1464
1808
  const getVisibleExplorerItems = (items, minLineY, maxLineY, focusedIndex, editingIndex, editingType, editingValue) => {
1465
1809
  const visible = [];
1466
1810
  for (let i = minLineY; i < Math.min(maxLineY, items.length); i++) {
@@ -1481,7 +1825,7 @@ const getVisibleExplorerItems = (items, minLineY, maxLineY, focusedIndex, editin
1481
1825
  });
1482
1826
  }
1483
1827
  }
1484
- if (editingType !== None && editingIndex === -1) {
1828
+ if (editingType !== None$1 && editingIndex === -1) {
1485
1829
  visible.push({
1486
1830
  depth: 3,
1487
1831
  posInSet: 1,
@@ -1497,45 +1841,17 @@ const getVisibleExplorerItems = (items, minLineY, maxLineY, focusedIndex, editin
1497
1841
  return visible;
1498
1842
  };
1499
1843
 
1500
- const focusIndex = (state, index) => {
1844
+ const getFocusedDirent = state => {
1501
1845
  const {
1846
+ focusedIndex,
1502
1847
  minLineY,
1503
- maxLineY
1848
+ items
1504
1849
  } = state;
1505
- if (index < minLineY) {
1506
- if (index < 0) {
1507
- return {
1508
- ...state,
1509
- focusedIndex: index,
1510
- focused: true
1511
- };
1512
- }
1513
- const diff = maxLineY - minLineY;
1514
- return {
1515
- ...state,
1516
- focusedIndex: index,
1517
- focused: true,
1518
- minLineY: index,
1519
- maxLineY: index + diff
1520
- };
1521
- }
1522
- if (index >= maxLineY) {
1523
- const diff = maxLineY - minLineY;
1524
- return {
1525
- ...state,
1526
- focusedIndex: index,
1527
- focused: true,
1528
- minLineY: index + 1 - diff,
1529
- maxLineY: index + 1
1530
- };
1531
- }
1532
- return {
1533
- ...state,
1534
- focusedIndex: index,
1535
- focused: true
1536
- };
1850
+ const dirent = items[focusedIndex + minLineY];
1851
+ return dirent;
1537
1852
  };
1538
1853
 
1854
+ const Keyboard = -1;
1539
1855
  const LeftClick = 0;
1540
1856
 
1541
1857
  const openFolder = async () => {
@@ -1595,15 +1911,6 @@ const setDeltaY = (state, deltaY) => {
1595
1911
  const handleWheel = (state, deltaMode, deltaY) => {
1596
1912
  return setDeltaY(state, state.deltaY + deltaY);
1597
1913
  };
1598
- const getFocusedDirent = state => {
1599
- const {
1600
- focusedIndex,
1601
- minLineY,
1602
- items
1603
- } = state;
1604
- const dirent = items[focusedIndex + minLineY];
1605
- return dirent;
1606
- };
1607
1914
 
1608
1915
  // TODO support multiselection and removing multiple dirents
1609
1916
  const removeDirent = async state => {
@@ -1685,22 +1992,9 @@ const cancelEdit = state => {
1685
1992
  focused: true,
1686
1993
  editingIndex: -1,
1687
1994
  editingValue: '',
1688
- editingType: None
1995
+ editingType: None$1
1689
1996
  };
1690
1997
  };
1691
- const copyRelativePath = async state => {
1692
- const dirent = getFocusedDirent(state);
1693
- // @ts-ignore
1694
- dirent.path.slice(1);
1695
- // TODO handle error
1696
-
1697
- // await Command.execute(RendererWorkerCommandType.ClipBoardWriteText, /* text */ relativePath)
1698
- return state;
1699
- };
1700
- const copyPath = async state => {
1701
- // await Command.execute(RendererWorkerCommandType.ClipBoardWriteText, /* text */ path)
1702
- return state;
1703
- };
1704
1998
 
1705
1999
  // TODO much shared logic with newFolder
1706
2000
 
@@ -1931,7 +2225,7 @@ const handleBlur = state => {
1931
2225
  const {
1932
2226
  editingType
1933
2227
  } = state;
1934
- if (editingType !== None) {
2228
+ if (editingType !== None$1) {
1935
2229
  return state;
1936
2230
  }
1937
2231
  return {
@@ -1947,6 +2241,83 @@ const handleClickOpenFolder = async state => {
1947
2241
  return state;
1948
2242
  };
1949
2243
 
2244
+ const state = {
2245
+ rpc: undefined
2246
+ };
2247
+ const invoke = (method, ...params) => {
2248
+ const rpc = state.rpc;
2249
+ // @ts-ignore
2250
+ return rpc.invoke(method, ...params);
2251
+ };
2252
+ const setRpc = rpc => {
2253
+ state.rpc = rpc;
2254
+ };
2255
+
2256
+ const show = async (x, y, id, ...args) => {
2257
+ return invoke('ContextMenu.show', x, y, id, ...args);
2258
+ };
2259
+
2260
+ const Explorer = 4;
2261
+
2262
+ const handleContextMenuKeyboard = async state => {
2263
+ const {
2264
+ focusedIndex,
2265
+ x,
2266
+ y,
2267
+ minLineY,
2268
+ itemHeight
2269
+ } = state;
2270
+ const menuX = x;
2271
+ const menuY = y + (focusedIndex - minLineY + 1) * itemHeight;
2272
+ await show(menuX, menuY, Explorer);
2273
+ return state;
2274
+ };
2275
+
2276
+ const handleContextMenuMouseAt = async (state, x, y) => {
2277
+ number(x);
2278
+ number(y);
2279
+ const focusedIndex = getIndexFromPosition(state, x, y);
2280
+ await show(x, y, Explorer);
2281
+ return {
2282
+ ...state,
2283
+ focusedIndex,
2284
+ focused: false
2285
+ };
2286
+ };
2287
+
2288
+ const handleContextMenu = (state, button, x, y) => {
2289
+ switch (button) {
2290
+ case Keyboard:
2291
+ return handleContextMenuKeyboard(state);
2292
+ default:
2293
+ return handleContextMenuMouseAt(state, x, y);
2294
+ }
2295
+ };
2296
+
2297
+ const writeText = async text => {
2298
+ await invoke('ClipBoard.writeText', /* text */text);
2299
+ };
2300
+
2301
+ const copyRelativePath = async state => {
2302
+ const dirent = getFocusedDirent(state);
2303
+ const relativePath = dirent.path.slice(1);
2304
+ // TODO handle error
2305
+ await writeText(relativePath);
2306
+ return state;
2307
+ };
2308
+
2309
+ const handlePointerDown = (state, button, x, y) => {
2310
+ const index = getIndexFromPosition(state, x, y);
2311
+ if (button === LeftClick && index === -1) {
2312
+ return {
2313
+ ...state,
2314
+ focused: true,
2315
+ focusedIndex: -1
2316
+ };
2317
+ }
2318
+ return state;
2319
+ };
2320
+
1950
2321
  // TODO viewlet should only have create and refresh functions
1951
2322
  // every thing else can be in a separate module <viewlet>.lazy.js
1952
2323
  // and <viewlet>.ipc.js
@@ -1974,11 +2345,11 @@ const getExcluded = () => {
1974
2345
  }
1975
2346
  return excluded;
1976
2347
  };
1977
- const getSavedRoot = (savedState, workspacePath) => {
2348
+ const getSavedRoot$1 = (savedState, workspacePath) => {
1978
2349
  return workspacePath;
1979
2350
  };
1980
2351
  const loadContent = async (state, savedState) => {
1981
- const root = getSavedRoot(savedState, '');
2352
+ const root = getSavedRoot$1(savedState, '');
1982
2353
  // TODO path separator could be restored from saved state
1983
2354
  const pathSeparator = await getPathSeparator(); // TODO only load path separator once
1984
2355
  const excluded = getExcluded();
@@ -2008,11 +2379,95 @@ const loadContent = async (state, savedState) => {
2008
2379
  };
2009
2380
  };
2010
2381
 
2382
+ const getContaingingFolder = (root, dirents, focusedIndex, pathSeparator) => {
2383
+ if (focusedIndex < 0) {
2384
+ return root;
2385
+ }
2386
+ const dirent = dirents[focusedIndex];
2387
+ const direntPath = dirent.path;
2388
+ const direntParentPath = direntPath.slice(0, -(dirent.name.length + 1));
2389
+ const path = `${direntParentPath}`;
2390
+ return path;
2391
+ };
2392
+ const openContainingFolder = async state => {
2393
+ const {
2394
+ focusedIndex,
2395
+ root,
2396
+ items,
2397
+ pathSeparator
2398
+ } = state;
2399
+ const path = getContaingingFolder(root, items, focusedIndex);
2400
+ await invoke('OpenNativeFolder.openNativeFolder', /* path */path);
2401
+ return state;
2402
+ };
2403
+
2404
+ const getSavedRoot = (savedState, workspacePath) => {
2405
+ return workspacePath;
2406
+ };
2407
+ const restoreState = savedState => {
2408
+ if (!savedState) {
2409
+ return {
2410
+ minLineY: 0,
2411
+ deltaY: 0
2412
+ };
2413
+ }
2414
+ const root = getSavedRoot(savedState, savedState.workspacePath || '');
2415
+ let minLineY = 0;
2416
+ if (savedState && typeof savedState.minLineY === 'number') {
2417
+ minLineY = savedState.minLineY;
2418
+ }
2419
+ let deltaY = 0;
2420
+ if (savedState && typeof savedState.deltaY === 'number') {
2421
+ deltaY = savedState.deltaY;
2422
+ }
2423
+ return {
2424
+ ...savedState,
2425
+ root,
2426
+ minLineY,
2427
+ deltaY
2428
+ };
2429
+ };
2430
+
2431
+ const copyPath = async state => {
2432
+ // await Command.execute(RendererWorkerCommandType.ClipBoardWriteText, /* text */ path)
2433
+ return state;
2434
+ };
2435
+
2436
+ const isExpandedDirectory = dirent => {
2437
+ return dirent.type === DirectoryExpanded;
2438
+ };
2439
+ const getPath = dirent => {
2440
+ return dirent.path;
2441
+ };
2442
+ const saveState = state => {
2443
+ const {
2444
+ items,
2445
+ root,
2446
+ deltaY,
2447
+ minLineY,
2448
+ maxLineY
2449
+ } = state;
2450
+ const expandedPaths = items.filter(isExpandedDirectory).map(getPath);
2451
+ return {
2452
+ expandedPaths,
2453
+ root,
2454
+ minLineY,
2455
+ maxLineY,
2456
+ deltaY
2457
+ };
2458
+ };
2459
+
2011
2460
  const commandMap = {
2461
+ 'Explorer.acceptEdit': acceptEdit,
2012
2462
  'Explorer.cancelEdit': cancelEdit,
2013
2463
  'Explorer.copyPath': copyPath,
2014
2464
  'Explorer.copyRelativePath': copyRelativePath,
2015
2465
  'Explorer.expandAll': expandAll,
2466
+ 'Explorer.focusFirst': focusFirst,
2467
+ 'Explorer.focusIndex': focusIndex,
2468
+ 'Explorer.focusLast': focusLast,
2469
+ 'Explorer.focusNext': focusNext,
2470
+ 'Explorer.focusPrevious': focusPrevious,
2016
2471
  'Explorer.getKeyBindings': getKeyBindings,
2017
2472
  'Explorer.getVirtualDom': getExplorerVirtualDom,
2018
2473
  'Explorer.getVisibleItems': getVisibleExplorerItems,
@@ -2023,17 +2478,23 @@ const commandMap = {
2023
2478
  'Explorer.handleClickAt': handleClickAt,
2024
2479
  'Explorer.handleClickCurrentButKeepFocus': handleClickCurrentButKeepFocus,
2025
2480
  'Explorer.handleClickOpenFolder': handleClickOpenFolder,
2481
+ 'Explorer.handleContextMenu': handleContextMenu,
2026
2482
  'Explorer.handleIconThemeChange': handleIconThemeChange,
2483
+ 'Explorer.handlePointerDown': handlePointerDown,
2027
2484
  'Explorer.handleWheel': handleWheel,
2028
2485
  'Explorer.loadContent': loadContent,
2486
+ 'Explorer.openContainingFolder': openContainingFolder,
2029
2487
  'Explorer.removeDirent': removeDirent,
2030
- 'Explorer.renameDirent': renameDirent
2488
+ 'Explorer.renameDirent': renameDirent,
2489
+ 'Explorer.restoreState': restoreState,
2490
+ 'Explorer.saveState': saveState
2031
2491
  };
2032
2492
 
2033
2493
  const listen = async () => {
2034
- await WebWorkerRpcClient.create({
2494
+ const rpc = await WebWorkerRpcClient.create({
2035
2495
  commandMap: commandMap
2036
2496
  });
2497
+ setRpc(rpc);
2037
2498
  };
2038
2499
 
2039
2500
  const main = async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/explorer-view",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "description": "Explorer Worker",
5
5
  "main": "dist/explorerViewWorkerMain.js",
6
6
  "type": "module",