@lvce-editor/problems-view 1.25.4 → 1.26.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.
@@ -3,29 +3,87 @@ 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
  }
13
70
  },
14
71
  diff(uid, modules, numbers) {
15
72
  const {
16
- newState,
17
- oldState
73
+ oldState,
74
+ scheduledState
18
75
  } = states[uid];
19
76
  const diffResult = [];
20
77
  for (let i = 0; i < modules.length; i++) {
21
78
  const fn = modules[i];
22
- if (!fn(oldState, newState)) {
79
+ if (!fn(oldState, scheduledState)) {
23
80
  diffResult.push(numbers[i]);
24
81
  }
25
82
  }
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) {
@@ -37,21 +95,33 @@ const create$a = () => {
37
95
  return ids;
38
96
  },
39
97
  getKeys() {
40
- return Object.keys(states).map(key => {
41
- return Number.parseFloat(key);
42
- });
98
+ return Object.keys(states).map(Number);
43
99
  },
44
100
  registerCommands(commandMap) {
45
101
  Object.assign(commandMapRef, commandMap);
46
102
  },
47
- set(uid, oldState, newState) {
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
+ }
48
108
  states[uid] = {
49
109
  newState,
50
- oldState
110
+ oldState,
111
+ scheduledState: scheduledState ?? newState
51
112
  };
52
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
+ },
53
122
  wrapCommand(fn) {
54
123
  const wrapped = async (uid, ...args) => {
124
+ const generation = getGeneration(uid);
55
125
  const {
56
126
  newState,
57
127
  oldState
@@ -60,6 +130,9 @@ const create$a = () => {
60
130
  if (oldState === newerState || newState === newerState) {
61
131
  return;
62
132
  }
133
+ if (!isCurrentGeneration(uid, generation)) {
134
+ return;
135
+ }
63
136
  const latestOld = states[uid];
64
137
  const latestNew = {
65
138
  ...latestOld.newState,
@@ -67,7 +140,8 @@ const create$a = () => {
67
140
  };
68
141
  states[uid] = {
69
142
  newState: latestNew,
70
- oldState: latestOld.oldState
143
+ oldState: latestOld.oldState,
144
+ scheduledState: latestNew
71
145
  };
72
146
  };
73
147
  return wrapped;
@@ -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,
@@ -104,13 +184,59 @@ const create$a = () => {
104
184
  };
105
185
  states[uid] = {
106
186
  newState: latestNew,
107
- oldState: latestOld.oldState
187
+ oldState: latestOld.oldState,
188
+ scheduledState: latestNew
108
189
  };
109
190
  return {
110
191
  error
111
192
  };
112
193
  };
113
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;
114
240
  }
115
241
  };
116
242
  };
@@ -183,7 +309,7 @@ class AssertionError extends Error {
183
309
  const Object$1 = 1;
184
310
  const Number$1 = 2;
185
311
  const Array$1 = 3;
186
- const String = 4;
312
+ const String$1 = 4;
187
313
  const Boolean$1 = 5;
188
314
  const Function = 6;
189
315
  const Null = 7;
@@ -195,7 +321,7 @@ const getType = value => {
195
321
  case 'function':
196
322
  return Function;
197
323
  case 'string':
198
- return String;
324
+ return String$1;
199
325
  case 'object':
200
326
  if (value === null) {
201
327
  return Null;
@@ -224,7 +350,7 @@ const array = value => {
224
350
  };
225
351
  const string = value => {
226
352
  const type = getType(value);
227
- if (type !== String) {
353
+ if (type !== String$1) {
228
354
  throw new AssertionError('expected value to be of type string');
229
355
  }
230
356
  };
@@ -271,7 +397,6 @@ const walkValue = (value, transferrables, isTransferrable) => {
271
397
  for (const property of Object.values(value)) {
272
398
  walkValue(property, transferrables, isTransferrable);
273
399
  }
274
- return;
275
400
  }
276
401
  };
277
402
  const getTransferrables = value => {
@@ -425,7 +550,14 @@ class IpcError extends VError {
425
550
  const cause = new Error(message);
426
551
  // @ts-ignore
427
552
  cause.code = code;
428
- cause.stack = stack;
553
+ if (stack) {
554
+ Object.defineProperty(cause, 'stack', {
555
+ configurable: true,
556
+ enumerable: false,
557
+ value: stack,
558
+ writable: true
559
+ });
560
+ }
429
561
  super(cause, betterMessage);
430
562
  } else {
431
563
  super(betterMessage);
@@ -1295,13 +1427,178 @@ const ToolBar = 'toolbar';
1295
1427
  const Tree = 'tree';
1296
1428
  const TreeItem = 'treeitem';
1297
1429
 
1430
+ const Audio = 0;
1298
1431
  const Button$1 = 1;
1432
+ const Col = 2;
1433
+ const ColGroup = 3;
1299
1434
  const Div = 4;
1435
+ const H1 = 5;
1300
1436
  const Input = 6;
1437
+ const Kbd = 7;
1301
1438
  const Span = 8;
1439
+ const Table$1 = 9;
1440
+ const TBody = 10;
1441
+ const Td = 11;
1302
1442
  const Text = 12;
1443
+ const Th = 13;
1444
+ const THead = 14;
1445
+ const Tr = 15;
1446
+ const I = 16;
1303
1447
  const Img = 17;
1448
+ const Root = 0;
1449
+ const Ins = 20;
1450
+ const Del = 21;
1451
+ const H2 = 22;
1452
+ const H3 = 23;
1453
+ const H4 = 24;
1454
+ const H5 = 25;
1455
+ const H6 = 26;
1456
+ const Article = 27;
1457
+ const Aside = 28;
1458
+ const Footer = 29;
1459
+ const Header = 30;
1460
+ const Nav = 40;
1461
+ const Section = 41;
1462
+ const Search = 42;
1463
+ const Dd = 43;
1464
+ const Dl = 44;
1465
+ const Figcaption = 45;
1466
+ const Figure = 46;
1467
+ const Hr = 47;
1468
+ const Li = 48;
1469
+ const Ol = 49;
1470
+ const P = 50;
1471
+ const Pre = 51;
1304
1472
  const A = 53;
1473
+ const Abbr = 54;
1474
+ const Br = 55;
1475
+ const Cite = 56;
1476
+ const Data = 57;
1477
+ const Time = 58;
1478
+ const Tfoot = 59;
1479
+ const Ul = 60;
1480
+ const Video = 61;
1481
+ const TextArea = 62;
1482
+ const Select = 63;
1483
+ const Option = 64;
1484
+ const Code$1 = 65;
1485
+ const Label$1 = 66;
1486
+ const Dt = 67;
1487
+ const Iframe = 68;
1488
+ const Main = 69;
1489
+ const Strong = 70;
1490
+ const Em = 71;
1491
+ const Style = 72;
1492
+ const Html = 73;
1493
+ const Head = 74;
1494
+ const Title = 75;
1495
+ const Meta = 76;
1496
+ const Canvas = 77;
1497
+ const Form = 78;
1498
+ const BlockQuote = 79;
1499
+ const Quote = 80;
1500
+ const Circle = 81;
1501
+ const Defs = 82;
1502
+ const Ellipse = 83;
1503
+ const G = 84;
1504
+ const Line = 85;
1505
+ const Path = 86;
1506
+ const Polygon = 87;
1507
+ const Polyline = 88;
1508
+ const Rect = 89;
1509
+ const Svg = 90;
1510
+ const Use = 91;
1511
+ const Reference = 100;
1512
+
1513
+ const VirtualDomElements = {
1514
+ __proto__: null,
1515
+ A,
1516
+ Abbr,
1517
+ Article,
1518
+ Aside,
1519
+ Audio,
1520
+ BlockQuote,
1521
+ Br,
1522
+ Button: Button$1,
1523
+ Canvas,
1524
+ Circle,
1525
+ Cite,
1526
+ Code: Code$1,
1527
+ Col,
1528
+ ColGroup,
1529
+ Data,
1530
+ Dd,
1531
+ Defs,
1532
+ Del,
1533
+ Div,
1534
+ Dl,
1535
+ Dt,
1536
+ Ellipse,
1537
+ Em,
1538
+ Figcaption,
1539
+ Figure,
1540
+ Footer,
1541
+ Form,
1542
+ G,
1543
+ H1,
1544
+ H2,
1545
+ H3,
1546
+ H4,
1547
+ H5,
1548
+ H6,
1549
+ Head,
1550
+ Header,
1551
+ Hr,
1552
+ Html,
1553
+ I,
1554
+ Iframe,
1555
+ Img,
1556
+ Input,
1557
+ Ins,
1558
+ Kbd,
1559
+ Label: Label$1,
1560
+ Li,
1561
+ Line,
1562
+ Main,
1563
+ Meta,
1564
+ Nav,
1565
+ Ol,
1566
+ Option,
1567
+ P,
1568
+ Path,
1569
+ Polygon,
1570
+ Polyline,
1571
+ Pre,
1572
+ Quote,
1573
+ Rect,
1574
+ Reference,
1575
+ Root,
1576
+ Search,
1577
+ Section,
1578
+ Select,
1579
+ Span,
1580
+ Strong,
1581
+ Style,
1582
+ Svg,
1583
+ TBody,
1584
+ THead,
1585
+ Table: Table$1,
1586
+ Td,
1587
+ Text,
1588
+ TextArea,
1589
+ Tfoot,
1590
+ Th,
1591
+ Time,
1592
+ Title,
1593
+ Tr,
1594
+ Ul,
1595
+ Use,
1596
+ Video
1597
+ };
1598
+
1599
+ const ClientY = 'event.clientY';
1600
+ const DeltaMode = 'event.deltaMode';
1601
+ const DeltaY = 'event.deltaY';
1305
1602
 
1306
1603
  const Space = 9;
1307
1604
  const PageUp = 10;
@@ -1419,17 +1716,23 @@ const create = (id, uri, x, y, width, height, workspaceUri) => {
1419
1716
  const state = {
1420
1717
  activeUri: '',
1421
1718
  collapsedUris: [],
1719
+ deltaY: 0,
1422
1720
  filteredProblems: [],
1423
1721
  filterValue: '',
1722
+ finalDeltaY: 0,
1424
1723
  focusedIndex: -2,
1724
+ handleOffset: 0,
1425
1725
  height,
1426
1726
  inputSource: User,
1427
1727
  itemHeight: 22,
1428
1728
  listItems: [],
1429
1729
  maxLineY: 0,
1430
1730
  message: '',
1731
+ minimumSliderSize: 20,
1431
1732
  minLineY: 0,
1432
1733
  problems: [],
1734
+ scrollBarActive: false,
1735
+ scrollBarHeight: 0,
1433
1736
  showErrors: true,
1434
1737
  showInfos: true,
1435
1738
  showWarnings: true,
@@ -1445,15 +1748,26 @@ const create = (id, uri, x, y, width, height, workspaceUri) => {
1445
1748
  };
1446
1749
 
1447
1750
  const isEqual$2 = (oldState, newState) => {
1448
- return oldState.collapsedUris === newState.collapsedUris && oldState.filterValue === newState.filterValue && oldState.problems === newState.problems;
1751
+ return oldState.collapsedUris === newState.collapsedUris && oldState.deltaY === newState.deltaY && oldState.filterValue === newState.filterValue && oldState.finalDeltaY === newState.finalDeltaY && oldState.height === newState.height && oldState.itemHeight === newState.itemHeight && oldState.maxLineY === newState.maxLineY && oldState.minLineY === newState.minLineY && oldState.problems === newState.problems && oldState.scrollBarHeight === newState.scrollBarHeight && oldState.viewMode === newState.viewMode && oldState.width === newState.width;
1449
1752
  };
1450
1753
 
1451
1754
  const isEqual$1 = (oldState, newState) => {
1452
1755
  return newState.inputSource === User || oldState.filterValue === newState.filterValue;
1453
1756
  };
1454
1757
 
1758
+ const haveSameCollapsedUris = (oldState, newState) => {
1759
+ const oldCollapsedUris = oldState.collapsedUris;
1760
+ const newCollapsedUris = newState.collapsedUris;
1761
+ if (oldCollapsedUris === newCollapsedUris) {
1762
+ return true;
1763
+ }
1764
+ if (!oldCollapsedUris || !newCollapsedUris) {
1765
+ return false;
1766
+ }
1767
+ return oldCollapsedUris.length === newCollapsedUris.length && oldCollapsedUris.every((uri, index) => uri === newCollapsedUris[index]);
1768
+ };
1455
1769
  const isEqual = (oldState, newState) => {
1456
- return oldState.activeUri === newState.activeUri && oldState.problems === newState.problems && oldState.filterValue === newState.filterValue && oldState.message === newState.message && oldState.viewMode === newState.viewMode;
1770
+ return oldState.activeUri === newState.activeUri && haveSameCollapsedUris(oldState, newState) && oldState.focusedIndex === newState.focusedIndex && oldState.height === newState.height && oldState.maxLineY === newState.maxLineY && oldState.minLineY === newState.minLineY && oldState.problems === newState.problems && oldState.filterValue === newState.filterValue && oldState.message === newState.message && oldState.scrollBarActive === newState.scrollBarActive && oldState.scrollBarHeight === newState.scrollBarHeight && oldState.width === newState.width && oldState.viewMode === newState.viewMode;
1457
1771
  };
1458
1772
 
1459
1773
  const RenderItems = 1;
@@ -1474,12 +1788,132 @@ const diff = (oldState, newState) => {
1474
1788
  return diffResult;
1475
1789
  };
1476
1790
 
1791
+ const FilterHeight = 24;
1792
+ const TableHeaderHeight = 22;
1793
+ const getListTopOffset = (width, smallWidthBreakPoint, viewMode) => {
1794
+ const filterHeight = viewMode !== None && width <= smallWidthBreakPoint ? FilterHeight : 0;
1795
+ const tableHeaderHeight = viewMode === Table ? TableHeaderHeight : 0;
1796
+ return filterHeight + tableHeaderHeight;
1797
+ };
1798
+ const getListHeight = (height, width, smallWidthBreakPoint, viewMode) => {
1799
+ return Math.max(height - getListTopOffset(width, smallWidthBreakPoint, viewMode), 0);
1800
+ };
1801
+
1802
+ const getNumberOfVisibleItems = (listHeight, itemHeight) => {
1803
+ if (listHeight <= 0 || itemHeight <= 0) {
1804
+ return 0;
1805
+ }
1806
+ return Math.ceil(listHeight / itemHeight) + 1;
1807
+ };
1808
+
1809
+ const getScrollBarSize = (size, contentSize, minimumSliderSize) => {
1810
+ if (size <= 0 || size >= contentSize) {
1811
+ return 0;
1812
+ }
1813
+ return Math.min(Math.max(Math.round(size ** 2 / contentSize), minimumSliderSize), size);
1814
+ };
1815
+
1816
+ const matchesFilterValue = (string, filterValueLower) => {
1817
+ if (filterValueLower) {
1818
+ return string.toLowerCase().indexOf(filterValueLower);
1819
+ }
1820
+ return 0;
1821
+ };
1822
+
1823
+ const Item = 0;
1824
+ const Expanded = 1;
1825
+ const Collapsed = 2;
1826
+
1827
+ const getListItemType = (listItemType, isCollapsed) => {
1828
+ if (listItemType === Item) {
1829
+ return Item;
1830
+ }
1831
+ if (isCollapsed) {
1832
+ return Collapsed;
1833
+ }
1834
+ return Expanded;
1835
+ };
1836
+ const filterProblems = (problems, collapsedUris, filterValue) => {
1837
+ const filterValueLower = filterValue.toLowerCase();
1838
+ const filtered = [];
1839
+ for (const problem of problems) {
1840
+ const uriMatchIndex = matchesFilterValue(problem.uri, filterValueLower);
1841
+ const sourceMatchIndex = matchesFilterValue(problem.source, filterValueLower);
1842
+ const messageMatchIndex = matchesFilterValue(problem.message, filterValueLower);
1843
+ if (uriMatchIndex === -1 && sourceMatchIndex === -1 && messageMatchIndex === -1) {
1844
+ continue;
1845
+ }
1846
+ const isCollapsed = collapsedUris.includes(problem.uri);
1847
+ if (isCollapsed && problem.listItemType === Item) {
1848
+ continue;
1849
+ }
1850
+ filtered.push({
1851
+ ...problem,
1852
+ isCollapsed,
1853
+ listItemType: getListItemType(problem.listItemType, isCollapsed),
1854
+ messageMatchIndex,
1855
+ sourceMatchIndex,
1856
+ uriMatchIndex
1857
+ });
1858
+ }
1859
+ return filtered;
1860
+ };
1861
+
1862
+ const getVisibleProblemCount = (problems, collapsedUris, filterValue, viewMode) => {
1863
+ const filtered = filterProblems(problems, collapsedUris, filterValue);
1864
+ if (viewMode !== Table) {
1865
+ return filtered.length;
1866
+ }
1867
+ let count = 0;
1868
+ for (const problem of filtered) {
1869
+ if (problem.message) {
1870
+ count++;
1871
+ }
1872
+ }
1873
+ return count;
1874
+ };
1875
+
1876
+ const updateVirtualList = (state, newDeltaY) => {
1877
+ const {
1878
+ collapsedUris,
1879
+ deltaY: currentDeltaY,
1880
+ filterValue,
1881
+ height,
1882
+ itemHeight,
1883
+ minimumSliderSize,
1884
+ problems,
1885
+ smallWidthBreakPoint,
1886
+ viewMode,
1887
+ width
1888
+ } = state;
1889
+ const itemCount = getVisibleProblemCount(problems, collapsedUris, filterValue, viewMode);
1890
+ const listHeight = getListHeight(height, width, smallWidthBreakPoint, viewMode);
1891
+ const contentHeight = itemCount * itemHeight;
1892
+ const finalDeltaY = Math.max(contentHeight - listHeight, 0);
1893
+ const requestedDeltaY = newDeltaY ?? currentDeltaY;
1894
+ const deltaY = Math.min(Math.max(Number.isFinite(requestedDeltaY) ? requestedDeltaY : 0, 0), finalDeltaY);
1895
+ const minLineY = itemHeight > 0 ? Math.floor(deltaY / itemHeight) : 0;
1896
+ const visibleCount = getNumberOfVisibleItems(listHeight, itemHeight);
1897
+ const maxLineY = Math.min(minLineY + visibleCount, itemCount);
1898
+ const scrollBarHeight = getScrollBarSize(listHeight, contentHeight, minimumSliderSize);
1899
+ return {
1900
+ ...state,
1901
+ deltaY,
1902
+ finalDeltaY,
1903
+ maxLineY,
1904
+ minLineY,
1905
+ scrollBarHeight
1906
+ };
1907
+ };
1908
+
1477
1909
  const diff2 = uid => {
1478
1910
  const {
1479
1911
  newState,
1480
1912
  oldState
1481
1913
  } = get(uid);
1482
- const diffResult = diff(oldState, newState);
1914
+ const updatedState = updateVirtualList(newState);
1915
+ set(uid, oldState, updatedState);
1916
+ const diffResult = diff(oldState, updatedState);
1483
1917
  return diffResult;
1484
1918
  };
1485
1919
 
@@ -1502,6 +1936,8 @@ const text = data => {
1502
1936
  };
1503
1937
  };
1504
1938
 
1939
+ new Set(Object.values(VirtualDomElements));
1940
+
1505
1941
  const FocusProblems = 19;
1506
1942
 
1507
1943
  const getKeyBindings = () => {
@@ -1553,15 +1989,15 @@ const getKeyBindings = () => {
1553
1989
  };
1554
1990
 
1555
1991
  const emptyObject = {};
1556
- const RE_PLACEHOLDER = /\{(PH\d+)\}/g;
1557
1992
  const i18nString = (key, placeholders = emptyObject) => {
1558
1993
  if (placeholders === emptyObject) {
1559
1994
  return key;
1560
1995
  }
1561
- const replacer = (match, rest) => {
1562
- return placeholders[rest];
1563
- };
1564
- return key.replaceAll(RE_PLACEHOLDER, replacer);
1996
+ let result = key;
1997
+ for (const [placeholder, replacement] of Object.entries(placeholders)) {
1998
+ result = result.split(`{${placeholder}}`).join(String(replacement));
1999
+ }
2000
+ return result;
1565
2001
  };
1566
2002
 
1567
2003
  const ClearFilters = 'Clear Filters';
@@ -1687,10 +2123,6 @@ const {
1687
2123
  getProblems: getProblems$1,
1688
2124
  getUri} = EditorWorker;
1689
2125
 
1690
- const Item = 0;
1691
- const Expanded = 1;
1692
- const Collapsed = 2;
1693
-
1694
2126
  const toProblem = (diagnostic, index) => {
1695
2127
  const {
1696
2128
  code,
@@ -1922,19 +2354,27 @@ const getListIndex = (eventX, eventY, x, y, deltaY, itemHeight) => {
1922
2354
 
1923
2355
  const handleClickAt = (state, eventX, eventY) => {
1924
2356
  const {
2357
+ collapsedUris,
2358
+ deltaY,
2359
+ filterValue,
1925
2360
  itemHeight,
1926
2361
  problems,
2362
+ smallWidthBreakPoint,
2363
+ viewMode,
2364
+ width,
1927
2365
  x,
1928
2366
  y
1929
2367
  } = state;
1930
2368
 
1931
2369
  // TODO use functional focus rendering
1932
2370
  // Focus.setFocus(FocusKey.Problems)
1933
- if (problems.length === 0) {
2371
+ const problemCount = getVisibleProblemCount(problems, collapsedUris, filterValue, viewMode);
2372
+ if (problemCount === 0) {
1934
2373
  return focusIndex(state, -1);
1935
2374
  }
1936
- const index = getListIndex(eventX, eventY, x, y, 0, itemHeight);
1937
- if (index > problems.length) {
2375
+ const listTopOffset = getListTopOffset(width, smallWidthBreakPoint, viewMode);
2376
+ const index = getListIndex(eventX, eventY, x, y + listTopOffset, deltaY, itemHeight);
2377
+ if (index < 0 || index >= problemCount) {
1938
2378
  return focusIndex(state, -1);
1939
2379
  }
1940
2380
  return {
@@ -1989,6 +2429,109 @@ const handleIconThemeChange = state => {
1989
2429
  };
1990
2430
  };
1991
2431
 
2432
+ const handleScrollBarCaptureLost = state => {
2433
+ return {
2434
+ ...state,
2435
+ scrollBarActive: false
2436
+ };
2437
+ };
2438
+
2439
+ const getNewDeltaYPercent = (height, scrollBarHeight, relativeY) => {
2440
+ const halfScrollBarHeight = scrollBarHeight / 2;
2441
+ if (relativeY <= halfScrollBarHeight) {
2442
+ return {
2443
+ handleOffset: Math.max(relativeY, 0),
2444
+ percent: 0
2445
+ };
2446
+ }
2447
+ if (relativeY <= height - halfScrollBarHeight) {
2448
+ return {
2449
+ handleOffset: halfScrollBarHeight,
2450
+ percent: (relativeY - halfScrollBarHeight) / (height - scrollBarHeight)
2451
+ };
2452
+ }
2453
+ return {
2454
+ handleOffset: Math.min(scrollBarHeight - height + relativeY, scrollBarHeight),
2455
+ percent: 1
2456
+ };
2457
+ };
2458
+
2459
+ const getScrollBarTop = (height, finalDeltaY, deltaY, scrollBarHeight) => {
2460
+ if (finalDeltaY <= 0 || !Number.isFinite(finalDeltaY)) {
2461
+ return 0;
2462
+ }
2463
+ const scrollBarTop = Math.round(deltaY / finalDeltaY * (height - scrollBarHeight));
2464
+ return Number.isFinite(scrollBarTop) ? scrollBarTop : 0;
2465
+ };
2466
+
2467
+ const setDeltaY = (state, deltaY) => {
2468
+ return updateVirtualList(state, deltaY);
2469
+ };
2470
+
2471
+ const handleScrollBarClick = (state, eventY) => {
2472
+ const {
2473
+ deltaY,
2474
+ finalDeltaY,
2475
+ height,
2476
+ scrollBarHeight,
2477
+ smallWidthBreakPoint,
2478
+ viewMode,
2479
+ width,
2480
+ y
2481
+ } = state;
2482
+ const listTopOffset = getListTopOffset(width, smallWidthBreakPoint, viewMode);
2483
+ const listHeight = getListHeight(height, width, smallWidthBreakPoint, viewMode);
2484
+ const relativeY = eventY - y - listTopOffset;
2485
+ const scrollBarTop = getScrollBarTop(listHeight, finalDeltaY, deltaY, scrollBarHeight);
2486
+ const offsetInThumb = relativeY - scrollBarTop;
2487
+ if (offsetInThumb >= 0 && offsetInThumb < scrollBarHeight) {
2488
+ return {
2489
+ ...state,
2490
+ handleOffset: offsetInThumb,
2491
+ scrollBarActive: true
2492
+ };
2493
+ }
2494
+ const {
2495
+ handleOffset,
2496
+ percent
2497
+ } = getNewDeltaYPercent(listHeight, scrollBarHeight, relativeY);
2498
+ return {
2499
+ ...setDeltaY(state, percent * finalDeltaY),
2500
+ handleOffset,
2501
+ scrollBarActive: true
2502
+ };
2503
+ };
2504
+
2505
+ const handleScrollBarMove = (state, eventY) => {
2506
+ const {
2507
+ finalDeltaY,
2508
+ handleOffset,
2509
+ height,
2510
+ scrollBarActive,
2511
+ scrollBarHeight,
2512
+ smallWidthBreakPoint,
2513
+ viewMode,
2514
+ width,
2515
+ y
2516
+ } = state;
2517
+ if (!scrollBarActive) {
2518
+ return state;
2519
+ }
2520
+ const listTopOffset = getListTopOffset(width, smallWidthBreakPoint, viewMode);
2521
+ const listHeight = getListHeight(height, width, smallWidthBreakPoint, viewMode);
2522
+ const availableTrackHeight = listHeight - scrollBarHeight;
2523
+ const relativeY = eventY - y - listTopOffset - handleOffset;
2524
+ const percent = availableTrackHeight <= 0 ? 0 : relativeY / availableTrackHeight;
2525
+ return setDeltaY(state, percent * finalDeltaY);
2526
+ };
2527
+
2528
+ const handleWheel = (state, deltaMode, deltaY) => {
2529
+ const {
2530
+ deltaY: currentDeltaY
2531
+ } = state;
2532
+ return setDeltaY(state, currentDeltaY + deltaY);
2533
+ };
2534
+
1992
2535
  const initialize = async () => {
1993
2536
  // function is not needed anymore
1994
2537
  };
@@ -2086,48 +2629,6 @@ const getUniqueIndents = problems => {
2086
2629
  return uniqueIndents;
2087
2630
  };
2088
2631
 
2089
- const matchesFilterValue = (string, filterValueLower) => {
2090
- if (filterValueLower) {
2091
- return string.toLowerCase().indexOf(filterValueLower);
2092
- }
2093
- return 0;
2094
- };
2095
-
2096
- const getListItemType = (listItemType, isCollapsed) => {
2097
- if (listItemType === Item) {
2098
- return Item;
2099
- }
2100
- if (isCollapsed) {
2101
- return Collapsed;
2102
- }
2103
- return Expanded;
2104
- };
2105
- const filterProblems = (problems, collapsedUris, filterValue) => {
2106
- const filterValueLower = filterValue.toLowerCase();
2107
- const filtered = [];
2108
- for (const problem of problems) {
2109
- const uriMatchIndex = matchesFilterValue(problem.uri, filterValueLower);
2110
- const sourceMatchIndex = matchesFilterValue(problem.source, filterValueLower);
2111
- const messageMatchIndex = matchesFilterValue(problem.message, filterValueLower);
2112
- if (uriMatchIndex === -1 && sourceMatchIndex === -1 && messageMatchIndex === -1) {
2113
- continue;
2114
- }
2115
- const isCollapsed = collapsedUris.includes(problem.uri);
2116
- if (isCollapsed && problem.listItemType === Item) {
2117
- continue;
2118
- }
2119
- filtered.push({
2120
- ...problem,
2121
- isCollapsed,
2122
- listItemType: getListItemType(problem.listItemType, isCollapsed),
2123
- messageMatchIndex,
2124
- sourceMatchIndex,
2125
- uriMatchIndex
2126
- });
2127
- }
2128
- return filtered;
2129
- };
2130
-
2131
2632
  const getFileNameIcon = file => {
2132
2633
  return '';
2133
2634
  };
@@ -2139,7 +2640,7 @@ const getIcon = uri => {
2139
2640
  return getFileNameIcon();
2140
2641
  };
2141
2642
 
2142
- const getVisibleProblems = (problems, collapsedUris, focusedIndex, filterValue) => {
2643
+ const getVisibleProblems = (problems, collapsedUris, focusedIndex, filterValue, minLineY = 0, maxLineY = Infinity, viewMode = List) => {
2143
2644
  array(problems);
2144
2645
  array(collapsedUris);
2145
2646
  number(focusedIndex);
@@ -2147,8 +2648,10 @@ const getVisibleProblems = (problems, collapsedUris, focusedIndex, filterValue)
2147
2648
  const visibleItems = [];
2148
2649
  const filterValueLength = filterValue.length;
2149
2650
  const filtered = filterProblems(problems, collapsedUris, filterValue);
2150
- for (let i = 0; i < filtered.length; i++) {
2151
- const problem = filtered[i];
2651
+ const displayProblems = viewMode === Table ? filtered.filter(problem => problem.message) : filtered;
2652
+ const finalLineY = Math.min(maxLineY, displayProblems.length);
2653
+ for (let i = minLineY; i < finalLineY; i++) {
2654
+ const problem = displayProblems[i];
2152
2655
  visibleItems.push({
2153
2656
  ...problem,
2154
2657
  filterValueLength,
@@ -2163,14 +2666,62 @@ const getVisibleProblems = (problems, collapsedUris, focusedIndex, filterValue)
2163
2666
  const renderCss = (oldState, newState) => {
2164
2667
  const {
2165
2668
  collapsedUris,
2669
+ deltaY,
2166
2670
  filterValue,
2671
+ finalDeltaY,
2167
2672
  focusedIndex,
2673
+ height,
2674
+ itemHeight,
2675
+ maxLineY,
2676
+ minLineY,
2168
2677
  problems,
2169
- uid
2678
+ scrollBarHeight,
2679
+ smallWidthBreakPoint,
2680
+ uid,
2681
+ viewMode,
2682
+ width
2170
2683
  } = newState;
2171
- const visibleProblems = getVisibleProblems(problems, collapsedUris, focusedIndex, filterValue);
2684
+ const visibleProblems = getVisibleProblems(problems, collapsedUris, focusedIndex, filterValue, minLineY, maxLineY, viewMode);
2172
2685
  const uniqueIndents = getUniqueIndents(visibleProblems);
2173
- const css = uniqueIndents.map(getIndentRule).join('\n');
2686
+ const listHeight = getListHeight(height, width, smallWidthBreakPoint, viewMode);
2687
+ const scrollBarTop = getScrollBarTop(listHeight, finalDeltaY, deltaY, scrollBarHeight);
2688
+ const itemOffset = itemHeight > 0 ? -(deltaY % itemHeight) : 0;
2689
+ const rules = [`.Problems {
2690
+ display: flex;
2691
+ flex-direction: column;
2692
+ overflow: hidden;
2693
+ position: relative;
2694
+ }
2695
+ .ProblemsContent {
2696
+ flex: 1;
2697
+ min-height: 0;
2698
+ overflow: hidden;
2699
+ position: relative;
2700
+ }
2701
+ .ProblemsList {
2702
+ contain: strict;
2703
+ height: 100%;
2704
+ overflow: hidden;
2705
+ width: 100%;
2706
+ }
2707
+ .ProblemsTableBody {
2708
+ overflow: hidden;
2709
+ }
2710
+ .ProblemsTableRow {
2711
+ height: ${itemHeight}px;
2712
+ }
2713
+ .ProblemsContentTable > .ScrollBar {
2714
+ top: 22px;
2715
+ }
2716
+ .Problems .ScrollBarThumb {
2717
+ height: ${scrollBarHeight}px;
2718
+ translate: 0 ${scrollBarTop}px;
2719
+ }
2720
+ .ProblemsList > .Problem:first-child,
2721
+ .ProblemsTableBody > .ProblemsTableRow:first-child {
2722
+ margin-top: ${itemOffset}px;
2723
+ }`, ...uniqueIndents.map(getIndentRule)];
2724
+ const css = rules.join('\n');
2174
2725
  return [SetCss, uid, css];
2175
2726
  };
2176
2727
 
@@ -2200,6 +2751,8 @@ const ProblemAt = 'ProblemAt';
2200
2751
  const ProblemBadge = 'ProblemBadge';
2201
2752
  const ProblemLabel = 'ProblemLabel';
2202
2753
  const Problems = 'Problems';
2754
+ const ProblemsContent = 'ProblemsContent';
2755
+ const ProblemsContentTable = 'ProblemsContentTable';
2203
2756
  const ProblemSelected = 'ProblemSelected';
2204
2757
  const ProblemsErrorIcon = 'ProblemsErrorIcon';
2205
2758
  const ProblemsIcon = 'ProblemsIcon';
@@ -2211,6 +2764,10 @@ const ProblemsTableRow = 'ProblemsTableRow';
2211
2764
  const ProblemsTableRowItem = 'ProblemsTableRowItem';
2212
2765
  const ProblemsTableRowOdd = 'ProblemsTableRowOdd';
2213
2766
  const ProblemsWarningIcon = 'ProblemsWarningIcon';
2767
+ const ScrollBar = 'ScrollBar';
2768
+ const ScrollBarSmall = 'ScrollBarSmall';
2769
+ const ScrollBarThumb = 'ScrollBarThumb';
2770
+ const ScrollBarThumbActive = 'ScrollBarThumbActive';
2214
2771
  const Viewlet = 'Viewlet';
2215
2772
 
2216
2773
  const HandleBlur = 1;
@@ -2219,6 +2776,10 @@ const HandleContextMenu = 3;
2219
2776
  const HandleFilterInput = 4;
2220
2777
  const HandlePointerDown = 5;
2221
2778
  const HandleClickMoreFilters = 6;
2779
+ const HandleWheel = 7;
2780
+ const HandleScrollBarMove = 8;
2781
+ const HandleScrollBarPointerCaptureLost = 9;
2782
+ const HandleScrollBarPointerDown = 10;
2222
2783
 
2223
2784
  const getIconVirtualDom = (icon, type = Div) => {
2224
2785
  return {
@@ -2348,19 +2909,21 @@ const getFileIconVirtualDom = icon => {
2348
2909
 
2349
2910
  const Warning = 'warning';
2350
2911
 
2912
+ const warningIconNode = {
2913
+ childCount: 0,
2914
+ className: mergeClassNames(ProblemsIcon, ProblemsWarningIcon),
2915
+ type: Div
2916
+ };
2917
+ const errorIconNode = {
2918
+ childCount: 0,
2919
+ className: mergeClassNames(ProblemsIcon, ProblemsErrorIcon),
2920
+ type: Div
2921
+ };
2351
2922
  const getProblemsIconVirtualDom = type => {
2352
2923
  if (type === Warning) {
2353
- return {
2354
- childCount: 0,
2355
- className: mergeClassNames(ProblemsIcon, ProblemsWarningIcon),
2356
- type: Div
2357
- };
2924
+ return warningIconNode;
2358
2925
  }
2359
- return {
2360
- childCount: 0,
2361
- className: mergeClassNames(ProblemsIcon, ProblemsErrorIcon),
2362
- type: Div
2363
- };
2926
+ return errorIconNode;
2364
2927
  };
2365
2928
 
2366
2929
  // TODO compute detail message in getVisibleProblems
@@ -2574,14 +3137,14 @@ const messageNode = {
2574
3137
  className: Message,
2575
3138
  type: Div
2576
3139
  };
2577
- const getProblemsVirtualDom$1 = (viewMode, problems, filterValue, message) => {
2578
- if (problems.length === 0 && message) {
3140
+ const getProblemsVirtualDom$1 = (viewMode, problems, filterValue, message, problemCount = problems.length) => {
3141
+ if (problemCount === 0 && message) {
2579
3142
  return [messageNode, text(message)];
2580
3143
  }
2581
- if (problems.length === 0 && filterValue) {
3144
+ if (problemCount === 0 && filterValue) {
2582
3145
  return getNoResultsWithFilterVirtualDom();
2583
3146
  }
2584
- if (problems.length === 0) {
3147
+ if (problemCount === 0) {
2585
3148
  return getProblemsNoProblemsFoundVirtualDom();
2586
3149
  }
2587
3150
  if (viewMode === Table) {
@@ -2590,9 +3153,26 @@ const getProblemsVirtualDom$1 = (viewMode, problems, filterValue, message) => {
2590
3153
  return getProblemsListVirtualDom(problems);
2591
3154
  };
2592
3155
 
3156
+ const scrollBarNode = {
3157
+ childCount: 1,
3158
+ className: mergeClassNames(ScrollBar, ScrollBarSmall),
3159
+ onPointerDown: HandleScrollBarPointerDown,
3160
+ type: Div
3161
+ };
3162
+ const getScrollBarVirtualDom = (scrollBarHeight, scrollBarActive) => {
3163
+ if (scrollBarHeight <= 0) {
3164
+ return [];
3165
+ }
3166
+ return [scrollBarNode, {
3167
+ childCount: 0,
3168
+ className: mergeClassNames(ScrollBarThumb, scrollBarActive ? ScrollBarThumbActive : ''),
3169
+ type: Div
3170
+ }];
3171
+ };
3172
+
2593
3173
  const Focusable = 0;
2594
3174
 
2595
- const getProblemsVirtualDom = (activeUri, viewMode, problems, filterValue, isSmall, message) => {
3175
+ const getProblemsVirtualDom = (activeUri, viewMode, problems, filterValue, isSmall, message, scrollBarHeight = 0, scrollBarActive = false, problemCount = problems.length) => {
2596
3176
  const baseDom = {
2597
3177
  childCount: isSmall ? 2 : 1,
2598
3178
  className: mergeClassNames(Viewlet, Problems),
@@ -2600,6 +3180,7 @@ const getProblemsVirtualDom = (activeUri, viewMode, problems, filterValue, isSma
2600
3180
  onBlur: HandleBlur,
2601
3181
  onContextMenu: HandleContextMenu,
2602
3182
  onPointerDown: HandlePointerDown,
3183
+ onWheel: HandleWheel,
2603
3184
  tabIndex: Focusable,
2604
3185
  type: Div
2605
3186
  };
@@ -2607,8 +3188,15 @@ const getProblemsVirtualDom = (activeUri, viewMode, problems, filterValue, isSma
2607
3188
  badgeText: '',
2608
3189
  command: HandleFilterInput,
2609
3190
  placeholder: filter()}) : [];
2610
- const itemsDom = getProblemsVirtualDom$1(viewMode, problems, filterValue, message);
2611
- return [baseDom, ...filterDom, ...itemsDom];
3191
+ const itemsDom = getProblemsVirtualDom$1(viewMode, problems, filterValue, message, problemCount);
3192
+ const scrollBarDom = getScrollBarVirtualDom(scrollBarHeight, scrollBarActive);
3193
+ const contentClassName = viewMode === Table ? mergeClassNames(ProblemsContent, ProblemsContentTable) : ProblemsContent;
3194
+ const contentDom = {
3195
+ childCount: scrollBarDom.length > 0 ? 2 : 1,
3196
+ className: contentClassName,
3197
+ type: Div
3198
+ };
3199
+ return [baseDom, ...filterDom, contentDom, ...itemsDom, ...scrollBarDom];
2612
3200
  };
2613
3201
 
2614
3202
  const renderItems = (oldState, newState) => {
@@ -2617,15 +3205,20 @@ const renderItems = (oldState, newState) => {
2617
3205
  collapsedUris,
2618
3206
  filterValue,
2619
3207
  focusedIndex,
3208
+ maxLineY,
2620
3209
  message,
3210
+ minLineY,
2621
3211
  problems,
3212
+ scrollBarActive,
3213
+ scrollBarHeight,
2622
3214
  smallWidthBreakPoint,
2623
3215
  viewMode,
2624
3216
  width
2625
3217
  } = newState;
2626
- const visible = getVisibleProblems(problems, collapsedUris, focusedIndex, filterValue);
3218
+ const problemCount = getVisibleProblemCount(problems, collapsedUris, filterValue, viewMode);
3219
+ const visible = getVisibleProblems(problems, collapsedUris, focusedIndex, filterValue, minLineY, maxLineY, viewMode);
2627
3220
  const isSmall = width <= smallWidthBreakPoint;
2628
- const dom = getProblemsVirtualDom(activeUri, viewMode, visible, filterValue, isSmall, message);
3221
+ const dom = getProblemsVirtualDom(activeUri, viewMode, visible, filterValue, isSmall, message, scrollBarHeight, scrollBarActive, problemCount);
2629
3222
  return ['Viewlet.setDom2', dom];
2630
3223
  };
2631
3224
 
@@ -2692,7 +3285,7 @@ const getActions = state => {
2692
3285
  viewMode,
2693
3286
  width
2694
3287
  } = state;
2695
- const visibleCount = getVisibleProblems(problems, collapsedUris, focusedIndex, filterValue).length;
3288
+ const visibleCount = getVisibleProblems(problems, collapsedUris, focusedIndex, filterValue, 0, Infinity, viewMode).length;
2696
3289
  const problemsCount = problems.length;
2697
3290
  const isSmall = width <= smallWidthBreakPoint;
2698
3291
  const actions = [];
@@ -2759,6 +3352,21 @@ const renderEventListeners = () => {
2759
3352
  }, {
2760
3353
  name: HandleClickMoreFilters,
2761
3354
  params: ['handleClickMoreFilters']
3355
+ }, {
3356
+ name: HandleWheel,
3357
+ params: ['handleWheel', DeltaMode, DeltaY],
3358
+ passive: true
3359
+ }, {
3360
+ name: HandleScrollBarPointerDown,
3361
+ params: ['handleScrollBarClick', ClientY],
3362
+ preventDefault: true,
3363
+ trackPointerEvents: [HandleScrollBarMove, HandleScrollBarPointerCaptureLost]
3364
+ }, {
3365
+ name: HandleScrollBarMove,
3366
+ params: ['handleScrollBarMove', ClientY]
3367
+ }, {
3368
+ name: HandleScrollBarPointerCaptureLost,
3369
+ params: ['handleScrollBarCaptureLost']
2762
3370
  }];
2763
3371
  };
2764
3372
 
@@ -2815,6 +3423,10 @@ const commandMap = {
2815
3423
  'Problems.handleContextMenu': wrapCommand(handleContextMenu),
2816
3424
  'Problems.handleFilterInput': wrapCommand(handleFilterInput),
2817
3425
  'Problems.handleIconThemeChange': wrapCommand(handleIconThemeChange),
3426
+ 'Problems.handleScrollBarCaptureLost': wrapCommand(handleScrollBarCaptureLost),
3427
+ 'Problems.handleScrollBarClick': wrapCommand(handleScrollBarClick),
3428
+ 'Problems.handleScrollBarMove': wrapCommand(handleScrollBarMove),
3429
+ 'Problems.handleWheel': wrapCommand(handleWheel),
2818
3430
  'Problems.initialize': initialize,
2819
3431
  'Problems.loadContent': wrapCommand(loadContent),
2820
3432
  'Problems.render2': render2,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/problems-view",
3
- "version": "1.25.4",
3
+ "version": "1.26.0",
4
4
  "description": "Problems View Worker",
5
5
  "repository": {
6
6
  "type": "git",