@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.
- package/dist/explorerViewWorkerMain.js +575 -114
- package/package.json +1 -1
|
@@ -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
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
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
|
|
884
|
-
numeric: true
|
|
885
|
-
});
|
|
1018
|
+
return path.slice(0, index);
|
|
886
1019
|
};
|
|
887
1020
|
|
|
888
|
-
const
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
[
|
|
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
|
|
897
|
-
|
|
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
|
|
900
|
-
|
|
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
|
|
903
|
-
|
|
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
|
|
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
|
|
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
|
|
1844
|
+
const getFocusedDirent = state => {
|
|
1501
1845
|
const {
|
|
1846
|
+
focusedIndex,
|
|
1502
1847
|
minLineY,
|
|
1503
|
-
|
|
1848
|
+
items
|
|
1504
1849
|
} = state;
|
|
1505
|
-
|
|
1506
|
-
|
|
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 () => {
|