@lvce-editor/explorer-view 2.7.0 → 2.8.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 +299 -256
- package/package.json +1 -1
|
@@ -901,6 +901,241 @@ const compareDirent = (direntA, direntB) => {
|
|
|
901
901
|
return compareDirentType(direntA, direntB) || compareDirentName(direntA, direntB);
|
|
902
902
|
};
|
|
903
903
|
|
|
904
|
+
const None$5 = 0;
|
|
905
|
+
const CreateFile = 1;
|
|
906
|
+
const CreateFolder = 2;
|
|
907
|
+
const Rename$1 = 3;
|
|
908
|
+
|
|
909
|
+
const emptyObject = {};
|
|
910
|
+
const RE_PLACEHOLDER = /\{(PH\d+)\}/g;
|
|
911
|
+
const i18nString = (key, placeholders = emptyObject) => {
|
|
912
|
+
if (placeholders === emptyObject) {
|
|
913
|
+
return key;
|
|
914
|
+
}
|
|
915
|
+
const replacer = (match, rest) => {
|
|
916
|
+
return placeholders[rest];
|
|
917
|
+
};
|
|
918
|
+
return key.replaceAll(RE_PLACEHOLDER, replacer);
|
|
919
|
+
};
|
|
920
|
+
|
|
921
|
+
const CollapseAllFoldersInExplorer = 'Collapse All Folders in Explorer';
|
|
922
|
+
const Copy$1 = 'Copy';
|
|
923
|
+
const CopyPath = 'Copy Path';
|
|
924
|
+
const CopyRelativePath = 'Copy Relative Path';
|
|
925
|
+
const Cut$1 = 'Cut';
|
|
926
|
+
const Delete$1 = 'Delete';
|
|
927
|
+
const FileOrFolderNameMustBeProvider = 'A file or folder name must be provided.';
|
|
928
|
+
const FilesExplorer = 'Files Explorer';
|
|
929
|
+
const NewFile$1 = 'New File...';
|
|
930
|
+
const NewFolder$1 = 'New Folder...';
|
|
931
|
+
const OpenContainingFolder = 'Open Containing Folder';
|
|
932
|
+
const OpenFolder = 'Open folder';
|
|
933
|
+
const OpenInIntegratedTerminal = 'Open in integrated Terminal';
|
|
934
|
+
const Paste = 'Paste';
|
|
935
|
+
const RefreshExplorer = 'Refresh Explorer';
|
|
936
|
+
const Rename = 'Rename';
|
|
937
|
+
const YouHaveNotYetOpenedAFolder = 'You have not yet opened a folder';
|
|
938
|
+
|
|
939
|
+
const newFile$1 = () => {
|
|
940
|
+
return i18nString(NewFile$1);
|
|
941
|
+
};
|
|
942
|
+
const newFolder$1 = () => {
|
|
943
|
+
return i18nString(NewFolder$1);
|
|
944
|
+
};
|
|
945
|
+
const openContainingFolder$1 = () => {
|
|
946
|
+
return i18nString(OpenContainingFolder);
|
|
947
|
+
};
|
|
948
|
+
const openInIntegratedTerminal = () => {
|
|
949
|
+
return i18nString(OpenInIntegratedTerminal);
|
|
950
|
+
};
|
|
951
|
+
const cut = () => {
|
|
952
|
+
return i18nString(Cut$1);
|
|
953
|
+
};
|
|
954
|
+
const copy$1 = () => {
|
|
955
|
+
return i18nString(Copy$1);
|
|
956
|
+
};
|
|
957
|
+
const paste = () => {
|
|
958
|
+
return i18nString(Paste);
|
|
959
|
+
};
|
|
960
|
+
const copyPath$1 = () => {
|
|
961
|
+
return i18nString(CopyPath);
|
|
962
|
+
};
|
|
963
|
+
const copyRelativePath$1 = () => {
|
|
964
|
+
return i18nString(CopyRelativePath);
|
|
965
|
+
};
|
|
966
|
+
const rename$1 = () => {
|
|
967
|
+
return i18nString(Rename);
|
|
968
|
+
};
|
|
969
|
+
const deleteItem = () => {
|
|
970
|
+
return i18nString(Delete$1);
|
|
971
|
+
};
|
|
972
|
+
const refresh$1 = () => {
|
|
973
|
+
return i18nString(RefreshExplorer);
|
|
974
|
+
};
|
|
975
|
+
const collapseAll$1 = () => {
|
|
976
|
+
return i18nString(CollapseAllFoldersInExplorer);
|
|
977
|
+
};
|
|
978
|
+
const filesExplorer = () => {
|
|
979
|
+
return i18nString(FilesExplorer);
|
|
980
|
+
};
|
|
981
|
+
const youHaveNotYetOpenedAFolder = () => {
|
|
982
|
+
return i18nString(YouHaveNotYetOpenedAFolder);
|
|
983
|
+
};
|
|
984
|
+
const openFolder$1 = () => {
|
|
985
|
+
return i18nString(OpenFolder);
|
|
986
|
+
};
|
|
987
|
+
const fileOrFolderNameMustBeProvided = () => {
|
|
988
|
+
return i18nString(FileOrFolderNameMustBeProvider);
|
|
989
|
+
};
|
|
990
|
+
|
|
991
|
+
const getParentFolder = (dirents, index, root) => {
|
|
992
|
+
if (index < 0) {
|
|
993
|
+
return root;
|
|
994
|
+
}
|
|
995
|
+
return dirents[index].path;
|
|
996
|
+
};
|
|
997
|
+
const acceptCreate = async (state, newDirentType, createFn) => {
|
|
998
|
+
const {
|
|
999
|
+
focusedIndex,
|
|
1000
|
+
editingValue
|
|
1001
|
+
} = state;
|
|
1002
|
+
const newFileName = editingValue;
|
|
1003
|
+
if (!newFileName) {
|
|
1004
|
+
// TODO show error message that file name must not be empty
|
|
1005
|
+
// below input box
|
|
1006
|
+
// await ErrorHandling.showErrorDialog(new Error('file name must not be empty'))
|
|
1007
|
+
const editingErrorMessage = fileOrFolderNameMustBeProvided();
|
|
1008
|
+
return {
|
|
1009
|
+
...state,
|
|
1010
|
+
editingErrorMessage
|
|
1011
|
+
};
|
|
1012
|
+
}
|
|
1013
|
+
const parentFolder = getParentFolder(state.items, focusedIndex, state.root);
|
|
1014
|
+
const absolutePath = [parentFolder, newFileName].join(state.pathSeparator);
|
|
1015
|
+
// TODO better handle error
|
|
1016
|
+
try {
|
|
1017
|
+
await createFn(absolutePath);
|
|
1018
|
+
} catch (error) {
|
|
1019
|
+
console.error(new VError(error, `Failed to create file`));
|
|
1020
|
+
// TODO display error
|
|
1021
|
+
return state;
|
|
1022
|
+
}
|
|
1023
|
+
const parentDirent = focusedIndex >= 0 ? state.items[focusedIndex] : {
|
|
1024
|
+
depth: 0};
|
|
1025
|
+
const depth = parentDirent.depth + 1;
|
|
1026
|
+
const newDirent = {
|
|
1027
|
+
path: absolutePath,
|
|
1028
|
+
posInSet: -1,
|
|
1029
|
+
setSize: 1,
|
|
1030
|
+
depth,
|
|
1031
|
+
name: newFileName,
|
|
1032
|
+
type: newDirentType,
|
|
1033
|
+
icon: ''
|
|
1034
|
+
};
|
|
1035
|
+
newDirent.icon = '';
|
|
1036
|
+
let insertIndex = state.focusedIndex;
|
|
1037
|
+
let deltaPosInSet = 0;
|
|
1038
|
+
let posInSet = 1;
|
|
1039
|
+
let setSize = 1;
|
|
1040
|
+
let i = Math.max(state.focusedIndex, -1) + 1;
|
|
1041
|
+
const {
|
|
1042
|
+
items
|
|
1043
|
+
} = state;
|
|
1044
|
+
// TODO update posinset and setsize of all affected dirents
|
|
1045
|
+
for (; i < items.length; i++) {
|
|
1046
|
+
const dirent = items[i];
|
|
1047
|
+
if (dirent.depth !== depth) {
|
|
1048
|
+
break;
|
|
1049
|
+
}
|
|
1050
|
+
const compareResult = compareDirent(dirent, newDirent);
|
|
1051
|
+
if (compareResult === 1) {
|
|
1052
|
+
insertIndex = i - 1;
|
|
1053
|
+
deltaPosInSet = 1 - 1;
|
|
1054
|
+
break;
|
|
1055
|
+
} else {
|
|
1056
|
+
// @ts-ignore
|
|
1057
|
+
posInSet = dirent.posInSet + 1;
|
|
1058
|
+
// @ts-ignore
|
|
1059
|
+
setSize = dirent.setSize + 1;
|
|
1060
|
+
// @ts-ignore
|
|
1061
|
+
insertIndex = i;
|
|
1062
|
+
}
|
|
1063
|
+
// @ts-ignore
|
|
1064
|
+
dirent.setSize++;
|
|
1065
|
+
// @ts-ignore
|
|
1066
|
+
dirent.posInSet += deltaPosInSet;
|
|
1067
|
+
}
|
|
1068
|
+
newDirent.setSize = setSize;
|
|
1069
|
+
newDirent.posInSet = posInSet;
|
|
1070
|
+
// @ts-ignore
|
|
1071
|
+
items.splice(insertIndex + 1, 0, newDirent);
|
|
1072
|
+
const newDirents = [...items];
|
|
1073
|
+
const newMaxlineY = Math.max(state.maxLineY, newDirents.length);
|
|
1074
|
+
return {
|
|
1075
|
+
...state,
|
|
1076
|
+
items: newDirents,
|
|
1077
|
+
editingIndex: -1,
|
|
1078
|
+
focusedIndex: insertIndex + 1,
|
|
1079
|
+
editingType: None$5,
|
|
1080
|
+
maxLineY: newMaxlineY
|
|
1081
|
+
};
|
|
1082
|
+
};
|
|
1083
|
+
|
|
1084
|
+
const RendererWorker = 1;
|
|
1085
|
+
|
|
1086
|
+
const rpcs = Object.create(null);
|
|
1087
|
+
const set$1 = (id, rpc) => {
|
|
1088
|
+
rpcs[id] = rpc;
|
|
1089
|
+
};
|
|
1090
|
+
const get$1 = id => {
|
|
1091
|
+
return rpcs[id];
|
|
1092
|
+
};
|
|
1093
|
+
|
|
1094
|
+
const invoke = (method, ...params) => {
|
|
1095
|
+
const rpc = get$1(RendererWorker);
|
|
1096
|
+
// @ts-ignore
|
|
1097
|
+
return rpc.invoke(method, ...params);
|
|
1098
|
+
};
|
|
1099
|
+
|
|
1100
|
+
const remove = async dirent => {
|
|
1101
|
+
return invoke('FileSystem.remove', dirent);
|
|
1102
|
+
};
|
|
1103
|
+
const readDirWithFileTypes = async uri => {
|
|
1104
|
+
return invoke('FileSystem.readDirWithFileTypes', uri);
|
|
1105
|
+
};
|
|
1106
|
+
const getPathSeparator$1 = async root => {
|
|
1107
|
+
return invoke('FileSystem.getPathSeparator', root);
|
|
1108
|
+
};
|
|
1109
|
+
const getRealPath = async path => {
|
|
1110
|
+
return invoke('FileSystem.getRealPath', path);
|
|
1111
|
+
};
|
|
1112
|
+
const stat = async dirent => {
|
|
1113
|
+
return invoke('FileSystem.stat', dirent);
|
|
1114
|
+
};
|
|
1115
|
+
const createFile = async uri => {
|
|
1116
|
+
return invoke('FileSystem.writeFile', uri, '');
|
|
1117
|
+
};
|
|
1118
|
+
const writeFile = async (uri, content) => {
|
|
1119
|
+
return invoke('FileSystem.writeFile', uri, content);
|
|
1120
|
+
};
|
|
1121
|
+
const mkdir = async uri => {
|
|
1122
|
+
return invoke('FileSystem.mkdir', uri);
|
|
1123
|
+
};
|
|
1124
|
+
const rename = async (oldUri, newUri) => {
|
|
1125
|
+
return invoke('FileSystem.rename', oldUri, newUri);
|
|
1126
|
+
};
|
|
1127
|
+
const copy = async (oldUri, newUri) => {
|
|
1128
|
+
return invoke('FileSystem.copy', oldUri, newUri);
|
|
1129
|
+
};
|
|
1130
|
+
|
|
1131
|
+
const acceptCreateFile = async state => {
|
|
1132
|
+
return acceptCreate(state, File, createFile);
|
|
1133
|
+
};
|
|
1134
|
+
|
|
1135
|
+
const acceptCreateFolder = async state => {
|
|
1136
|
+
return acceptCreate(state, Directory, mkdir);
|
|
1137
|
+
};
|
|
1138
|
+
|
|
904
1139
|
// TODO use posInSet and setSize properties to compute more effectively
|
|
905
1140
|
const computeExplorerRenamedDirent = (dirents, index, newName) => {
|
|
906
1141
|
let startIndex = index;
|
|
@@ -996,58 +1231,6 @@ const computeExplorerRenamedDirent = (dirents, index, newName) => {
|
|
|
996
1231
|
};
|
|
997
1232
|
};
|
|
998
1233
|
|
|
999
|
-
const None$5 = 0;
|
|
1000
|
-
const CreateFile = 1;
|
|
1001
|
-
const CreateFolder = 2;
|
|
1002
|
-
const Rename$1 = 3;
|
|
1003
|
-
|
|
1004
|
-
const RendererWorker = 1;
|
|
1005
|
-
|
|
1006
|
-
const rpcs = Object.create(null);
|
|
1007
|
-
const set$1 = (id, rpc) => {
|
|
1008
|
-
rpcs[id] = rpc;
|
|
1009
|
-
};
|
|
1010
|
-
const get$1 = id => {
|
|
1011
|
-
return rpcs[id];
|
|
1012
|
-
};
|
|
1013
|
-
|
|
1014
|
-
const invoke = (method, ...params) => {
|
|
1015
|
-
const rpc = get$1(RendererWorker);
|
|
1016
|
-
// @ts-ignore
|
|
1017
|
-
return rpc.invoke(method, ...params);
|
|
1018
|
-
};
|
|
1019
|
-
|
|
1020
|
-
const remove = async dirent => {
|
|
1021
|
-
return invoke('FileSystem.remove', dirent);
|
|
1022
|
-
};
|
|
1023
|
-
const readDirWithFileTypes = async uri => {
|
|
1024
|
-
return invoke('FileSystem.readDirWithFileTypes', uri);
|
|
1025
|
-
};
|
|
1026
|
-
const getPathSeparator$1 = async root => {
|
|
1027
|
-
return invoke('FileSystem.getPathSeparator', root);
|
|
1028
|
-
};
|
|
1029
|
-
const getRealPath = async path => {
|
|
1030
|
-
return invoke('FileSystem.getRealPath', path);
|
|
1031
|
-
};
|
|
1032
|
-
const stat = async dirent => {
|
|
1033
|
-
return invoke('FileSystem.stat', dirent);
|
|
1034
|
-
};
|
|
1035
|
-
const createFile = async uri => {
|
|
1036
|
-
return invoke('FileSystem.createFile', uri);
|
|
1037
|
-
};
|
|
1038
|
-
const writeFile = async (uri, content) => {
|
|
1039
|
-
return invoke('FileSystem.writeFile', uri, content);
|
|
1040
|
-
};
|
|
1041
|
-
const mkdir = async uri => {
|
|
1042
|
-
return invoke('FileSystem.mkdir', uri);
|
|
1043
|
-
};
|
|
1044
|
-
const rename$1 = async (oldUri, newUri) => {
|
|
1045
|
-
return invoke('FileSystem.rename', oldUri, newUri);
|
|
1046
|
-
};
|
|
1047
|
-
const copy$1 = async (oldUri, newUri) => {
|
|
1048
|
-
return invoke('FileSystem.copy', oldUri, newUri);
|
|
1049
|
-
};
|
|
1050
|
-
|
|
1051
1234
|
const dirname = (pathSeparator, path) => {
|
|
1052
1235
|
const index = path.lastIndexOf(pathSeparator);
|
|
1053
1236
|
if (index === -1) {
|
|
@@ -1062,93 +1245,6 @@ const getBaseName = (pathSeparator, path) => {
|
|
|
1062
1245
|
return path.slice(path.lastIndexOf(pathSeparator) + 1);
|
|
1063
1246
|
};
|
|
1064
1247
|
|
|
1065
|
-
const getParentFolder = (dirents, index, root) => {
|
|
1066
|
-
if (index < 0) {
|
|
1067
|
-
return root;
|
|
1068
|
-
}
|
|
1069
|
-
return dirents[index].path;
|
|
1070
|
-
};
|
|
1071
|
-
const acceptCreate = async (state, newDirentType, createFn) => {
|
|
1072
|
-
const {
|
|
1073
|
-
focusedIndex,
|
|
1074
|
-
editingValue
|
|
1075
|
-
} = state;
|
|
1076
|
-
const newFileName = editingValue;
|
|
1077
|
-
if (!newFileName) {
|
|
1078
|
-
// TODO show error message that file name must not be empty
|
|
1079
|
-
// below input box
|
|
1080
|
-
// await ErrorHandling.showErrorDialog(new Error('file name must not be empty'))
|
|
1081
|
-
return state;
|
|
1082
|
-
}
|
|
1083
|
-
const parentFolder = getParentFolder(state.items, focusedIndex, state.root);
|
|
1084
|
-
const absolutePath = [parentFolder, newFileName].join(state.pathSeparator);
|
|
1085
|
-
// TODO better handle error
|
|
1086
|
-
try {
|
|
1087
|
-
await createFn(absolutePath);
|
|
1088
|
-
} catch {
|
|
1089
|
-
// TODO display error
|
|
1090
|
-
return state;
|
|
1091
|
-
}
|
|
1092
|
-
const parentDirent = focusedIndex >= 0 ? state.items[focusedIndex] : {
|
|
1093
|
-
depth: 0};
|
|
1094
|
-
const depth = parentDirent.depth + 1;
|
|
1095
|
-
const newDirent = {
|
|
1096
|
-
path: absolutePath,
|
|
1097
|
-
posInSet: -1,
|
|
1098
|
-
setSize: 1,
|
|
1099
|
-
depth,
|
|
1100
|
-
name: newFileName,
|
|
1101
|
-
type: newDirentType,
|
|
1102
|
-
icon: ''
|
|
1103
|
-
};
|
|
1104
|
-
newDirent.icon = '';
|
|
1105
|
-
let insertIndex = state.focusedIndex;
|
|
1106
|
-
let deltaPosInSet = 0;
|
|
1107
|
-
let posInSet = 1;
|
|
1108
|
-
let setSize = 1;
|
|
1109
|
-
let i = Math.max(state.focusedIndex, -1) + 1;
|
|
1110
|
-
const {
|
|
1111
|
-
items
|
|
1112
|
-
} = state;
|
|
1113
|
-
// TODO update posinset and setsize of all affected dirents
|
|
1114
|
-
for (; i < items.length; i++) {
|
|
1115
|
-
const dirent = items[i];
|
|
1116
|
-
if (dirent.depth !== depth) {
|
|
1117
|
-
break;
|
|
1118
|
-
}
|
|
1119
|
-
const compareResult = compareDirent(dirent, newDirent);
|
|
1120
|
-
if (compareResult === 1) {
|
|
1121
|
-
insertIndex = i - 1;
|
|
1122
|
-
deltaPosInSet = 1 - 1;
|
|
1123
|
-
break;
|
|
1124
|
-
} else {
|
|
1125
|
-
// @ts-ignore
|
|
1126
|
-
posInSet = dirent.posInSet + 1;
|
|
1127
|
-
// @ts-ignore
|
|
1128
|
-
setSize = dirent.setSize + 1;
|
|
1129
|
-
// @ts-ignore
|
|
1130
|
-
insertIndex = i;
|
|
1131
|
-
}
|
|
1132
|
-
// @ts-ignore
|
|
1133
|
-
dirent.setSize++;
|
|
1134
|
-
// @ts-ignore
|
|
1135
|
-
dirent.posInSet += deltaPosInSet;
|
|
1136
|
-
}
|
|
1137
|
-
newDirent.setSize = setSize;
|
|
1138
|
-
newDirent.posInSet = posInSet;
|
|
1139
|
-
// @ts-ignore
|
|
1140
|
-
items.splice(insertIndex + 1, 0, newDirent);
|
|
1141
|
-
const newDirents = [...items];
|
|
1142
|
-
const newMaxlineY = Math.max(state.maxLineY, newDirents.length);
|
|
1143
|
-
return {
|
|
1144
|
-
...state,
|
|
1145
|
-
items: newDirents,
|
|
1146
|
-
editingIndex: -1,
|
|
1147
|
-
focusedIndex: insertIndex + 1,
|
|
1148
|
-
editingType: None$5,
|
|
1149
|
-
maxLineY: newMaxlineY
|
|
1150
|
-
};
|
|
1151
|
-
};
|
|
1152
1248
|
const acceptRename = async state => {
|
|
1153
1249
|
const {
|
|
1154
1250
|
editingIndex,
|
|
@@ -1162,7 +1258,7 @@ const acceptRename = async state => {
|
|
|
1162
1258
|
const oldAbsolutePath = renamedDirent.path;
|
|
1163
1259
|
const oldParentPath = dirname(pathSeparator, oldAbsolutePath);
|
|
1164
1260
|
const newAbsolutePath = [oldParentPath, editingValue].join(pathSeparator);
|
|
1165
|
-
await rename
|
|
1261
|
+
await rename(oldAbsolutePath, newAbsolutePath);
|
|
1166
1262
|
} catch {
|
|
1167
1263
|
// TODO
|
|
1168
1264
|
// await ErrorHandling.showErrorDialog(error)
|
|
@@ -1185,15 +1281,16 @@ const acceptRename = async state => {
|
|
|
1185
1281
|
focused: true
|
|
1186
1282
|
};
|
|
1187
1283
|
};
|
|
1284
|
+
|
|
1188
1285
|
const acceptEdit = async state => {
|
|
1189
1286
|
const {
|
|
1190
1287
|
editingType
|
|
1191
1288
|
} = state;
|
|
1192
1289
|
switch (editingType) {
|
|
1193
1290
|
case CreateFile:
|
|
1194
|
-
return
|
|
1291
|
+
return acceptCreateFile(state);
|
|
1195
1292
|
case CreateFolder:
|
|
1196
|
-
return
|
|
1293
|
+
return acceptCreateFolder(state);
|
|
1197
1294
|
case Rename$1:
|
|
1198
1295
|
return acceptRename(state);
|
|
1199
1296
|
default:
|
|
@@ -1229,7 +1326,7 @@ const toCollapsedDirent = dirent => {
|
|
|
1229
1326
|
return dirent;
|
|
1230
1327
|
};
|
|
1231
1328
|
|
|
1232
|
-
const collapseAll
|
|
1329
|
+
const collapseAll = state => {
|
|
1233
1330
|
const {
|
|
1234
1331
|
items
|
|
1235
1332
|
} = state;
|
|
@@ -1250,7 +1347,7 @@ const getFocusedDirent$1 = state => {
|
|
|
1250
1347
|
return dirent;
|
|
1251
1348
|
};
|
|
1252
1349
|
|
|
1253
|
-
const copyPath
|
|
1350
|
+
const copyPath = async state => {
|
|
1254
1351
|
// await Command.execute(RendererWorkerCommandType.ClipBoardWriteText, /* text */ path)
|
|
1255
1352
|
return state;
|
|
1256
1353
|
};
|
|
@@ -1265,7 +1362,7 @@ const writeNativeFiles = async (type, files) => {
|
|
|
1265
1362
|
return invoke('ClipBoard.writeNativeFiles', type, files);
|
|
1266
1363
|
};
|
|
1267
1364
|
|
|
1268
|
-
const copyRelativePath
|
|
1365
|
+
const copyRelativePath = async state => {
|
|
1269
1366
|
const dirent = getFocusedDirent$1(state);
|
|
1270
1367
|
const relativePath = dirent.path.slice(1);
|
|
1271
1368
|
// TODO handle error
|
|
@@ -1318,7 +1415,8 @@ const create2 = (uid, uri, x, y, width, height, args, parentUid, platform = 0) =
|
|
|
1318
1415
|
useChevrons: false,
|
|
1319
1416
|
icons: [],
|
|
1320
1417
|
platform,
|
|
1321
|
-
focus: 0
|
|
1418
|
+
focus: 0,
|
|
1419
|
+
editingErrorMessage: ''
|
|
1322
1420
|
};
|
|
1323
1421
|
set(uid, state, state);
|
|
1324
1422
|
};
|
|
@@ -1353,7 +1451,8 @@ const create = (id, uri, x, y, width, height, args, parentUid, platform = 0) =>
|
|
|
1353
1451
|
useChevrons: false,
|
|
1354
1452
|
icons: [],
|
|
1355
1453
|
platform,
|
|
1356
|
-
focus: 0
|
|
1454
|
+
focus: 0,
|
|
1455
|
+
editingErrorMessage: ''
|
|
1357
1456
|
};
|
|
1358
1457
|
set(state.uid, state, state);
|
|
1359
1458
|
return state;
|
|
@@ -1376,7 +1475,7 @@ const DiffEditingIndex = {
|
|
|
1376
1475
|
|
|
1377
1476
|
const diffType$1 = RenderFocus;
|
|
1378
1477
|
const isEqual$2 = (oldState, newState) => {
|
|
1379
|
-
return oldState.focused === newState.focused;
|
|
1478
|
+
return oldState.focused === newState.focused && oldState.focus === newState.focus;
|
|
1380
1479
|
};
|
|
1381
1480
|
|
|
1382
1481
|
const DiffFocus = {
|
|
@@ -1387,7 +1486,7 @@ const DiffFocus = {
|
|
|
1387
1486
|
|
|
1388
1487
|
const diffType = RenderItems;
|
|
1389
1488
|
const isEqual$1 = (oldState, newState) => {
|
|
1390
|
-
return oldState.items === newState.items && oldState.minLineY === newState.minLineY && oldState.maxLineY === newState.maxLineY && oldState.focusedIndex === newState.focusedIndex && oldState.editingIndex === newState.editingIndex && oldState.editingType === newState.editingType && oldState.editingValue === newState.editingValue && oldState.width === newState.width && oldState.focused === newState.focused && oldState.dropTargets === newState.dropTargets;
|
|
1489
|
+
return oldState.items === newState.items && oldState.minLineY === newState.minLineY && oldState.maxLineY === newState.maxLineY && oldState.focusedIndex === newState.focusedIndex && oldState.editingIndex === newState.editingIndex && oldState.editingType === newState.editingType && oldState.editingValue === newState.editingValue && oldState.editingErrorMessage === newState.editingErrorMessage && oldState.width === newState.width && oldState.focused === newState.focused && oldState.dropTargets === newState.dropTargets;
|
|
1391
1490
|
};
|
|
1392
1491
|
|
|
1393
1492
|
const DiffItems = {
|
|
@@ -1862,7 +1961,7 @@ const LeftArrow = 13;
|
|
|
1862
1961
|
const UpArrow = 14;
|
|
1863
1962
|
const RightArrow = 15;
|
|
1864
1963
|
const DownArrow = 16;
|
|
1865
|
-
const Delete
|
|
1964
|
+
const Delete = 18;
|
|
1866
1965
|
const KeyC = 31;
|
|
1867
1966
|
const KeyV = 50;
|
|
1868
1967
|
const F2 = 58;
|
|
@@ -1932,7 +2031,7 @@ const getKeyBindings = () => {
|
|
|
1932
2031
|
command: 'Explorer.acceptEdit',
|
|
1933
2032
|
when: FocusExplorerEditBox
|
|
1934
2033
|
}, {
|
|
1935
|
-
key: Delete
|
|
2034
|
+
key: Delete,
|
|
1936
2035
|
command: 'Explorer.removeDirent',
|
|
1937
2036
|
when: FocusExplorer
|
|
1938
2037
|
}, {
|
|
@@ -1950,84 +2049,6 @@ const getKeyBindings = () => {
|
|
|
1950
2049
|
}];
|
|
1951
2050
|
};
|
|
1952
2051
|
|
|
1953
|
-
const emptyObject = {};
|
|
1954
|
-
const RE_PLACEHOLDER = /\{(PH\d+)\}/g;
|
|
1955
|
-
const i18nString = (key, placeholders = emptyObject) => {
|
|
1956
|
-
if (placeholders === emptyObject) {
|
|
1957
|
-
return key;
|
|
1958
|
-
}
|
|
1959
|
-
const replacer = (match, rest) => {
|
|
1960
|
-
return placeholders[rest];
|
|
1961
|
-
};
|
|
1962
|
-
return key.replaceAll(RE_PLACEHOLDER, replacer);
|
|
1963
|
-
};
|
|
1964
|
-
|
|
1965
|
-
const NewFile$1 = 'New File...';
|
|
1966
|
-
const NewFolder$1 = 'New Folder...';
|
|
1967
|
-
const OpenContainingFolder = 'Open Containing Folder';
|
|
1968
|
-
const OpenInIntegratedTerminal = 'Open in integrated Terminal';
|
|
1969
|
-
const Cut$1 = 'Cut';
|
|
1970
|
-
const Copy$1 = 'Copy';
|
|
1971
|
-
const Paste = 'Paste';
|
|
1972
|
-
const CopyPath = 'Copy Path';
|
|
1973
|
-
const CopyRelativePath = 'Copy Relative Path';
|
|
1974
|
-
const Rename = 'Rename';
|
|
1975
|
-
const Delete = 'Delete';
|
|
1976
|
-
const RefreshExplorer = 'Refresh Explorer';
|
|
1977
|
-
const CollapseAllFoldersInExplorer = 'Collapse All Folders in Explorer';
|
|
1978
|
-
const FilesExplorer = 'Files Explorer';
|
|
1979
|
-
const YouHaveNotYetOpenedAFolder = 'You have not yet opened a folder';
|
|
1980
|
-
const OpenFolder = 'Open folder';
|
|
1981
|
-
|
|
1982
|
-
const newFile$1 = () => {
|
|
1983
|
-
return i18nString(NewFile$1);
|
|
1984
|
-
};
|
|
1985
|
-
const newFolder$1 = () => {
|
|
1986
|
-
return i18nString(NewFolder$1);
|
|
1987
|
-
};
|
|
1988
|
-
const openContainingFolder$1 = () => {
|
|
1989
|
-
return i18nString(OpenContainingFolder);
|
|
1990
|
-
};
|
|
1991
|
-
const openInIntegratedTerminal = () => {
|
|
1992
|
-
return i18nString(OpenInIntegratedTerminal);
|
|
1993
|
-
};
|
|
1994
|
-
const cut = () => {
|
|
1995
|
-
return i18nString(Cut$1);
|
|
1996
|
-
};
|
|
1997
|
-
const copy = () => {
|
|
1998
|
-
return i18nString(Copy$1);
|
|
1999
|
-
};
|
|
2000
|
-
const paste = () => {
|
|
2001
|
-
return i18nString(Paste);
|
|
2002
|
-
};
|
|
2003
|
-
const copyPath = () => {
|
|
2004
|
-
return i18nString(CopyPath);
|
|
2005
|
-
};
|
|
2006
|
-
const copyRelativePath = () => {
|
|
2007
|
-
return i18nString(CopyRelativePath);
|
|
2008
|
-
};
|
|
2009
|
-
const rename = () => {
|
|
2010
|
-
return i18nString(Rename);
|
|
2011
|
-
};
|
|
2012
|
-
const deleteItem = () => {
|
|
2013
|
-
return i18nString(Delete);
|
|
2014
|
-
};
|
|
2015
|
-
const refresh$1 = () => {
|
|
2016
|
-
return i18nString(RefreshExplorer);
|
|
2017
|
-
};
|
|
2018
|
-
const collapseAll = () => {
|
|
2019
|
-
return i18nString(CollapseAllFoldersInExplorer);
|
|
2020
|
-
};
|
|
2021
|
-
const filesExplorer = () => {
|
|
2022
|
-
return i18nString(FilesExplorer);
|
|
2023
|
-
};
|
|
2024
|
-
const youHaveNotYetOpenedAFolder = () => {
|
|
2025
|
-
return i18nString(YouHaveNotYetOpenedAFolder);
|
|
2026
|
-
};
|
|
2027
|
-
const openFolder$1 = () => {
|
|
2028
|
-
return i18nString(OpenFolder);
|
|
2029
|
-
};
|
|
2030
|
-
|
|
2031
2052
|
const Separator = 1;
|
|
2032
2053
|
const None$4 = 0;
|
|
2033
2054
|
const RestoreFocus = 6;
|
|
@@ -2071,7 +2092,7 @@ const menuEntryCut = {
|
|
|
2071
2092
|
};
|
|
2072
2093
|
const menuEntryCopy = {
|
|
2073
2094
|
id: 'copy',
|
|
2074
|
-
label: copy(),
|
|
2095
|
+
label: copy$1(),
|
|
2075
2096
|
flags: RestoreFocus,
|
|
2076
2097
|
command: 'Explorer.handleCopy'
|
|
2077
2098
|
};
|
|
@@ -2083,19 +2104,19 @@ const menuEntryPaste = {
|
|
|
2083
2104
|
};
|
|
2084
2105
|
const menuEntryCopyPath = {
|
|
2085
2106
|
id: 'copyPath',
|
|
2086
|
-
label: copyPath(),
|
|
2107
|
+
label: copyPath$1(),
|
|
2087
2108
|
flags: RestoreFocus,
|
|
2088
2109
|
command: 'Explorer.copyPath'
|
|
2089
2110
|
};
|
|
2090
2111
|
const menuEntryCopyRelativePath = {
|
|
2091
2112
|
id: 'copyRelativePath',
|
|
2092
|
-
label: copyRelativePath(),
|
|
2113
|
+
label: copyRelativePath$1(),
|
|
2093
2114
|
flags: RestoreFocus,
|
|
2094
2115
|
command: 'Explorer.copyRelativePath'
|
|
2095
2116
|
};
|
|
2096
2117
|
const menuEntryRename = {
|
|
2097
2118
|
id: 'rename',
|
|
2098
|
-
label: rename(),
|
|
2119
|
+
label: rename$1(),
|
|
2099
2120
|
flags: None$4,
|
|
2100
2121
|
command: 'Explorer.renameDirent'
|
|
2101
2122
|
};
|
|
@@ -2569,7 +2590,7 @@ const handleCopy = async state => {
|
|
|
2569
2590
|
// TODO if not file is selected, what happens?
|
|
2570
2591
|
const dirent = getFocusedDirent$1(state);
|
|
2571
2592
|
if (!dirent) {
|
|
2572
|
-
console.
|
|
2593
|
+
console.error('[ViewletExplorer/handleCopy] no dirent selected');
|
|
2573
2594
|
return state;
|
|
2574
2595
|
}
|
|
2575
2596
|
const absolutePath = dirent.path;
|
|
@@ -2689,7 +2710,7 @@ const applyOperation = operation => {
|
|
|
2689
2710
|
return mkdir(operation.path);
|
|
2690
2711
|
}
|
|
2691
2712
|
if (operation.type === 'copy') {
|
|
2692
|
-
return copy
|
|
2713
|
+
return copy(operation.from || '', operation.path);
|
|
2693
2714
|
}
|
|
2694
2715
|
return writeFile(operation.path, operation.text);
|
|
2695
2716
|
};
|
|
@@ -2724,7 +2745,9 @@ const isFileHandle = fileHandle => {
|
|
|
2724
2745
|
const createUploadTree = async (root, fileHandles) => {
|
|
2725
2746
|
const uploadTree = Object.create(null);
|
|
2726
2747
|
for (const fileHandle of fileHandles) {
|
|
2727
|
-
const
|
|
2748
|
+
const {
|
|
2749
|
+
name
|
|
2750
|
+
} = fileHandle;
|
|
2728
2751
|
if (isDirectoryHandle(fileHandle)) {
|
|
2729
2752
|
const children = await getChildHandles(fileHandle);
|
|
2730
2753
|
const childTree = await createUploadTree(name, children);
|
|
@@ -2812,7 +2835,9 @@ const getFileOperationsElectron = async (root, paths, fileHandles) => {
|
|
|
2812
2835
|
const operations = [];
|
|
2813
2836
|
for (let i = 0; i < paths.length; i++) {
|
|
2814
2837
|
const fileHandle = fileHandles[i];
|
|
2815
|
-
const
|
|
2838
|
+
const {
|
|
2839
|
+
name
|
|
2840
|
+
} = fileHandle;
|
|
2816
2841
|
const path = paths[i];
|
|
2817
2842
|
operations.push({
|
|
2818
2843
|
type: 'copy',
|
|
@@ -2898,7 +2923,7 @@ const handleDropIntoFolder = async (state, dirent, index, fileHandles, files, pa
|
|
|
2898
2923
|
const baseName = file.name;
|
|
2899
2924
|
const to = dirent.path + pathSeparator + baseName;
|
|
2900
2925
|
// @ts-ignore
|
|
2901
|
-
await copy
|
|
2926
|
+
await copy(file, to);
|
|
2902
2927
|
}
|
|
2903
2928
|
const childDirents = await getChildDirents(pathSeparator, dirent);
|
|
2904
2929
|
const mergedDirents = getMergedDirents(items, index, dirent, childDirents);
|
|
@@ -3051,7 +3076,7 @@ const handlePasteCopy = async (state, nativeFiles) => {
|
|
|
3051
3076
|
for (const source of nativeFiles.files) {
|
|
3052
3077
|
// @ts-ignore
|
|
3053
3078
|
const target = join(state.pathSeperator, state.root, getBaseName(state.pathSeparator, source));
|
|
3054
|
-
await copy
|
|
3079
|
+
await copy(source, target);
|
|
3055
3080
|
}
|
|
3056
3081
|
// TODO only update folder at which level it changed
|
|
3057
3082
|
return updateRoot(state);
|
|
@@ -3060,13 +3085,13 @@ const handlePasteCopy = async (state, nativeFiles) => {
|
|
|
3060
3085
|
const handlePasteCut = async (state, nativeFiles) => {
|
|
3061
3086
|
for (const source of nativeFiles.files) {
|
|
3062
3087
|
const target = `${state.root}${state.pathSeparator}${getBaseName(state.pathSeparator, source)}`;
|
|
3063
|
-
await rename
|
|
3088
|
+
await rename(source, target);
|
|
3064
3089
|
}
|
|
3065
3090
|
return state;
|
|
3066
3091
|
};
|
|
3067
3092
|
|
|
3068
3093
|
const handlePasteNone = async (state, nativeFiles) => {
|
|
3069
|
-
console.
|
|
3094
|
+
console.error('[ViewletExplorer/handlePaste] no paths detected');
|
|
3070
3095
|
return state;
|
|
3071
3096
|
};
|
|
3072
3097
|
|
|
@@ -3370,6 +3395,8 @@ const handleWorkspaceChange = async state => {
|
|
|
3370
3395
|
return newState;
|
|
3371
3396
|
};
|
|
3372
3397
|
|
|
3398
|
+
const Input$1 = 2;
|
|
3399
|
+
|
|
3373
3400
|
const ExplorerEditBox = FocusExplorerEditBox;
|
|
3374
3401
|
|
|
3375
3402
|
const newDirent = async (state, editingType) => {
|
|
@@ -3392,7 +3419,8 @@ const newDirent = async (state, editingType) => {
|
|
|
3392
3419
|
...state,
|
|
3393
3420
|
editingIndex: focusedIndex,
|
|
3394
3421
|
editingType,
|
|
3395
|
-
editingValue: ''
|
|
3422
|
+
editingValue: '',
|
|
3423
|
+
focus: Input$1
|
|
3396
3424
|
};
|
|
3397
3425
|
};
|
|
3398
3426
|
|
|
@@ -3507,7 +3535,12 @@ const renderEditingIndex = (oldState, newState) => {
|
|
|
3507
3535
|
return ['focusInput', 'ExplorerInput'];
|
|
3508
3536
|
};
|
|
3509
3537
|
|
|
3538
|
+
const ExplorerInput = 'ExplorerInput';
|
|
3539
|
+
|
|
3510
3540
|
const renderFocus = (oldState, newState) => {
|
|
3541
|
+
if (newState.focus === Input$1) {
|
|
3542
|
+
return ['Viewlet.focusElementByName', ExplorerInput];
|
|
3543
|
+
}
|
|
3511
3544
|
// TODO
|
|
3512
3545
|
// 1. when focused, focus the outer list element
|
|
3513
3546
|
// 2. when focused, set focus context in renderer worker
|
|
@@ -3525,13 +3558,14 @@ const ButtonNarrow = 'ButtonNarrow';
|
|
|
3525
3558
|
const ButtonPrimary = 'ButtonPrimary';
|
|
3526
3559
|
const ButtonWide = 'ButtonWide';
|
|
3527
3560
|
const Chevron = 'Chevron';
|
|
3528
|
-
const Explorer = 'Explorer';
|
|
3529
3561
|
const Empty = '';
|
|
3562
|
+
const Explorer = 'Explorer';
|
|
3530
3563
|
const ExplorerDropTarget = 'DropTarget';
|
|
3531
3564
|
const FileIcon = 'FileIcon';
|
|
3532
3565
|
const FocusOutline = 'FocusOutline';
|
|
3533
3566
|
const IconButton = 'IconButton';
|
|
3534
3567
|
const InputBox = 'InputBox';
|
|
3568
|
+
const InputValidationError = 'InputValidationError';
|
|
3535
3569
|
const Label = 'Label';
|
|
3536
3570
|
const MaskIconChevronDown = 'MaskIconChevronDown';
|
|
3537
3571
|
const MaskIconChevronRight = 'MaskIconChevronRight';
|
|
@@ -3610,18 +3644,22 @@ const getFileIconVirtualDom = icon => {
|
|
|
3610
3644
|
};
|
|
3611
3645
|
};
|
|
3612
3646
|
|
|
3613
|
-
const ExplorerInput = 'ExplorerInput';
|
|
3614
|
-
|
|
3615
3647
|
const label = {
|
|
3616
3648
|
type: Div,
|
|
3617
3649
|
className: Label,
|
|
3618
3650
|
childCount: 1
|
|
3619
3651
|
};
|
|
3620
|
-
const
|
|
3652
|
+
const getClassName$1 = hasEditingError => {
|
|
3653
|
+
if (hasEditingError) {
|
|
3654
|
+
return mergeClassNames(InputBox, InputValidationError);
|
|
3655
|
+
}
|
|
3656
|
+
return InputBox;
|
|
3657
|
+
};
|
|
3658
|
+
const getInputOrLabelDom = (isEditing, hasEditingError, name) => {
|
|
3621
3659
|
if (isEditing) {
|
|
3622
3660
|
return [{
|
|
3623
3661
|
type: Input,
|
|
3624
|
-
className:
|
|
3662
|
+
className: getClassName$1(hasEditingError),
|
|
3625
3663
|
id: 'ExplorerInput',
|
|
3626
3664
|
onInput: HandleEditingInput,
|
|
3627
3665
|
childCount: 0,
|
|
@@ -3644,7 +3682,8 @@ const getExplorerItemVirtualDom = item => {
|
|
|
3644
3682
|
id,
|
|
3645
3683
|
className,
|
|
3646
3684
|
isEditing,
|
|
3647
|
-
ariaExpanded
|
|
3685
|
+
ariaExpanded,
|
|
3686
|
+
hasEditingError
|
|
3648
3687
|
} = item;
|
|
3649
3688
|
const chevronDom = getChevronVirtualDom(chevron);
|
|
3650
3689
|
const dom = [{
|
|
@@ -3662,7 +3701,7 @@ const getExplorerItemVirtualDom = item => {
|
|
|
3662
3701
|
ariaExpanded,
|
|
3663
3702
|
ariaDescription: '',
|
|
3664
3703
|
id
|
|
3665
|
-
}, ...chevronDom, getFileIconVirtualDom(icon), ...getInputOrLabelDom(isEditing, name)];
|
|
3704
|
+
}, ...chevronDom, getFileIconVirtualDom(icon), ...getInputOrLabelDom(isEditing, hasEditingError, name)];
|
|
3666
3705
|
return dom;
|
|
3667
3706
|
};
|
|
3668
3707
|
|
|
@@ -3778,7 +3817,7 @@ const getTreeItemIndentWithChevron = (depth, chevron) => {
|
|
|
3778
3817
|
};
|
|
3779
3818
|
|
|
3780
3819
|
const ariaExpandedValues = [undefined, 'true', 'false'];
|
|
3781
|
-
const getVisibleExplorerItems = (items, minLineY, maxLineY, focusedIndex, editingIndex, editingType, editingValue, icons, useChevrons, dropTargets) => {
|
|
3820
|
+
const getVisibleExplorerItems = (items, minLineY, maxLineY, focusedIndex, editingIndex, editingType, editingValue, editingErrorMessage, icons, useChevrons, dropTargets) => {
|
|
3782
3821
|
const visible = [];
|
|
3783
3822
|
const indentFn = useChevrons ? getTreeItemIndentWithChevron : getTreeItemIndent;
|
|
3784
3823
|
let iconIndex = 0;
|
|
@@ -3795,6 +3834,7 @@ const getVisibleExplorerItems = (items, minLineY, maxLineY, focusedIndex, editin
|
|
|
3795
3834
|
visible.push({
|
|
3796
3835
|
...item,
|
|
3797
3836
|
isEditing: i === editingIndex,
|
|
3837
|
+
hasEditingError: i === editingIndex && Boolean(editingErrorMessage),
|
|
3798
3838
|
icon,
|
|
3799
3839
|
indent,
|
|
3800
3840
|
ariaExpanded,
|
|
@@ -3812,6 +3852,7 @@ const getVisibleExplorerItems = (items, minLineY, maxLineY, focusedIndex, editin
|
|
|
3812
3852
|
name: 'new',
|
|
3813
3853
|
path: '/test/new',
|
|
3814
3854
|
isEditing: true,
|
|
3855
|
+
hasEditingError: Boolean(editingErrorMessage),
|
|
3815
3856
|
indent: '',
|
|
3816
3857
|
ariaExpanded: undefined,
|
|
3817
3858
|
chevron: 0,
|
|
@@ -3823,7 +3864,7 @@ const getVisibleExplorerItems = (items, minLineY, maxLineY, focusedIndex, editin
|
|
|
3823
3864
|
};
|
|
3824
3865
|
|
|
3825
3866
|
const renderItems = (oldState, newState) => {
|
|
3826
|
-
const visibleDirents = getVisibleExplorerItems(newState.items, newState.minLineY, newState.maxLineY, newState.focusedIndex, newState.editingIndex, newState.editingType, newState.editingValue, newState.icons, newState.useChevrons);
|
|
3867
|
+
const visibleDirents = getVisibleExplorerItems(newState.items, newState.minLineY, newState.maxLineY, newState.focusedIndex, newState.editingIndex, newState.editingType, newState.editingValue, newState.editingErrorMessage, newState.icons, newState.useChevrons);
|
|
3827
3868
|
const isWide = newState.width > 450;
|
|
3828
3869
|
const dom = getExplorerVirtualDom(visibleDirents, newState.focusedIndex, newState.root, isWide, newState.focused, newState.dropTargets);
|
|
3829
3870
|
return ['Viewlet.setDom2', dom];
|
|
@@ -3892,7 +3933,7 @@ const getActions = root => {
|
|
|
3892
3933
|
command: 'refresh'
|
|
3893
3934
|
}, {
|
|
3894
3935
|
type: Button,
|
|
3895
|
-
id: collapseAll(),
|
|
3936
|
+
id: collapseAll$1(),
|
|
3896
3937
|
icon: CollapseAll,
|
|
3897
3938
|
command: 'collapseAll'
|
|
3898
3939
|
}];
|
|
@@ -4265,7 +4306,9 @@ const isExpandedDirectory = dirent => {
|
|
|
4265
4306
|
const saveState = uid => {
|
|
4266
4307
|
number(uid);
|
|
4267
4308
|
const value = get(uid);
|
|
4268
|
-
const
|
|
4309
|
+
const {
|
|
4310
|
+
newState
|
|
4311
|
+
} = value;
|
|
4269
4312
|
const {
|
|
4270
4313
|
items,
|
|
4271
4314
|
root,
|
|
@@ -4315,9 +4358,9 @@ const commandMap = {
|
|
|
4315
4358
|
'Explorer.getMenuEntries2': getMenuEntries2,
|
|
4316
4359
|
'Explorer.acceptEdit': wrapCommand(acceptEdit),
|
|
4317
4360
|
'Explorer.cancelEdit': wrapCommand(cancelEdit),
|
|
4318
|
-
'Explorer.collapseAll': wrapCommand(collapseAll
|
|
4319
|
-
'Explorer.copyPath': wrapCommand(copyPath
|
|
4320
|
-
'Explorer.copyRelativePath': wrapCommand(copyRelativePath
|
|
4361
|
+
'Explorer.collapseAll': wrapCommand(collapseAll),
|
|
4362
|
+
'Explorer.copyPath': wrapCommand(copyPath),
|
|
4363
|
+
'Explorer.copyRelativePath': wrapCommand(copyRelativePath),
|
|
4321
4364
|
'Explorer.expandAll': wrapCommand(expandAll),
|
|
4322
4365
|
'Explorer.expandRecursively': wrapCommand(expandRecursively),
|
|
4323
4366
|
'Explorer.focusFirst': wrapCommand(focusFirst),
|