@lvce-editor/explorer-view 7.8.0 → 7.9.1

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.
@@ -3,10 +3,67 @@ const toCommandId = key => {
3
3
  return key.slice(dotIndex + 1);
4
4
  };
5
5
  const create$a = () => {
6
+ const commandQueues = new Map();
7
+ const generations = Object.create(null);
6
8
  const states = Object.create(null);
7
9
  const commandMapRef = {};
10
+ const getGeneration = uid => generations[uid] || 0;
11
+ const isCurrentGeneration = (uid, generation) => {
12
+ return states[uid] !== undefined && getGeneration(uid) === generation;
13
+ };
14
+ const updateState = (uid, generation, fallbackState, updater) => {
15
+ if (!isCurrentGeneration(uid, generation)) {
16
+ return Promise.resolve(fallbackState);
17
+ }
18
+ const current = states[uid];
19
+ const updatedState = updater(current.newState);
20
+ if (updatedState !== current.newState) {
21
+ states[uid] = {
22
+ newState: updatedState,
23
+ oldState: current.oldState,
24
+ scheduledState: updatedState
25
+ };
26
+ }
27
+ return Promise.resolve(updatedState);
28
+ };
29
+ const createAsyncCommandContext = (uid, generation) => {
30
+ let latestState = states[uid].newState;
31
+ return {
32
+ getState: () => {
33
+ if (isCurrentGeneration(uid, generation)) {
34
+ latestState = states[uid].newState;
35
+ }
36
+ return latestState;
37
+ },
38
+ updateState: async updater => {
39
+ latestState = await updateState(uid, generation, latestState, updater);
40
+ return latestState;
41
+ }
42
+ };
43
+ };
44
+ const enqueueCommand = async (uid, command) => {
45
+ const previous = commandQueues.get(uid) || Promise.resolve();
46
+ const run = async () => {
47
+ try {
48
+ await previous;
49
+ } catch {
50
+ // The previous caller receives its error; later commands must still run.
51
+ }
52
+ await command();
53
+ };
54
+ const current = run();
55
+ commandQueues.set(uid, current);
56
+ try {
57
+ await current;
58
+ } finally {
59
+ if (commandQueues.get(uid) === current) {
60
+ commandQueues.delete(uid);
61
+ }
62
+ }
63
+ };
8
64
  return {
9
65
  clear() {
66
+ commandQueues.clear();
10
67
  for (const key of Object.keys(states)) {
11
68
  delete states[key];
12
69
  }
@@ -26,6 +83,7 @@ const create$a = () => {
26
83
  return diffResult;
27
84
  },
28
85
  dispose(uid) {
86
+ commandQueues.delete(uid);
29
87
  delete states[uid];
30
88
  },
31
89
  get(uid) {
@@ -43,14 +101,27 @@ const create$a = () => {
43
101
  Object.assign(commandMapRef, commandMap);
44
102
  },
45
103
  set(uid, oldState, newState, scheduledState) {
104
+ const current = states[uid];
105
+ if (!current || oldState === newState && newState !== current.newState) {
106
+ generations[uid] = getGeneration(uid) + 1;
107
+ }
46
108
  states[uid] = {
47
109
  newState,
48
110
  oldState,
49
111
  scheduledState: scheduledState ?? newState
50
112
  };
51
113
  },
114
+ wrapAsyncCommand(fn) {
115
+ const wrapped = async (uid, ...args) => {
116
+ const generation = getGeneration(uid);
117
+ const context = createAsyncCommandContext(uid, generation);
118
+ await fn(context, ...args);
119
+ };
120
+ return wrapped;
121
+ },
52
122
  wrapCommand(fn) {
53
123
  const wrapped = async (uid, ...args) => {
124
+ const generation = getGeneration(uid);
54
125
  const {
55
126
  newState,
56
127
  oldState
@@ -59,6 +130,9 @@ const create$a = () => {
59
130
  if (oldState === newerState || newState === newerState) {
60
131
  return;
61
132
  }
133
+ if (!isCurrentGeneration(uid, generation)) {
134
+ return;
135
+ }
62
136
  const latestOld = states[uid];
63
137
  const latestNew = {
64
138
  ...latestOld.newState,
@@ -83,6 +157,7 @@ const create$a = () => {
83
157
  },
84
158
  wrapLoadContent(fn) {
85
159
  const wrapped = async (uid, ...args) => {
160
+ const generation = getGeneration(uid);
86
161
  const {
87
162
  newState,
88
163
  oldState
@@ -97,6 +172,11 @@ const create$a = () => {
97
172
  error
98
173
  };
99
174
  }
175
+ if (!isCurrentGeneration(uid, generation)) {
176
+ return {
177
+ error
178
+ };
179
+ }
100
180
  const latestOld = states[uid];
101
181
  const latestNew = {
102
182
  ...latestOld.newState,
@@ -112,6 +192,51 @@ const create$a = () => {
112
192
  };
113
193
  };
114
194
  return wrapped;
195
+ },
196
+ wrapSerialAsyncCommand(fn) {
197
+ const wrapped = async (uid, ...args) => {
198
+ await enqueueCommand(uid, async () => {
199
+ if (!states[uid]) {
200
+ return;
201
+ }
202
+ const generation = getGeneration(uid);
203
+ const context = createAsyncCommandContext(uid, generation);
204
+ await fn(context, ...args);
205
+ });
206
+ };
207
+ return wrapped;
208
+ },
209
+ wrapSerialCommand(fn) {
210
+ const wrapped = async (uid, ...args) => {
211
+ await enqueueCommand(uid, async () => {
212
+ if (!states[uid]) {
213
+ return;
214
+ }
215
+ const generation = getGeneration(uid);
216
+ const {
217
+ newState,
218
+ oldState
219
+ } = states[uid];
220
+ const newerState = await fn(newState, ...args);
221
+ if (oldState === newerState || newState === newerState) {
222
+ return;
223
+ }
224
+ if (!isCurrentGeneration(uid, generation)) {
225
+ return;
226
+ }
227
+ const latestOld = states[uid];
228
+ const latestNew = {
229
+ ...latestOld.newState,
230
+ ...newerState
231
+ };
232
+ states[uid] = {
233
+ newState: latestNew,
234
+ oldState: latestOld.oldState,
235
+ scheduledState: latestNew
236
+ };
237
+ });
238
+ };
239
+ return wrapped;
115
240
  }
116
241
  };
117
242
  };
@@ -284,7 +409,6 @@ const walkValue = (value, transferrables, isTransferrable) => {
284
409
  for (const property of Object.values(value)) {
285
410
  walkValue(property, transferrables, isTransferrable);
286
411
  }
287
- return;
288
412
  }
289
413
  };
290
414
  const getTransferrables = value => {
@@ -438,7 +562,14 @@ class IpcError extends VError {
438
562
  const cause = new Error(message);
439
563
  // @ts-ignore
440
564
  cause.code = code;
441
- cause.stack = stack;
565
+ if (stack) {
566
+ Object.defineProperty(cause, 'stack', {
567
+ configurable: true,
568
+ enumerable: false,
569
+ value: stack,
570
+ writable: true
571
+ });
572
+ }
442
573
  super(cause, betterMessage);
443
574
  } else {
444
575
  super(betterMessage);
@@ -725,7 +856,10 @@ const constructError = (message, type, name) => {
725
856
  if (ErrorConstructor === Error) {
726
857
  const error = new Error(message);
727
858
  if (name && name !== 'VError') {
728
- error.name = name;
859
+ Object.defineProperty(error, 'name', {
860
+ configurable: true,
861
+ value: name
862
+ });
729
863
  }
730
864
  return error;
731
865
  }
@@ -742,8 +876,10 @@ const getCurrentStack = () => {
742
876
  const currentStack = joinLines(splitLines(new Error().stack || '').slice(stackLinesToSkip));
743
877
  return currentStack;
744
878
  };
745
- const getNewLineIndex = (string, startIndex = undefined) => {
746
- return string.indexOf(NewLine, startIndex);
879
+ const getNewLineIndex = (string, startIndex) => {
880
+ {
881
+ return string.indexOf(NewLine);
882
+ }
747
883
  };
748
884
  const getParentStack = error => {
749
885
  let parentStack = error.stack || error.data || error.message || '';
@@ -754,55 +890,91 @@ const getParentStack = error => {
754
890
  };
755
891
  const MethodNotFound = -32601;
756
892
  const Custom = -32001;
893
+ const setStack = (error, stack) => {
894
+ const descriptor = Object.getOwnPropertyDescriptor(error, 'stack');
895
+ if (descriptor) {
896
+ if (!descriptor.configurable && !descriptor.writable) {
897
+ return;
898
+ }
899
+ if (!descriptor.configurable && descriptor.writable) {
900
+ error.stack = stack;
901
+ return;
902
+ }
903
+ }
904
+ Object.defineProperty(error, 'stack', {
905
+ configurable: true,
906
+ value: stack,
907
+ writable: true
908
+ });
909
+ };
910
+ const restoreExistingError = (error, currentStack) => {
911
+ if (typeof error.stack === 'string') {
912
+ setStack(error, `${error.stack}${NewLine}${currentStack}`);
913
+ }
914
+ return error;
915
+ };
916
+ const restoreMethodNotFoundError = (error, currentStack) => {
917
+ const restoredError = new JsonRpcError(error.message);
918
+ const parentStack = getParentStack(error);
919
+ setStack(restoredError, `${parentStack}${NewLine}${currentStack}`);
920
+ return restoredError;
921
+ };
922
+ const restoreStackFromData = (restoredError, error, currentStack) => {
923
+ if (error.data.stack && error.data.type && error.message) {
924
+ setStack(restoredError, `${error.data.type}: ${error.message}${NewLine}${error.data.stack}${NewLine}${currentStack}`);
925
+ return;
926
+ }
927
+ if (error.data.stack) {
928
+ setStack(restoredError, error.data.stack);
929
+ }
930
+ };
931
+ const applyDataProperties = (restoredError, error) => {
932
+ restoreStackFromData(restoredError, error, getCurrentStack());
933
+ if (error.data.codeFrame) {
934
+ // @ts-ignore
935
+ restoredError.codeFrame = error.data.codeFrame;
936
+ }
937
+ if (error.data.code) {
938
+ // @ts-ignore
939
+ restoredError.code = error.data.code;
940
+ }
941
+ if (error.data.type) {
942
+ // @ts-ignore
943
+ restoredError.name = error.data.type;
944
+ }
945
+ };
946
+ const applyDirectProperties = (restoredError, error) => {
947
+ if (error.stack) {
948
+ const lowerStack = restoredError.stack || '';
949
+ const indexNewLine = getNewLineIndex(lowerStack);
950
+ const parentStack = getParentStack(error);
951
+ // @ts-ignore
952
+ setStack(restoredError, `${parentStack}${lowerStack.slice(indexNewLine)}`);
953
+ }
954
+ if (error.codeFrame) {
955
+ // @ts-ignore
956
+ restoredError.codeFrame = error.codeFrame;
957
+ }
958
+ };
959
+ const restoreMessageError = (error, _currentStack) => {
960
+ const restoredError = constructError(error.message, error.type, error.name);
961
+ if (error.data) {
962
+ applyDataProperties(restoredError, error);
963
+ } else {
964
+ applyDirectProperties(restoredError, error);
965
+ }
966
+ return restoredError;
967
+ };
757
968
  const restoreJsonRpcError = error => {
758
969
  const currentStack = getCurrentStack();
759
970
  if (error && error instanceof Error) {
760
- if (typeof error.stack === 'string') {
761
- error.stack = error.stack + NewLine + currentStack;
762
- }
763
- return error;
971
+ return restoreExistingError(error, currentStack);
764
972
  }
765
973
  if (error && error.code && error.code === MethodNotFound) {
766
- const restoredError = new JsonRpcError(error.message);
767
- const parentStack = getParentStack(error);
768
- restoredError.stack = parentStack + NewLine + currentStack;
769
- return restoredError;
974
+ return restoreMethodNotFoundError(error, currentStack);
770
975
  }
771
976
  if (error && error.message) {
772
- const restoredError = constructError(error.message, error.type, error.name);
773
- if (error.data) {
774
- if (error.data.stack && error.data.type && error.message) {
775
- restoredError.stack = error.data.type + ': ' + error.message + NewLine + error.data.stack + NewLine + currentStack;
776
- } else if (error.data.stack) {
777
- restoredError.stack = error.data.stack;
778
- }
779
- if (error.data.codeFrame) {
780
- // @ts-ignore
781
- restoredError.codeFrame = error.data.codeFrame;
782
- }
783
- if (error.data.code) {
784
- // @ts-ignore
785
- restoredError.code = error.data.code;
786
- }
787
- if (error.data.type) {
788
- // @ts-ignore
789
- restoredError.name = error.data.type;
790
- }
791
- } else {
792
- if (error.stack) {
793
- const lowerStack = restoredError.stack || '';
794
- // @ts-ignore
795
- const indexNewLine = getNewLineIndex(lowerStack);
796
- const parentStack = getParentStack(error);
797
- // @ts-ignore
798
- restoredError.stack = parentStack + lowerStack.slice(indexNewLine);
799
- }
800
- if (error.codeFrame) {
801
- // @ts-ignore
802
- restoredError.codeFrame = error.codeFrame;
803
- }
804
- }
805
- return restoredError;
977
+ return restoreMessageError(error);
806
978
  }
807
979
  if (typeof error === 'string') {
808
980
  return new Error(`JsonRpc Error: ${error}`);
@@ -1262,9 +1434,175 @@ const create$1 = rpcId => {
1262
1434
  };
1263
1435
  };
1264
1436
 
1437
+ const Audio = 0;
1438
+ const Button$4 = 1;
1439
+ const Col = 2;
1440
+ const ColGroup = 3;
1441
+ const Div$1 = 4;
1442
+ const H1 = 5;
1443
+ const Input$2 = 6;
1444
+ const Kbd = 7;
1445
+ const Span = 8;
1446
+ const Table = 9;
1447
+ const TBody = 10;
1448
+ const Td = 11;
1265
1449
  const Text = 12;
1450
+ const Th = 13;
1451
+ const THead = 14;
1452
+ const Tr = 15;
1453
+ const I = 16;
1454
+ const Img$1 = 17;
1455
+ const Root = 0;
1456
+ const Ins = 20;
1457
+ const Del = 21;
1458
+ const H2 = 22;
1459
+ const H3 = 23;
1460
+ const H4 = 24;
1461
+ const H5 = 25;
1462
+ const H6 = 26;
1463
+ const Article = 27;
1464
+ const Aside = 28;
1465
+ const Footer = 29;
1466
+ const Header = 30;
1467
+ const Nav = 40;
1468
+ const Section = 41;
1469
+ const Search = 42;
1470
+ const Dd = 43;
1471
+ const Dl = 44;
1472
+ const Figcaption = 45;
1473
+ const Figure = 46;
1474
+ const Hr = 47;
1475
+ const Li = 48;
1476
+ const Ol = 49;
1477
+ const P$1 = 50;
1478
+ const Pre = 51;
1479
+ const A = 53;
1480
+ const Abbr = 54;
1481
+ const Br = 55;
1482
+ const Cite = 56;
1483
+ const Data = 57;
1484
+ const Time = 58;
1485
+ const Tfoot = 59;
1486
+ const Ul = 60;
1487
+ const Video = 61;
1488
+ const TextArea = 62;
1489
+ const Select = 63;
1490
+ const Option = 64;
1491
+ const Code = 65;
1492
+ const Label$1 = 66;
1493
+ const Dt = 67;
1494
+ const Iframe = 68;
1495
+ const Main = 69;
1496
+ const Strong = 70;
1497
+ const Em = 71;
1498
+ const Style = 72;
1499
+ const Html = 73;
1500
+ const Head = 74;
1501
+ const Title = 75;
1502
+ const Meta = 76;
1503
+ const Canvas = 77;
1504
+ const Form = 78;
1505
+ const BlockQuote = 79;
1506
+ const Quote = 80;
1507
+ const Circle = 81;
1508
+ const Defs = 82;
1509
+ const Ellipse = 83;
1510
+ const G = 84;
1511
+ const Line = 85;
1512
+ const Path = 86;
1513
+ const Polygon = 87;
1514
+ const Polyline = 88;
1515
+ const Rect = 89;
1516
+ const Svg = 90;
1517
+ const Use = 91;
1266
1518
  const Reference = 100;
1267
1519
 
1520
+ const VirtualDomElements = {
1521
+ __proto__: null,
1522
+ A,
1523
+ Abbr,
1524
+ Article,
1525
+ Aside,
1526
+ Audio,
1527
+ BlockQuote,
1528
+ Br,
1529
+ Button: Button$4,
1530
+ Canvas,
1531
+ Circle,
1532
+ Cite,
1533
+ Code,
1534
+ Col,
1535
+ ColGroup,
1536
+ Data,
1537
+ Dd,
1538
+ Defs,
1539
+ Del,
1540
+ Div: Div$1,
1541
+ Dl,
1542
+ Dt,
1543
+ Ellipse,
1544
+ Em,
1545
+ Figcaption,
1546
+ Figure,
1547
+ Footer,
1548
+ Form,
1549
+ G,
1550
+ H1,
1551
+ H2,
1552
+ H3,
1553
+ H4,
1554
+ H5,
1555
+ H6,
1556
+ Head,
1557
+ Header,
1558
+ Hr,
1559
+ Html,
1560
+ I,
1561
+ Iframe,
1562
+ Img: Img$1,
1563
+ Input: Input$2,
1564
+ Ins,
1565
+ Kbd,
1566
+ Label: Label$1,
1567
+ Li,
1568
+ Line,
1569
+ Main,
1570
+ Meta,
1571
+ Nav,
1572
+ Ol,
1573
+ Option,
1574
+ P: P$1,
1575
+ Path,
1576
+ Polygon,
1577
+ Polyline,
1578
+ Pre,
1579
+ Quote,
1580
+ Rect,
1581
+ Reference,
1582
+ Root,
1583
+ Search,
1584
+ Section,
1585
+ Select,
1586
+ Span,
1587
+ Strong,
1588
+ Style,
1589
+ Svg,
1590
+ TBody,
1591
+ THead,
1592
+ Table,
1593
+ Td,
1594
+ Text,
1595
+ TextArea,
1596
+ Tfoot,
1597
+ Th,
1598
+ Time,
1599
+ Title,
1600
+ Tr,
1601
+ Ul,
1602
+ Use,
1603
+ Video
1604
+ };
1605
+
1268
1606
  const Button$3 = 'event.button';
1269
1607
  const ClientX = 'event.clientX';
1270
1608
  const ClientY = 'event.clientY';
@@ -1393,6 +1731,9 @@ const remove = async dirent => {
1393
1731
  const readDirWithFileTypes = async uri => {
1394
1732
  return invoke('FileSystem.readDirWithFileTypes', uri);
1395
1733
  };
1734
+ const readFile = async uri => {
1735
+ return invoke('FileSystem.readFile', uri);
1736
+ };
1396
1737
  const getPathSeparator$1 = async root => {
1397
1738
  return invoke('FileSystem.getPathSeparator', root);
1398
1739
  };
@@ -1903,7 +2244,18 @@ const mergeTrees = (a, b) => {
1903
2244
  };
1904
2245
  };
1905
2246
 
1906
- const openUri = async (uri, focus) => {
2247
+ const openUri = async (uri, focus, options) => {
2248
+ if (options) {
2249
+ await invoke$2('Main.openInput', {
2250
+ editorInput: {
2251
+ type: 'editor',
2252
+ uri
2253
+ },
2254
+ focu: focus,
2255
+ preview: options.preview ?? false
2256
+ });
2257
+ return;
2258
+ }
1907
2259
  await openUri$1(uri, /* focus */focus);
1908
2260
  };
1909
2261
 
@@ -1951,15 +2303,15 @@ const Slash$1 = '/';
1951
2303
  const BackSlash = '\\';
1952
2304
 
1953
2305
  const emptyObject = {};
1954
- const RE_PLACEHOLDER = /\{(PH\d+)\}/g;
1955
2306
  const i18nString = (key, placeholders = emptyObject) => {
1956
2307
  if (placeholders === emptyObject) {
1957
2308
  return key;
1958
2309
  }
1959
- const replacer = (match, rest) => {
1960
- return placeholders[rest];
1961
- };
1962
- return key.replaceAll(RE_PLACEHOLDER, replacer);
2310
+ let result = key;
2311
+ for (const [placeholder, replacement] of Object.entries(placeholders)) {
2312
+ result = result.split(`{${placeholder}}`).join(String(replacement));
2313
+ }
2314
+ return result;
1963
2315
  };
1964
2316
 
1965
2317
  const CollapseAllFoldersInExplorer = 'Collapse All Folders in Explorer';
@@ -2206,6 +2558,15 @@ const getFileOperationsRename = (oldAbsolutePath, newFileName) => {
2206
2558
  return operations;
2207
2559
  };
2208
2560
 
2561
+ const getRenameSiblingFileNames = (items, editingIndex, pathSeparator) => {
2562
+ const editingItem = items[editingIndex];
2563
+ if (!editingItem) {
2564
+ return [];
2565
+ }
2566
+ const parentPath = dirname(pathSeparator, editingItem.path);
2567
+ return items.filter((item, index) => index !== editingIndex && dirname(pathSeparator, item.path) === parentPath).map(item => item.name);
2568
+ };
2569
+
2209
2570
  const updateTree2 = (tree, update) => {
2210
2571
  const updatedTree = {
2211
2572
  ...tree,
@@ -2223,7 +2584,8 @@ const acceptRename = async state => {
2223
2584
  pathSeparator,
2224
2585
  root
2225
2586
  } = state;
2226
- const editingErrorMessage = validateFileName2(editingValue);
2587
+ const siblingFileNames = getRenameSiblingFileNames(items, editingIndex, pathSeparator);
2588
+ const editingErrorMessage = validateFileName2(editingValue, siblingFileNames);
2227
2589
  if (editingErrorMessage) {
2228
2590
  return {
2229
2591
  ...state,
@@ -2231,6 +2593,9 @@ const acceptRename = async state => {
2231
2593
  };
2232
2594
  }
2233
2595
  const renamedDirent = items[editingIndex];
2596
+ const oldUri = renamedDirent.path;
2597
+ const dirname = dirname2(oldUri);
2598
+ const newUri = join2(dirname, editingValue);
2234
2599
  const operations = getFileOperationsRename(renamedDirent.path, editingValue);
2235
2600
  const renameErrorMessage = await applyFileOperations(operations);
2236
2601
  if (renameErrorMessage) {
@@ -2239,9 +2604,7 @@ const acceptRename = async state => {
2239
2604
  editingErrorMessage: renameErrorMessage
2240
2605
  };
2241
2606
  }
2242
- const oldUri = renamedDirent.path;
2243
- const dirname = dirname2(oldUri);
2244
- const newUri = join2(dirname, editingValue);
2607
+ await invoke$2('Main.handleUriChange', oldUri, newUri);
2245
2608
  const children = await getChildDirents(pathSeparator, dirname, renamedDirent.depth - 1, excluded, root);
2246
2609
  const tree = createTree(items, root);
2247
2610
  const update = computeExplorerRenamedDirentUpdate(root, dirname, oldUri, children, tree, newUri);
@@ -2575,6 +2938,215 @@ const getFileIcons = async (dirents, fileIconCache) => {
2575
2938
  };
2576
2939
  };
2577
2940
 
2941
+ const directoryTypes = new Set([DirectoryExpanded, DirectoryExpanding, EditingDirectoryExpanded]);
2942
+ const getParentPath = (path, pathSeparator) => {
2943
+ const index = path.lastIndexOf(pathSeparator);
2944
+ if (index === -1) {
2945
+ return '';
2946
+ }
2947
+ return path.slice(0, index);
2948
+ };
2949
+ const getGitIgnoreCandidateDirs = (root, items, pathSeparator) => {
2950
+ const dirs = new Set([root]);
2951
+ for (const item of items) {
2952
+ if (directoryTypes.has(item.type)) {
2953
+ dirs.add(item.path);
2954
+ }
2955
+ const parent = getParentPath(item.path, pathSeparator);
2956
+ if (parent && parent.startsWith(root)) {
2957
+ dirs.add(parent);
2958
+ }
2959
+ }
2960
+ return [...dirs];
2961
+ };
2962
+
2963
+ const trimLeadingSeparator = path => {
2964
+ return path.startsWith('/') ? path.slice(1) : path;
2965
+ };
2966
+ const toSlashPath = (path, pathSeparator) => {
2967
+ if (pathSeparator === '/') {
2968
+ return path;
2969
+ }
2970
+ return path.replaceAll(pathSeparator, '/');
2971
+ };
2972
+ const getGitIgnoreRelativePath = (root, path, pathSeparator) => {
2973
+ const slashRoot = toSlashPath(root, pathSeparator);
2974
+ const slashPath = toSlashPath(path, pathSeparator);
2975
+ if (slashPath === slashRoot) {
2976
+ return '';
2977
+ }
2978
+ if (slashRoot.endsWith('/')) {
2979
+ return slashPath.slice(slashRoot.length);
2980
+ }
2981
+ return trimLeadingSeparator(slashPath.slice(slashRoot.length));
2982
+ };
2983
+
2984
+ const joinPath = (parent, child, pathSeparator) => {
2985
+ if (parent.endsWith(pathSeparator)) {
2986
+ return `${parent}${child}`;
2987
+ }
2988
+ return `${parent}${pathSeparator}${child}`;
2989
+ };
2990
+
2991
+ const lineSeparatorRegex = /\r?\n/;
2992
+ const stripTrailingSpaces = line => {
2993
+ let end = line.length;
2994
+ while (end > 0 && line[end - 1] === ' ' && line[end - 2] !== '\\') {
2995
+ end--;
2996
+ }
2997
+ return line.slice(0, end).replaceAll('\\ ', ' ');
2998
+ };
2999
+ const parseLine = (basePath, line) => {
3000
+ line = stripTrailingSpaces(line);
3001
+ if (!line || line.startsWith('#')) {
3002
+ return undefined;
3003
+ }
3004
+ let negative = false;
3005
+ if (line.startsWith('\\!')) {
3006
+ line = line.slice(1);
3007
+ } else if (line.startsWith('!')) {
3008
+ negative = true;
3009
+ line = line.slice(1);
3010
+ }
3011
+ const anchored = line.startsWith('/');
3012
+ line = line.replaceAll('\\#', '#').replaceAll('\\!', '!');
3013
+ const directoryOnly = line.endsWith('/');
3014
+ if (directoryOnly) {
3015
+ line = line.slice(0, -1);
3016
+ }
3017
+ while (line.startsWith('/')) {
3018
+ line = line.slice(1);
3019
+ }
3020
+ if (!line) {
3021
+ return undefined;
3022
+ }
3023
+ return {
3024
+ anchored,
3025
+ basePath,
3026
+ directoryOnly,
3027
+ hasSlash: line.includes('/'),
3028
+ negative,
3029
+ pattern: line
3030
+ };
3031
+ };
3032
+ const parseGitIgnore = (basePath, content) => {
3033
+ const patterns = [];
3034
+ for (const line of content.split(lineSeparatorRegex)) {
3035
+ const pattern = parseLine(basePath, line);
3036
+ if (pattern) {
3037
+ patterns.push(pattern);
3038
+ }
3039
+ }
3040
+ return patterns;
3041
+ };
3042
+
3043
+ const readGitIgnoreFile = async (root, dir, pathSeparator) => {
3044
+ try {
3045
+ const content = await readFile(joinPath(dir, '.gitignore', pathSeparator));
3046
+ const basePath = getGitIgnoreRelativePath(root, dir, pathSeparator);
3047
+ return parseGitIgnore(basePath, content);
3048
+ } catch {
3049
+ return [];
3050
+ }
3051
+ };
3052
+ const getGitIgnoreFiles = async (root, items, pathSeparator) => {
3053
+ const dirs = getGitIgnoreCandidateDirs(root, items, pathSeparator);
3054
+ const nestedPatterns = await Promise.all(dirs.map(dir => {
3055
+ return readGitIgnoreFile(root, dir, pathSeparator);
3056
+ }));
3057
+ return nestedPatterns.flat();
3058
+ };
3059
+
3060
+ const regexSpecialCharacters = /[|\\{}()[\]^$+?.]/g;
3061
+ const escapeRegex = text => {
3062
+ return text.replaceAll(regexSpecialCharacters, '\\$&');
3063
+ };
3064
+ const globToRegex = glob => {
3065
+ let regex = '^';
3066
+ for (let i = 0; i < glob.length; i++) {
3067
+ const char = glob[i];
3068
+ const next = glob[i + 1];
3069
+ if (char === '*' && next === '*') {
3070
+ if (glob[i + 2] === '/') {
3071
+ regex += '(?:.*/)?';
3072
+ i += 2;
3073
+ } else {
3074
+ regex += '.*';
3075
+ i++;
3076
+ }
3077
+ } else if (char === '*') {
3078
+ regex += '[^/]*';
3079
+ } else if (char === '?') {
3080
+ regex += '[^/]';
3081
+ } else {
3082
+ regex += escapeRegex(char);
3083
+ }
3084
+ }
3085
+ regex += '$';
3086
+ return new RegExp(regex);
3087
+ };
3088
+ const isWithinBase = (relativePath, basePath) => {
3089
+ return !basePath || relativePath === basePath || relativePath.startsWith(`${basePath}/`);
3090
+ };
3091
+ const getBaseRelativePath = (relativePath, basePath) => {
3092
+ if (!basePath) {
3093
+ return relativePath;
3094
+ }
3095
+ if (relativePath === basePath) {
3096
+ return '';
3097
+ }
3098
+ return relativePath.slice(basePath.length + 1);
3099
+ };
3100
+ const matchesDirectoryPattern = (baseRelativePath, pattern) => {
3101
+ if (pattern.hasSlash || pattern.anchored) {
3102
+ return baseRelativePath === pattern.pattern || baseRelativePath.startsWith(`${pattern.pattern}/`);
3103
+ }
3104
+ return baseRelativePath.split('/').includes(pattern.pattern);
3105
+ };
3106
+ const matchesPathPattern = (baseRelativePath, pattern) => {
3107
+ const regex = globToRegex(pattern.pattern);
3108
+ if (pattern.hasSlash || pattern.anchored) {
3109
+ return regex.test(baseRelativePath);
3110
+ }
3111
+ return baseRelativePath.split('/').some(part => regex.test(part));
3112
+ };
3113
+ const matchesPattern = (baseRelativePath, pattern) => {
3114
+ if (!baseRelativePath) {
3115
+ return false;
3116
+ }
3117
+ if (pattern.directoryOnly) {
3118
+ return matchesDirectoryPattern(baseRelativePath, pattern);
3119
+ }
3120
+ return matchesPathPattern(baseRelativePath, pattern);
3121
+ };
3122
+ const isGitIgnored = (relativePath, patterns) => {
3123
+ let ignored = false;
3124
+ for (const pattern of patterns) {
3125
+ if (!isWithinBase(relativePath, pattern.basePath)) {
3126
+ continue;
3127
+ }
3128
+ const baseRelativePath = getBaseRelativePath(relativePath, pattern.basePath);
3129
+ if (matchesPattern(baseRelativePath, pattern)) {
3130
+ ignored = !pattern.negative;
3131
+ }
3132
+ }
3133
+ return ignored;
3134
+ };
3135
+
3136
+ const getGitIgnoredUris = async (root, items, pathSeparator, enabled) => {
3137
+ if (!enabled || !root || items.length === 0) {
3138
+ return [];
3139
+ }
3140
+ const patterns = await getGitIgnoreFiles(root, items, pathSeparator);
3141
+ if (patterns.length === 0) {
3142
+ return [];
3143
+ }
3144
+ return items.filter(item => {
3145
+ const relativePath = getGitIgnoreRelativePath(root, item.path, pathSeparator);
3146
+ return isGitIgnored(relativePath, patterns);
3147
+ }).map(item => item.path);
3148
+ };
3149
+
2578
3150
  // TODO optimize this function to return the minimum number
2579
3151
  // of visible items needed, e.g. when not scrolled 5 items with
2580
3152
  // 20px fill 100px but when scrolled 6 items are needed
@@ -2696,6 +3268,8 @@ const text = data => {
2696
3268
  };
2697
3269
  };
2698
3270
 
3271
+ new Set(Object.values(VirtualDomElements));
3272
+
2699
3273
  const SetText = 1;
2700
3274
  const Replace = 2;
2701
3275
  const SetAttribute = 3;
@@ -3053,18 +3627,55 @@ const {
3053
3627
  set,
3054
3628
  wrapGetter
3055
3629
  } = create$a();
3630
+ const commandQueues = new Map();
3631
+ const runQueuedCommand = async (previousCommand, command) => {
3632
+ try {
3633
+ await previousCommand;
3634
+ } catch {
3635
+ // Keep the queue usable after returning the error to the command caller
3636
+ }
3637
+ await command();
3638
+ };
3639
+ const enqueueCommand = async (id, command) => {
3640
+ const currentCommand = runQueuedCommand(commandQueues.get(id), command);
3641
+ commandQueues.set(id, currentCommand);
3642
+ try {
3643
+ await currentCommand;
3644
+ } finally {
3645
+ if (commandQueues.get(id) === currentCommand) {
3646
+ commandQueues.delete(id);
3647
+ }
3648
+ }
3649
+ };
3056
3650
  const hasSameVisibleExplorerItemInputs = (oldState, newState) => {
3057
3651
  return oldState.items === newState.items && oldState.minLineY === newState.minLineY && oldState.height === newState.height && oldState.itemHeight === newState.itemHeight && oldState.focusedIndex === newState.focusedIndex && oldState.editingIndex === newState.editingIndex && oldState.editingIcon === newState.editingIcon && oldState.cutItems === newState.cutItems && oldState.editingErrorMessage === newState.editingErrorMessage && oldState.dropTargets === newState.dropTargets && oldState.fileIconCache === newState.fileIconCache && oldState.decorations === newState.decorations && oldState.useChevrons === newState.useChevrons && oldState.sourceControlIgnoredUris === newState.sourceControlIgnoredUris;
3058
3652
  };
3059
- const wrapListItemCommand = fn => {
3060
- const wrappedCommand = async (id, ...args) => {
3653
+ const maybeUpdateGitIgnoredUris = async (oldState, newState) => {
3654
+ if (oldState.items === newState.items || oldState.sourceControlIgnoredUris !== newState.sourceControlIgnoredUris) {
3655
+ return newState;
3656
+ }
3657
+ const {
3658
+ gitIgnoreDecorations,
3659
+ items,
3660
+ pathSeparator,
3661
+ root
3662
+ } = newState;
3663
+ const sourceControlIgnoredUris = await getGitIgnoredUris(root, items, pathSeparator, gitIgnoreDecorations);
3664
+ return {
3665
+ ...newState,
3666
+ sourceControlIgnoredUris
3667
+ };
3668
+ };
3669
+ const wrapListItemCommandInternal = (fn, queued) => {
3670
+ const runCommand = async (id, ...args) => {
3061
3671
  const {
3062
3672
  newState
3063
3673
  } = get(id);
3064
- const updatedState = await fn(newState, ...args);
3065
- if (newState === updatedState) {
3674
+ const rawUpdatedState = await fn(newState, ...args);
3675
+ if (newState === rawUpdatedState) {
3066
3676
  return;
3067
3677
  }
3678
+ const updatedState = await maybeUpdateGitIgnoredUris(newState, rawUpdatedState);
3068
3679
  const {
3069
3680
  cutItems,
3070
3681
  decorations,
@@ -3103,8 +3714,22 @@ const wrapListItemCommand = fn => {
3103
3714
  const intermediate2 = get(id);
3104
3715
  set(id, intermediate2.oldState, finalState);
3105
3716
  };
3717
+ if (!queued) {
3718
+ return runCommand;
3719
+ }
3720
+ const wrappedCommand = async (id, ...args) => {
3721
+ await enqueueCommand(id, async () => {
3722
+ await runCommand(id, ...args);
3723
+ });
3724
+ };
3106
3725
  return wrappedCommand;
3107
3726
  };
3727
+ const wrapListItemCommand = fn => {
3728
+ return wrapListItemCommandInternal(fn, true);
3729
+ };
3730
+ const wrapListItemCommandImmediate = fn => {
3731
+ return wrapListItemCommandInternal(fn, false);
3732
+ };
3108
3733
 
3109
3734
  const ListItem = 22;
3110
3735
 
@@ -3144,6 +3769,7 @@ const create = (id, uri, x, y, width, height, args, parentUid, platform = 0, ass
3144
3769
  focusedIndex: -1,
3145
3770
  focusWord: '',
3146
3771
  focusWordTimeout: 800,
3772
+ gitIgnoreDecorations: false,
3147
3773
  handleOffset: 0,
3148
3774
  hasError: false,
3149
3775
  height,
@@ -3920,7 +4546,9 @@ const handleClickDirectory = async (state, dirent, index, keepFocus) => {
3920
4546
  };
3921
4547
 
3922
4548
  const handleClickFile = async (state, dirent, index, keepFocus = false) => {
3923
- await openUri(dirent.path, !keepFocus);
4549
+ await openUri(dirent.path, !keepFocus, {
4550
+ preview: true
4551
+ });
3924
4552
  return {
3925
4553
  ...state,
3926
4554
  focused: keepFocus,
@@ -4240,7 +4868,9 @@ const refresh = async state => {
4240
4868
  const {
4241
4869
  excluded,
4242
4870
  focusedIndex,
4871
+ gitIgnoreDecorations,
4243
4872
  items,
4873
+ pathSeparator,
4244
4874
  root
4245
4875
  } = state;
4246
4876
  const expandedDirents = getExpandedDirents(items);
@@ -4253,10 +4883,12 @@ const refresh = async state => {
4253
4883
  if (focusedIndex >= newItems.length) {
4254
4884
  newFocusedIndex = newItems.length - 1;
4255
4885
  }
4886
+ const sourceControlIgnoredUris = await getGitIgnoredUris(root, newItems, pathSeparator, gitIgnoreDecorations);
4256
4887
  return {
4257
4888
  ...state,
4258
4889
  focusedIndex: newFocusedIndex,
4259
- items: newItems
4890
+ items: newItems,
4891
+ sourceControlIgnoredUris
4260
4892
  };
4261
4893
  };
4262
4894
 
@@ -4836,17 +5468,20 @@ const getSettings = async () => {
4836
5468
  const useChevronsRaw = await invoke$2('Preferences.get', 'explorer.useChevrons');
4837
5469
  const useChevrons = useChevronsRaw === false ? false : true;
4838
5470
  const confirmDeleteRaw = await invoke$2('Preferences.get', 'explorer.confirmdelete');
4839
- const confirmDelete = confirmDeleteRaw === false ? false : false;
5471
+ const confirmDelete = confirmDeleteRaw === false ? false : true;
4840
5472
  const confirmPasteRaw = await invoke$2('Preferences.get', 'explorer.confirmpaste');
4841
5473
  const confirmPaste = confirmPasteRaw === false ? false : false;
4842
5474
  const excludedRaw = await invoke$2('Preferences.get', 'files.exclude');
4843
5475
  const excluded = getExcluded(excludedRaw);
5476
+ const gitIgnoreDecorationsRaw = await invoke$2('Preferences.get', 'explorer.gitIgnoreDecorations');
5477
+ const gitIgnoreDecorations = gitIgnoreDecorationsRaw === false ? false : true;
4844
5478
  const sourceControlDecorationsRaw = await invoke$2('Preferences.get', 'explorer.sourceControlDecorations');
4845
5479
  const sourceControlDecorations = sourceControlDecorationsRaw === false ? false : true;
4846
5480
  return {
4847
5481
  confirmDelete,
4848
5482
  confirmPaste,
4849
5483
  excluded,
5484
+ gitIgnoreDecorations,
4850
5485
  sourceControlDecorations,
4851
5486
  useChevrons
4852
5487
  };
@@ -4960,6 +5595,7 @@ const loadContent = async (state, savedState) => {
4960
5595
  const {
4961
5596
  confirmDelete,
4962
5597
  excluded,
5598
+ gitIgnoreDecorations,
4963
5599
  sourceControlDecorations,
4964
5600
  useChevrons
4965
5601
  } = await getSettings();
@@ -4977,6 +5613,7 @@ const loadContent = async (state, savedState) => {
4977
5613
  const minLineY = Math.round(deltaY / itemHeight);
4978
5614
  const scheme = getScheme(root);
4979
5615
  const decorations = await getFileDecorations(scheme, root, restoredDirents.filter(item => item.depth === 1).map(item => item.path), sourceControlDecorations, assetDir, platform);
5616
+ const sourceControlIgnoredUris = await getGitIgnoredUris(root, restoredDirents, pathSeparator, gitIgnoreDecorations);
4980
5617
  return {
4981
5618
  ...state,
4982
5619
  confirmDelete,
@@ -4985,6 +5622,7 @@ const loadContent = async (state, savedState) => {
4985
5622
  errorCode: '',
4986
5623
  errorMessage: '',
4987
5624
  excluded,
5625
+ gitIgnoreDecorations,
4988
5626
  hasError: false,
4989
5627
  initial: false,
4990
5628
  isReadonly: isReadonly$1,
@@ -4993,6 +5631,7 @@ const loadContent = async (state, savedState) => {
4993
5631
  minLineY,
4994
5632
  pathSeparator,
4995
5633
  root,
5634
+ sourceControlIgnoredUris,
4996
5635
  useChevrons
4997
5636
  };
4998
5637
  } catch (error) {
@@ -5003,6 +5642,7 @@ const loadContent = async (state, savedState) => {
5003
5642
  confirmDelete,
5004
5643
  errorCode,
5005
5644
  errorMessage,
5645
+ gitIgnoreDecorations,
5006
5646
  hasError: true,
5007
5647
  initial: false,
5008
5648
  isReadonly: false,
@@ -5595,26 +6235,19 @@ const generateUniqueName = (baseName, existingPaths, root) => {
5595
6235
  }
5596
6236
  };
5597
6237
 
5598
- const getFileOperationsCopy = (root, existingUris, files, focusedUri) => {
6238
+ const getFileOperationsCopy = (targetUri, existingUris, files) => {
5599
6239
  const operations = [];
6240
+ const reservedUris = [...existingUris];
5600
6241
  for (const file of files) {
5601
6242
  const baseName = getBaseName('/', file);
5602
- if (existingUris.includes(file)) {
5603
- operations.push({
5604
- from: file,
5605
- path: join2(focusedUri, baseName),
5606
- type: Rename$2
5607
- });
5608
- } else {
5609
- const uniqueName = generateUniqueName(baseName, existingUris, root);
5610
- const newUri = join2(root, uniqueName);
5611
- operations.push({
5612
- from: file,
5613
- // TODO ensure file is uri
5614
- path: newUri,
5615
- type: Copy$1
5616
- });
5617
- }
6243
+ const uniqueName = generateUniqueName(baseName, reservedUris, targetUri);
6244
+ const newUri = join2(targetUri, uniqueName);
6245
+ operations.push({
6246
+ from: file,
6247
+ path: newUri,
6248
+ type: Copy$1
6249
+ });
6250
+ reservedUris.push(newUri);
5618
6251
  }
5619
6252
  return operations;
5620
6253
  };
@@ -5630,11 +6263,13 @@ const handlePasteCopy = async (state, nativeFiles) => {
5630
6263
  const {
5631
6264
  focusedIndex,
5632
6265
  items,
6266
+ pathSeparator,
5633
6267
  root
5634
6268
  } = state;
5635
- const focusedUri = items[focusedIndex]?.path || root;
5636
- const existingUris = items.map(item => item.path);
5637
- const operations = getFileOperationsCopy(root, existingUris, nativeFiles.files, focusedUri);
6269
+ const targetUri = getParentFolder(items, focusedIndex, root, pathSeparator);
6270
+ const targetDirents = await readDirWithFileTypes(targetUri);
6271
+ const existingUris = targetDirents.map(dirent => join2(targetUri, dirent.name));
6272
+ const operations = getFileOperationsCopy(targetUri, existingUris, nativeFiles.files);
5638
6273
  // TODO handle error?
5639
6274
  await applyFileOperations(operations);
5640
6275
 
@@ -6594,11 +7229,12 @@ const applyRender = (oldState, newState, diffResult) => {
6594
7229
  return commands;
6595
7230
  };
6596
7231
 
6597
- const render2 = (uid, diffResult) => {
7232
+ const render2 = (uid, _diffResult) => {
6598
7233
  const {
6599
7234
  oldState,
6600
7235
  scheduledState
6601
7236
  } = get(uid);
7237
+ const diffResult = diff(oldState, scheduledState);
6602
7238
  set(uid, scheduledState, scheduledState);
6603
7239
  const commands = applyRender(oldState, scheduledState, diffResult);
6604
7240
  return commands;
@@ -6858,8 +7494,9 @@ const revealItemHidden = async (state, uri) => {
6858
7494
  const pathPartsChildrenFlat = pathPartsChildren.flat();
6859
7495
  const orderedPathParts = orderDirents(pathPartsChildrenFlat);
6860
7496
  const mergedDirents = mergeVisibleWithHiddenItems(items, orderedPathParts);
7497
+ const orderedDirents = orderDirents(mergedDirents);
6861
7498
  const expandedPaths = new Set(pathPartsToReveal.map(pathPart => pathPart.path));
6862
- const newDirents = mergedDirents.map(item => {
7499
+ const newDirents = orderedDirents.map(item => {
6863
7500
  if (expandedPaths.has(item.path) && item.type === Directory) {
6864
7501
  return {
6865
7502
  ...item,
@@ -7044,13 +7681,16 @@ const updateEditingValue = async (state, value, inputSource = User) => {
7044
7681
  editingIndex,
7045
7682
  editingType,
7046
7683
  focusedIndex,
7047
- items} = state;
7684
+ items,
7685
+ pathSeparator} = state;
7048
7686
  const editingIcon = await getEditingIcon(editingType, value, items[editingIndex]?.type);
7049
7687
 
7050
7688
  // Get sibling file names for validation during file/folder creation
7051
7689
  let siblingFileNames = [];
7052
7690
  if (editingType === CreateFile || editingType === CreateFolder) {
7053
7691
  siblingFileNames = getSiblingFileNames(items, focusedIndex);
7692
+ } else if (editingType === Rename$1) {
7693
+ siblingFileNames = getRenameSiblingFileNames(items, editingIndex, pathSeparator);
7054
7694
  }
7055
7695
  const editingErrorMessage = validateFileName2(value, siblingFileNames);
7056
7696
  return {
@@ -7122,8 +7762,8 @@ const commandMap = {
7122
7762
  'Explorer.handleResize': wrapListItemCommand(handleResize),
7123
7763
  'Explorer.handleUpload': wrapListItemCommand(handleUpload),
7124
7764
  'Explorer.handleWheel': wrapListItemCommand(handleWheel),
7125
- 'Explorer.handleWorkspaceChange': wrapListItemCommand(handleWorkspaceChange),
7126
- 'Explorer.handleWorkspaceRefresh': wrapListItemCommand(handleWorkspaceRefresh),
7765
+ 'Explorer.handleWorkspaceChange': wrapListItemCommandImmediate(handleWorkspaceChange),
7766
+ 'Explorer.handleWorkspaceRefresh': wrapListItemCommandImmediate(handleWorkspaceRefresh),
7127
7767
  'Explorer.initialize': initialize,
7128
7768
  'Explorer.loadContent': wrapListItemCommand(loadContent),
7129
7769
  'Explorer.newFile': wrapListItemCommand(newFile),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/explorer-view",
3
- "version": "7.8.0",
3
+ "version": "7.9.1",
4
4
  "description": "Explorer Worker",
5
5
  "repository": {
6
6
  "type": "git",