@lvce-editor/explorer-view 1.1.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 +480 -80
- 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
|
};
|
|
@@ -1190,13 +1442,13 @@ const focusPrevious = state => {
|
|
|
1190
1442
|
}
|
|
1191
1443
|
};
|
|
1192
1444
|
|
|
1193
|
-
const None
|
|
1445
|
+
const None = 'none';
|
|
1194
1446
|
const Tree = 'tree';
|
|
1195
1447
|
const TreeItem$1 = 'treeitem';
|
|
1196
1448
|
|
|
1197
1449
|
const Button$1 = 'Button';
|
|
1198
1450
|
const ButtonPrimary = 'ButtonPrimary';
|
|
1199
|
-
const Explorer = 'Explorer';
|
|
1451
|
+
const Explorer$1 = 'Explorer';
|
|
1200
1452
|
const FileIcon = 'FileIcon';
|
|
1201
1453
|
const InputBox = 'InputBox';
|
|
1202
1454
|
const Label = 'Label';
|
|
@@ -1271,7 +1523,7 @@ const getFileIconVirtualDom = icon => {
|
|
|
1271
1523
|
type: Img,
|
|
1272
1524
|
className: FileIcon,
|
|
1273
1525
|
src: icon,
|
|
1274
|
-
role: None
|
|
1526
|
+
role: None,
|
|
1275
1527
|
childCount: 0
|
|
1276
1528
|
};
|
|
1277
1529
|
};
|
|
@@ -1413,7 +1665,7 @@ const mergeClassNames = (...classNames) => {
|
|
|
1413
1665
|
const getExplorerWelcomeVirtualDom = isWide => {
|
|
1414
1666
|
return [{
|
|
1415
1667
|
type: Div,
|
|
1416
|
-
className: mergeClassNames(Viewlet, Explorer),
|
|
1668
|
+
className: mergeClassNames(Viewlet, Explorer$1),
|
|
1417
1669
|
tabIndex: 0,
|
|
1418
1670
|
childCount: 1
|
|
1419
1671
|
}, {
|
|
@@ -1439,7 +1691,7 @@ const getExplorerVirtualDom = (visibleItems, focusedIndex, root, isWide) => {
|
|
|
1439
1691
|
const dom = [];
|
|
1440
1692
|
dom.push({
|
|
1441
1693
|
type: Div,
|
|
1442
|
-
className: mergeClassNames(Viewlet, Explorer),
|
|
1694
|
+
className: mergeClassNames(Viewlet, Explorer$1),
|
|
1443
1695
|
tabIndex: 0,
|
|
1444
1696
|
role: Tree,
|
|
1445
1697
|
ariaLabel: filesExplorer(),
|
|
@@ -1553,9 +1805,6 @@ const getKeyBindings = () => {
|
|
|
1553
1805
|
}];
|
|
1554
1806
|
};
|
|
1555
1807
|
|
|
1556
|
-
const None = 0;
|
|
1557
|
-
const Rename = 3;
|
|
1558
|
-
|
|
1559
1808
|
const getVisibleExplorerItems = (items, minLineY, maxLineY, focusedIndex, editingIndex, editingType, editingValue) => {
|
|
1560
1809
|
const visible = [];
|
|
1561
1810
|
for (let i = minLineY; i < Math.min(maxLineY, items.length); i++) {
|
|
@@ -1576,7 +1825,7 @@ const getVisibleExplorerItems = (items, minLineY, maxLineY, focusedIndex, editin
|
|
|
1576
1825
|
});
|
|
1577
1826
|
}
|
|
1578
1827
|
}
|
|
1579
|
-
if (editingType !== None && editingIndex === -1) {
|
|
1828
|
+
if (editingType !== None$1 && editingIndex === -1) {
|
|
1580
1829
|
visible.push({
|
|
1581
1830
|
depth: 3,
|
|
1582
1831
|
posInSet: 1,
|
|
@@ -1592,6 +1841,17 @@ const getVisibleExplorerItems = (items, minLineY, maxLineY, focusedIndex, editin
|
|
|
1592
1841
|
return visible;
|
|
1593
1842
|
};
|
|
1594
1843
|
|
|
1844
|
+
const getFocusedDirent = state => {
|
|
1845
|
+
const {
|
|
1846
|
+
focusedIndex,
|
|
1847
|
+
minLineY,
|
|
1848
|
+
items
|
|
1849
|
+
} = state;
|
|
1850
|
+
const dirent = items[focusedIndex + minLineY];
|
|
1851
|
+
return dirent;
|
|
1852
|
+
};
|
|
1853
|
+
|
|
1854
|
+
const Keyboard = -1;
|
|
1595
1855
|
const LeftClick = 0;
|
|
1596
1856
|
|
|
1597
1857
|
const openFolder = async () => {
|
|
@@ -1651,15 +1911,6 @@ const setDeltaY = (state, deltaY) => {
|
|
|
1651
1911
|
const handleWheel = (state, deltaMode, deltaY) => {
|
|
1652
1912
|
return setDeltaY(state, state.deltaY + deltaY);
|
|
1653
1913
|
};
|
|
1654
|
-
const getFocusedDirent = state => {
|
|
1655
|
-
const {
|
|
1656
|
-
focusedIndex,
|
|
1657
|
-
minLineY,
|
|
1658
|
-
items
|
|
1659
|
-
} = state;
|
|
1660
|
-
const dirent = items[focusedIndex + minLineY];
|
|
1661
|
-
return dirent;
|
|
1662
|
-
};
|
|
1663
1914
|
|
|
1664
1915
|
// TODO support multiselection and removing multiple dirents
|
|
1665
1916
|
const removeDirent = async state => {
|
|
@@ -1741,22 +1992,9 @@ const cancelEdit = state => {
|
|
|
1741
1992
|
focused: true,
|
|
1742
1993
|
editingIndex: -1,
|
|
1743
1994
|
editingValue: '',
|
|
1744
|
-
editingType: None
|
|
1995
|
+
editingType: None$1
|
|
1745
1996
|
};
|
|
1746
1997
|
};
|
|
1747
|
-
const copyRelativePath = async state => {
|
|
1748
|
-
const dirent = getFocusedDirent(state);
|
|
1749
|
-
// @ts-ignore
|
|
1750
|
-
dirent.path.slice(1);
|
|
1751
|
-
// TODO handle error
|
|
1752
|
-
|
|
1753
|
-
// await Command.execute(RendererWorkerCommandType.ClipBoardWriteText, /* text */ relativePath)
|
|
1754
|
-
return state;
|
|
1755
|
-
};
|
|
1756
|
-
const copyPath = async state => {
|
|
1757
|
-
// await Command.execute(RendererWorkerCommandType.ClipBoardWriteText, /* text */ path)
|
|
1758
|
-
return state;
|
|
1759
|
-
};
|
|
1760
1998
|
|
|
1761
1999
|
// TODO much shared logic with newFolder
|
|
1762
2000
|
|
|
@@ -1987,7 +2225,7 @@ const handleBlur = state => {
|
|
|
1987
2225
|
const {
|
|
1988
2226
|
editingType
|
|
1989
2227
|
} = state;
|
|
1990
|
-
if (editingType !== None) {
|
|
2228
|
+
if (editingType !== None$1) {
|
|
1991
2229
|
return state;
|
|
1992
2230
|
}
|
|
1993
2231
|
return {
|
|
@@ -2003,6 +2241,83 @@ const handleClickOpenFolder = async state => {
|
|
|
2003
2241
|
return state;
|
|
2004
2242
|
};
|
|
2005
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
|
+
|
|
2006
2321
|
// TODO viewlet should only have create and refresh functions
|
|
2007
2322
|
// every thing else can be in a separate module <viewlet>.lazy.js
|
|
2008
2323
|
// and <viewlet>.ipc.js
|
|
@@ -2030,11 +2345,11 @@ const getExcluded = () => {
|
|
|
2030
2345
|
}
|
|
2031
2346
|
return excluded;
|
|
2032
2347
|
};
|
|
2033
|
-
const getSavedRoot = (savedState, workspacePath) => {
|
|
2348
|
+
const getSavedRoot$1 = (savedState, workspacePath) => {
|
|
2034
2349
|
return workspacePath;
|
|
2035
2350
|
};
|
|
2036
2351
|
const loadContent = async (state, savedState) => {
|
|
2037
|
-
const root = getSavedRoot(savedState, '');
|
|
2352
|
+
const root = getSavedRoot$1(savedState, '');
|
|
2038
2353
|
// TODO path separator could be restored from saved state
|
|
2039
2354
|
const pathSeparator = await getPathSeparator(); // TODO only load path separator once
|
|
2040
2355
|
const excluded = getExcluded();
|
|
@@ -2064,7 +2379,86 @@ const loadContent = async (state, savedState) => {
|
|
|
2064
2379
|
};
|
|
2065
2380
|
};
|
|
2066
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
|
+
|
|
2067
2460
|
const commandMap = {
|
|
2461
|
+
'Explorer.acceptEdit': acceptEdit,
|
|
2068
2462
|
'Explorer.cancelEdit': cancelEdit,
|
|
2069
2463
|
'Explorer.copyPath': copyPath,
|
|
2070
2464
|
'Explorer.copyRelativePath': copyRelativePath,
|
|
@@ -2084,17 +2478,23 @@ const commandMap = {
|
|
|
2084
2478
|
'Explorer.handleClickAt': handleClickAt,
|
|
2085
2479
|
'Explorer.handleClickCurrentButKeepFocus': handleClickCurrentButKeepFocus,
|
|
2086
2480
|
'Explorer.handleClickOpenFolder': handleClickOpenFolder,
|
|
2481
|
+
'Explorer.handleContextMenu': handleContextMenu,
|
|
2087
2482
|
'Explorer.handleIconThemeChange': handleIconThemeChange,
|
|
2483
|
+
'Explorer.handlePointerDown': handlePointerDown,
|
|
2088
2484
|
'Explorer.handleWheel': handleWheel,
|
|
2089
2485
|
'Explorer.loadContent': loadContent,
|
|
2486
|
+
'Explorer.openContainingFolder': openContainingFolder,
|
|
2090
2487
|
'Explorer.removeDirent': removeDirent,
|
|
2091
|
-
'Explorer.renameDirent': renameDirent
|
|
2488
|
+
'Explorer.renameDirent': renameDirent,
|
|
2489
|
+
'Explorer.restoreState': restoreState,
|
|
2490
|
+
'Explorer.saveState': saveState
|
|
2092
2491
|
};
|
|
2093
2492
|
|
|
2094
2493
|
const listen = async () => {
|
|
2095
|
-
await WebWorkerRpcClient.create({
|
|
2494
|
+
const rpc = await WebWorkerRpcClient.create({
|
|
2096
2495
|
commandMap: commandMap
|
|
2097
2496
|
});
|
|
2497
|
+
setRpc(rpc);
|
|
2098
2498
|
};
|
|
2099
2499
|
|
|
2100
2500
|
const main = async () => {
|