@lvce-editor/main-process 1.0.3
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/LICENSE +21 -0
- package/README.md +17 -0
- package/dist/mainProcessMain.js +9666 -0
- package/package.json +23 -0
- package/pages/error/error.css +18 -0
- package/pages/error/error.html +11 -0
- package/pages/error/error.js +22 -0
- package/pages/error/errorMessage.js +26 -0
- package/pages/process-explorer/process-explorer.css +70 -0
- package/pages/process-explorer/process-explorer.html +32 -0
- package/pages/process-explorer/process-explorer.js +1039 -0
- package/pages/quickpick/QuickPickElements.js +12 -0
- package/pages/quickpick/QuickPickEvents.js +88 -0
- package/pages/quickpick/QuickPickFunctions.js +54 -0
- package/pages/quickpick/QuickPickIpc.js +36 -0
- package/pages/quickpick/QuickPickKeyBindings.js +13 -0
- package/pages/quickpick/preload.js +9 -0
- package/pages/quickpick/quickpick.html +117 -0
- package/pages/quickpick/quickpick.js +48 -0
- package/pages/suggestions/Ipc.js +36 -0
- package/pages/suggestions/preload.js +9 -0
- package/pages/suggestions/suggestions.html +16 -0
- package/pages/suggestions/suggestions.js +8 -0
|
@@ -0,0 +1,1039 @@
|
|
|
1
|
+
// The process explorer tries to implement the ARIA TreeGrid Design Pattern https://w3c.github.io/aria-practices/examples/treegrid/treegrid-1.html
|
|
2
|
+
|
|
3
|
+
const state = {
|
|
4
|
+
displayProcesses: [],
|
|
5
|
+
collapsed: [],
|
|
6
|
+
processes: [],
|
|
7
|
+
$Tbody: undefined,
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const formatMemory = (memory) => {
|
|
11
|
+
if (memory < 1000) {
|
|
12
|
+
return `${memory} B`
|
|
13
|
+
}
|
|
14
|
+
if (memory < 1000 ** 2) {
|
|
15
|
+
return `${(memory / 1000 ** 1).toFixed(1)} kB`
|
|
16
|
+
}
|
|
17
|
+
if (memory < 1000 ** 3) {
|
|
18
|
+
return `${(memory / 1000 ** 2).toFixed(1)} MB`
|
|
19
|
+
}
|
|
20
|
+
if (memory < 1000 ** 4) {
|
|
21
|
+
return `${(memory / 1000 ** 3).toFixed(1)} GB`
|
|
22
|
+
}
|
|
23
|
+
return `${(memory / 1000 ** 4).toFixed(1)} TB`
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const getDisplayProcesses = (processes) => {
|
|
27
|
+
const displayProcesses = []
|
|
28
|
+
|
|
29
|
+
const getChildren = (process, depth) => {
|
|
30
|
+
const children = []
|
|
31
|
+
for (const otherProcess of processes) {
|
|
32
|
+
if (otherProcess.ppid === process.pid) {
|
|
33
|
+
children.push(...withChildren(otherProcess, depth))
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return children
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const withChildren = (process, depth) => {
|
|
40
|
+
const children = getChildren(process, depth + 1)
|
|
41
|
+
if (children.length === 0) {
|
|
42
|
+
const displayProcess = {
|
|
43
|
+
...process,
|
|
44
|
+
flags: 0,
|
|
45
|
+
depth,
|
|
46
|
+
// posInSet,
|
|
47
|
+
// setSize,
|
|
48
|
+
}
|
|
49
|
+
return [displayProcess]
|
|
50
|
+
}
|
|
51
|
+
if (state.collapsed.includes(process.pid)) {
|
|
52
|
+
const displayProcess = {
|
|
53
|
+
...process,
|
|
54
|
+
flags: 1,
|
|
55
|
+
depth,
|
|
56
|
+
|
|
57
|
+
// posInSet,
|
|
58
|
+
// setSize,
|
|
59
|
+
}
|
|
60
|
+
return [displayProcess]
|
|
61
|
+
}
|
|
62
|
+
const displayProcess = {
|
|
63
|
+
...process,
|
|
64
|
+
flags: 2,
|
|
65
|
+
depth,
|
|
66
|
+
|
|
67
|
+
// posInSet,
|
|
68
|
+
// setSize,
|
|
69
|
+
}
|
|
70
|
+
return [displayProcess, ...children]
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const topProcess = processes[0]
|
|
74
|
+
displayProcesses.push(...withChildren(topProcess, 1))
|
|
75
|
+
return displayProcesses
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const focusElement = ($Element) => {
|
|
79
|
+
$Element.tabIndex = 0
|
|
80
|
+
$Element.focus()
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const getNodeIndex = ($Node) => {
|
|
84
|
+
let index = 0
|
|
85
|
+
while (($Node = $Node.previousElementSibling)) {
|
|
86
|
+
index++
|
|
87
|
+
}
|
|
88
|
+
return index
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const handleClickIndex = (index) => {
|
|
92
|
+
const displayProcess = state.displayProcesses[index]
|
|
93
|
+
const collapsedIndex = state.collapsed.indexOf(displayProcess.pid)
|
|
94
|
+
if (collapsedIndex === -1) {
|
|
95
|
+
state.collapsed.push(displayProcess.pid)
|
|
96
|
+
} else {
|
|
97
|
+
state.collapsed.splice(collapsedIndex, 1)
|
|
98
|
+
}
|
|
99
|
+
renderProcesses(state.processes)
|
|
100
|
+
const oldFocusedElement = state.$Tbody.querySelector('[tabIndex="0"]')
|
|
101
|
+
if (oldFocusedElement) {
|
|
102
|
+
oldFocusedElement.tabIndex = -1
|
|
103
|
+
}
|
|
104
|
+
const newFocusedElement = state.$Tbody.children[index]
|
|
105
|
+
if (newFocusedElement) {
|
|
106
|
+
newFocusedElement.tabIndex = 0
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const handleDoubleClick = (event) => {
|
|
111
|
+
const $Target = event.target
|
|
112
|
+
switch ($Target.className) {
|
|
113
|
+
case 'Row': {
|
|
114
|
+
const index = getNodeIndex($Target)
|
|
115
|
+
handleClickIndex(index)
|
|
116
|
+
break
|
|
117
|
+
}
|
|
118
|
+
case 'Cell': {
|
|
119
|
+
const index = getNodeIndex($Target.parentNode)
|
|
120
|
+
handleClickIndex(index)
|
|
121
|
+
break
|
|
122
|
+
}
|
|
123
|
+
default:
|
|
124
|
+
throw new Error('unexpected class name')
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const handleFocusIn = (event) => {
|
|
129
|
+
const oldFocusedElement = state.$Tbody.querySelector('[tabIndex="0"]')
|
|
130
|
+
const $Target = event.target
|
|
131
|
+
if (oldFocusedElement) {
|
|
132
|
+
oldFocusedElement.tabIndex = -1
|
|
133
|
+
}
|
|
134
|
+
$Target.tabIndex = 0
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const handleHomeRow = ($ActiveElement) => {
|
|
138
|
+
const $FirstRow = $ActiveElement.parentElement.firstElementChild
|
|
139
|
+
$FirstRow.focus()
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const handleHomeCell = ($ActiveElement, control) => {
|
|
143
|
+
if (control) {
|
|
144
|
+
const index = getNodeIndex($ActiveElement)
|
|
145
|
+
const $FirstRow = $ActiveElement.parentElement.parentElement.firstElementChild
|
|
146
|
+
const $TopCell = $FirstRow.children[index]
|
|
147
|
+
$TopCell.focus()
|
|
148
|
+
return
|
|
149
|
+
}
|
|
150
|
+
const $FirstCell = $ActiveElement.parentElement.firstElementChild
|
|
151
|
+
$FirstCell.focus()
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const handleHome = (control) => {
|
|
155
|
+
const $ActiveElement = document.activeElement
|
|
156
|
+
switch ($ActiveElement.className) {
|
|
157
|
+
case 'Row':
|
|
158
|
+
handleHomeRow($ActiveElement)
|
|
159
|
+
break
|
|
160
|
+
case 'Cell':
|
|
161
|
+
handleHomeCell($ActiveElement, control)
|
|
162
|
+
break
|
|
163
|
+
default:
|
|
164
|
+
break
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const handleArrowUpRow = ($ActiveElement) => {
|
|
169
|
+
const $RowAbove = $ActiveElement.previousElementSibling
|
|
170
|
+
if (!$RowAbove) {
|
|
171
|
+
return
|
|
172
|
+
}
|
|
173
|
+
// @ts-ignore
|
|
174
|
+
$RowAbove.focus()
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const handleArrowUpCell = ($ActiveElement) => {
|
|
178
|
+
const index = getNodeIndex($ActiveElement)
|
|
179
|
+
const $RowAbove = $ActiveElement.parentElement.previousElementSibling
|
|
180
|
+
if (!$RowAbove) {
|
|
181
|
+
return
|
|
182
|
+
}
|
|
183
|
+
const $CellAbove = $RowAbove.children[index]
|
|
184
|
+
// @ts-ignore
|
|
185
|
+
$CellAbove.focus()
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const handleArrowUp = () => {
|
|
189
|
+
const $ActiveElement = document.activeElement
|
|
190
|
+
switch ($ActiveElement.className) {
|
|
191
|
+
case 'Row':
|
|
192
|
+
handleArrowUpRow($ActiveElement)
|
|
193
|
+
break
|
|
194
|
+
case 'Cell':
|
|
195
|
+
handleArrowUpCell($ActiveElement)
|
|
196
|
+
break
|
|
197
|
+
default:
|
|
198
|
+
break
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const handleArrowDownRow = ($ActiveElement) => {
|
|
203
|
+
const $RowBelow = $ActiveElement.nextElementSibling
|
|
204
|
+
if (!$RowBelow) {
|
|
205
|
+
return
|
|
206
|
+
}
|
|
207
|
+
// @ts-ignore
|
|
208
|
+
$RowBelow.focus()
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const handleArrowDownCell = ($ActiveElement) => {
|
|
212
|
+
const index = getNodeIndex($ActiveElement)
|
|
213
|
+
const $RowBelow = $ActiveElement.parentElement.nextElementSibling
|
|
214
|
+
if (!$RowBelow) {
|
|
215
|
+
return
|
|
216
|
+
}
|
|
217
|
+
const $CellBelow = $RowBelow.children[index]
|
|
218
|
+
// @ts-ignore
|
|
219
|
+
$CellBelow.focus()
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const handleArrowDown = () => {
|
|
223
|
+
const $ActiveElement = document.activeElement
|
|
224
|
+
switch ($ActiveElement.className) {
|
|
225
|
+
case 'Row':
|
|
226
|
+
handleArrowDownRow($ActiveElement)
|
|
227
|
+
break
|
|
228
|
+
case 'Cell':
|
|
229
|
+
handleArrowDownCell($ActiveElement)
|
|
230
|
+
break
|
|
231
|
+
default:
|
|
232
|
+
break
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const handleEndRow = ($ActiveElement) => {
|
|
237
|
+
const $LastRow = $ActiveElement.parentElement.lastElementChild
|
|
238
|
+
$LastRow.focus()
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const handleEndCell = ($ActiveElement, control) => {
|
|
242
|
+
if (control) {
|
|
243
|
+
const index = getNodeIndex($ActiveElement)
|
|
244
|
+
const $LastRow = $ActiveElement.parentElement.parentElement.lastElementChild
|
|
245
|
+
const $BottomCell = $LastRow.children[index]
|
|
246
|
+
$BottomCell.focus()
|
|
247
|
+
return
|
|
248
|
+
}
|
|
249
|
+
const $LastCell = $ActiveElement.parentElement.lastElementChild
|
|
250
|
+
$LastCell.focus()
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const handleEnd = (control) => {
|
|
254
|
+
const $ActiveElement = document.activeElement
|
|
255
|
+
switch ($ActiveElement.className) {
|
|
256
|
+
case 'Row':
|
|
257
|
+
handleEndRow($ActiveElement)
|
|
258
|
+
break
|
|
259
|
+
case 'Cell':
|
|
260
|
+
handleEndCell($ActiveElement, control)
|
|
261
|
+
break
|
|
262
|
+
default:
|
|
263
|
+
break
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const handleArrowRightRow = ($ActiveElement) => {
|
|
268
|
+
if ($ActiveElement.ariaExpanded === 'false') {
|
|
269
|
+
const index = getNodeIndex($ActiveElement)
|
|
270
|
+
const displayProcess = state.displayProcesses[index]
|
|
271
|
+
const collapsedIndex = state.collapsed.indexOf(displayProcess.pid)
|
|
272
|
+
state.collapsed.splice(collapsedIndex, 1)
|
|
273
|
+
renderProcesses(state.processes)
|
|
274
|
+
return
|
|
275
|
+
}
|
|
276
|
+
const $Cell = $ActiveElement.firstElementChild
|
|
277
|
+
// @ts-ignore
|
|
278
|
+
$Cell.focus()
|
|
279
|
+
// @ts-ignore
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const handleArrowRightCell = ($ActiveElement) => {
|
|
283
|
+
// TODO focus next cell
|
|
284
|
+
const $NextCell = $ActiveElement.nextElementSibling
|
|
285
|
+
if (!$NextCell) {
|
|
286
|
+
return
|
|
287
|
+
}
|
|
288
|
+
// @ts-ignore
|
|
289
|
+
$NextCell.focus()
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const handleArrowRight = () => {
|
|
293
|
+
const $ActiveElement = document.activeElement
|
|
294
|
+
switch ($ActiveElement.className) {
|
|
295
|
+
case 'Row':
|
|
296
|
+
handleArrowRightRow($ActiveElement)
|
|
297
|
+
break
|
|
298
|
+
case 'Cell':
|
|
299
|
+
handleArrowRightCell($ActiveElement)
|
|
300
|
+
break
|
|
301
|
+
default:
|
|
302
|
+
break
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const handleArrowLeftRow = ($ActiveElement) => {
|
|
307
|
+
if ($ActiveElement.ariaExpanded === 'true') {
|
|
308
|
+
const index = getNodeIndex($ActiveElement)
|
|
309
|
+
const displayProcess = state.displayProcesses[index]
|
|
310
|
+
state.collapsed.push(displayProcess.pid)
|
|
311
|
+
renderProcesses(state.processes)
|
|
312
|
+
return
|
|
313
|
+
}
|
|
314
|
+
const index = getNodeIndex($ActiveElement)
|
|
315
|
+
const displayProcess = state.displayProcesses[index]
|
|
316
|
+
for (let i = index; i >= 0; i--) {
|
|
317
|
+
const otherProcess = state.displayProcesses[i]
|
|
318
|
+
if (otherProcess.depth === displayProcess.depth - 1) {
|
|
319
|
+
const $Row = state.$Tbody.children[i]
|
|
320
|
+
$Row.focus()
|
|
321
|
+
break
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const handleArrowLeftCell = ($ActiveElement) => {
|
|
327
|
+
const $PreviousCell = $ActiveElement.previousElementSibling
|
|
328
|
+
if ($PreviousCell) {
|
|
329
|
+
// @ts-ignore
|
|
330
|
+
$PreviousCell.focus()
|
|
331
|
+
return
|
|
332
|
+
}
|
|
333
|
+
const $Row = $ActiveElement.parentNode
|
|
334
|
+
// @ts-ignore
|
|
335
|
+
$Row.focus()
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
const handleArrowLeft = () => {
|
|
339
|
+
const $ActiveElement = document.activeElement
|
|
340
|
+
switch ($ActiveElement.className) {
|
|
341
|
+
case 'Row':
|
|
342
|
+
handleArrowLeftRow($ActiveElement)
|
|
343
|
+
break
|
|
344
|
+
case 'Cell':
|
|
345
|
+
handleArrowLeftCell($ActiveElement)
|
|
346
|
+
break
|
|
347
|
+
default:
|
|
348
|
+
break
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const handleMouseDownCell = () => {}
|
|
353
|
+
|
|
354
|
+
const handleMouseDown = (event) => {
|
|
355
|
+
const $Target = event.target
|
|
356
|
+
const $ActiveElement = document.activeElement
|
|
357
|
+
if ($Target === $ActiveElement) {
|
|
358
|
+
return
|
|
359
|
+
}
|
|
360
|
+
if ($Target.className === 'Cell') {
|
|
361
|
+
event.preventDefault()
|
|
362
|
+
$Target.parentElement.focus()
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
const IsDebuggable = {
|
|
367
|
+
isDebuggable(command) {
|
|
368
|
+
return command.includes('node ') || command.includes('node.exe') || command.includes('node.mojom.NodeService')
|
|
369
|
+
},
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
const UiStrings = {
|
|
373
|
+
KillProcess: 'Kill Process',
|
|
374
|
+
DebugProcess: 'Debug Process',
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
const getMenuItems = (displayProcess) => {
|
|
378
|
+
const menuItems = [
|
|
379
|
+
{
|
|
380
|
+
label: UiStrings.KillProcess,
|
|
381
|
+
},
|
|
382
|
+
]
|
|
383
|
+
if (IsDebuggable.isDebuggable(displayProcess.cmd)) {
|
|
384
|
+
menuItems.push({
|
|
385
|
+
label: UiStrings.DebugProcess,
|
|
386
|
+
})
|
|
387
|
+
}
|
|
388
|
+
return menuItems
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
const handleContextMenuSelect = (label, displayProcess) => {
|
|
392
|
+
switch (label) {
|
|
393
|
+
case UiStrings.DebugProcess:
|
|
394
|
+
return ProcessExplorer.invoke('AttachDebugger.attachDebugger', displayProcess.pid)
|
|
395
|
+
case UiStrings.KillProcess:
|
|
396
|
+
return ProcessExplorer.invoke('Process.kill', displayProcess.pid)
|
|
397
|
+
default:
|
|
398
|
+
break
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const processExplorerShowContextMenu = async (displayProcess, x, y) => {
|
|
403
|
+
const menuItems = getMenuItems(displayProcess)
|
|
404
|
+
const customData = displayProcess
|
|
405
|
+
const event = await ProcessExplorer.invoke('ElectronContextMenu.openContextMenu', menuItems, x, y, customData)
|
|
406
|
+
if (event.type === 'close') {
|
|
407
|
+
return
|
|
408
|
+
}
|
|
409
|
+
handleContextMenuSelect(event.data, displayProcess)
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
const handleContextMenu = async (event) => {
|
|
413
|
+
event.preventDefault()
|
|
414
|
+
const { clientX, clientY } = event
|
|
415
|
+
const $Target = event.target
|
|
416
|
+
|
|
417
|
+
const $Row = $Target.parentNode
|
|
418
|
+
const index = getNodeIndex($Row)
|
|
419
|
+
|
|
420
|
+
const displayProcess = state.displayProcesses[index]
|
|
421
|
+
await processExplorerShowContextMenu(displayProcess, clientX, clientY)
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
*
|
|
426
|
+
* @param {KeyboardEvent} event
|
|
427
|
+
*/
|
|
428
|
+
const handleKeyDown = (event) => {
|
|
429
|
+
const { key } = event
|
|
430
|
+
const control = event.ctrlKey
|
|
431
|
+
switch (key) {
|
|
432
|
+
case 'ArrowDown':
|
|
433
|
+
event.preventDefault()
|
|
434
|
+
handleArrowDown()
|
|
435
|
+
break
|
|
436
|
+
case 'ArrowUp':
|
|
437
|
+
event.preventDefault()
|
|
438
|
+
handleArrowUp()
|
|
439
|
+
break
|
|
440
|
+
case 'Home':
|
|
441
|
+
event.preventDefault()
|
|
442
|
+
handleHome(control)
|
|
443
|
+
break
|
|
444
|
+
case 'End':
|
|
445
|
+
event.preventDefault()
|
|
446
|
+
handleEnd(control)
|
|
447
|
+
break
|
|
448
|
+
case 'ArrowRight':
|
|
449
|
+
event.preventDefault()
|
|
450
|
+
handleArrowRight()
|
|
451
|
+
break
|
|
452
|
+
case 'ArrowLeft':
|
|
453
|
+
event.preventDefault()
|
|
454
|
+
handleArrowLeft()
|
|
455
|
+
break
|
|
456
|
+
default:
|
|
457
|
+
break
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
const ProcessFlag = {
|
|
462
|
+
None: 0,
|
|
463
|
+
Collapsed: 1,
|
|
464
|
+
Expanded: 2,
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
const getPaddingLeft = (process) => {
|
|
468
|
+
if (process.depth === 1) {
|
|
469
|
+
return '0'
|
|
470
|
+
}
|
|
471
|
+
const depthCh = (process.depth - 1) * 1.5
|
|
472
|
+
if (process.flags === ProcessFlag.None) {
|
|
473
|
+
return `calc(${depthCh}ch + 17px)`
|
|
474
|
+
}
|
|
475
|
+
return `${depthCh}ch`
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
const render$Process = ($Process, process) => {
|
|
479
|
+
$Process.ariaLevel = process.depth
|
|
480
|
+
$Process.firstChild.style.paddingLeft = getPaddingLeft(process)
|
|
481
|
+
$Process.title = process.cmd
|
|
482
|
+
switch (process.flags) {
|
|
483
|
+
case ProcessFlag.None:
|
|
484
|
+
$Process.removeAttribute('aria-expanded')
|
|
485
|
+
break
|
|
486
|
+
case ProcessFlag.Collapsed:
|
|
487
|
+
$Process.ariaExpanded = false
|
|
488
|
+
break
|
|
489
|
+
case ProcessFlag.Expanded:
|
|
490
|
+
$Process.ariaExpanded = true
|
|
491
|
+
break
|
|
492
|
+
default:
|
|
493
|
+
break
|
|
494
|
+
}
|
|
495
|
+
const $Name = $Process.children[0]
|
|
496
|
+
const $Id = $Process.children[1]
|
|
497
|
+
const $Memory = $Process.children[2]
|
|
498
|
+
|
|
499
|
+
const { name } = process
|
|
500
|
+
const id = `${process.pid}`
|
|
501
|
+
const memory = formatMemory(process.memory)
|
|
502
|
+
|
|
503
|
+
if ($Name.firstChild.nodeValue !== name) {
|
|
504
|
+
$Name.firstChild.nodeValue = name
|
|
505
|
+
}
|
|
506
|
+
if ($Id.firstChild.nodeValue !== id) {
|
|
507
|
+
$Id.firstChild.nodeValue = id
|
|
508
|
+
}
|
|
509
|
+
if ($Memory.firstChild.nodeValue !== memory) {
|
|
510
|
+
$Memory.firstChild.nodeValue = memory
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
const create$GridCell = () => {
|
|
515
|
+
const $Cell = document.createElement('td')
|
|
516
|
+
$Cell.className = 'Cell'
|
|
517
|
+
// @ts-ignore
|
|
518
|
+
$Cell.role = 'gridcell'
|
|
519
|
+
$Cell.tabIndex = -1
|
|
520
|
+
const $Text = document.createTextNode('')
|
|
521
|
+
$Cell.append($Text)
|
|
522
|
+
return $Cell
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
const create$Row = () => {
|
|
526
|
+
const $Row = document.createElement('tr')
|
|
527
|
+
$Row.className = 'Row'
|
|
528
|
+
// @ts-ignore
|
|
529
|
+
$Row.role = 'row'
|
|
530
|
+
$Row.tabIndex = -1
|
|
531
|
+
// Set aria-description to empty string so that screen readers don't read title as well
|
|
532
|
+
// More details https://github.com/microsoft/vscode/issues/95378
|
|
533
|
+
$Row.setAttribute('aria-description', '')
|
|
534
|
+
const $Name = create$GridCell()
|
|
535
|
+
const $Id = create$GridCell()
|
|
536
|
+
const $Memory = create$GridCell()
|
|
537
|
+
$Row.append($Name, $Id, $Memory)
|
|
538
|
+
return $Row
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
const render$ProcessesLess = ($Processes, processes) => {
|
|
542
|
+
for (let i = 0; i < $Processes.children.length; i++) {
|
|
543
|
+
render$Process($Processes.children[i], processes[i])
|
|
544
|
+
}
|
|
545
|
+
const fragment = document.createDocumentFragment()
|
|
546
|
+
for (let i = $Processes.children.length; i < processes.length; i++) {
|
|
547
|
+
const $Process = create$Row()
|
|
548
|
+
render$Process($Process, processes[i])
|
|
549
|
+
fragment.append($Process)
|
|
550
|
+
}
|
|
551
|
+
$Processes.append(fragment)
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
const render$ProcessesEqual = ($Processes, processes) => {
|
|
555
|
+
for (const [i, process_] of processes.entries()) {
|
|
556
|
+
render$Process($Processes.children[i], process_)
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
const render$ProcessesMore = ($Processes, processes) => {
|
|
561
|
+
for (const [i, process_] of processes.entries()) {
|
|
562
|
+
render$Process($Processes.children[i], process_)
|
|
563
|
+
}
|
|
564
|
+
const diff = $Processes.children.length - processes.length
|
|
565
|
+
for (let i = processes.length; i < processes.length + diff; i++) {
|
|
566
|
+
$Processes.lastChild.remove()
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
const renderProcesses = (processes) => {
|
|
571
|
+
const displayProcesses = getDisplayProcesses(processes)
|
|
572
|
+
state.processes = processes
|
|
573
|
+
state.displayProcesses = displayProcesses
|
|
574
|
+
const $Tbody = document.querySelector('tbody')
|
|
575
|
+
if (!$Tbody) {
|
|
576
|
+
return
|
|
577
|
+
}
|
|
578
|
+
if ($Tbody.children.length < displayProcesses.length) {
|
|
579
|
+
render$ProcessesLess($Tbody, displayProcesses)
|
|
580
|
+
} else if ($Tbody.children.length === displayProcesses.length) {
|
|
581
|
+
render$ProcessesEqual($Tbody, displayProcesses)
|
|
582
|
+
} else {
|
|
583
|
+
render$ProcessesMore($Tbody, displayProcesses)
|
|
584
|
+
}
|
|
585
|
+
$Tbody.ondblclick = handleDoubleClick
|
|
586
|
+
$Tbody.onkeydown = handleKeyDown
|
|
587
|
+
$Tbody.addEventListener('focusin', handleFocusIn, { capture: true })
|
|
588
|
+
$Tbody.onmousedown = handleMouseDown
|
|
589
|
+
$Tbody.oncontextmenu = handleContextMenu
|
|
590
|
+
state.$Tbody = $Tbody
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
const Id = {
|
|
594
|
+
id: 1,
|
|
595
|
+
create() {
|
|
596
|
+
return this.id++
|
|
597
|
+
},
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
const callbacks = Object.create(null)
|
|
601
|
+
|
|
602
|
+
const Callback = {
|
|
603
|
+
registerPromise() {
|
|
604
|
+
const id = Id.create()
|
|
605
|
+
const promise = new Promise((resolve, reject) => {
|
|
606
|
+
callbacks[id] = { resolve, reject }
|
|
607
|
+
})
|
|
608
|
+
return { id, promise }
|
|
609
|
+
},
|
|
610
|
+
resolve(id, message) {
|
|
611
|
+
callbacks[id].resolve(message)
|
|
612
|
+
delete callbacks[id]
|
|
613
|
+
},
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
const JsonRpcVersion = {
|
|
617
|
+
Two: '2.0',
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
const ErrorType = {
|
|
621
|
+
DomException: 'DOMException',
|
|
622
|
+
ReferenceError: 'ReferenceError',
|
|
623
|
+
SyntaxError: 'SyntaxError',
|
|
624
|
+
TypeError: 'TypeError',
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
const GetErrorConstructor = {
|
|
628
|
+
getErrorConstructor(message, type) {
|
|
629
|
+
if (type) {
|
|
630
|
+
switch (type) {
|
|
631
|
+
case ErrorType.DomException:
|
|
632
|
+
return DOMException
|
|
633
|
+
case ErrorType.TypeError:
|
|
634
|
+
return TypeError
|
|
635
|
+
case ErrorType.SyntaxError:
|
|
636
|
+
return SyntaxError
|
|
637
|
+
case ErrorType.ReferenceError:
|
|
638
|
+
return ReferenceError
|
|
639
|
+
default:
|
|
640
|
+
return Error
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
if (message.startsWith('TypeError: ')) {
|
|
644
|
+
return TypeError
|
|
645
|
+
}
|
|
646
|
+
if (message.startsWith('SyntaxError: ')) {
|
|
647
|
+
return SyntaxError
|
|
648
|
+
}
|
|
649
|
+
if (message.startsWith('ReferenceError: ')) {
|
|
650
|
+
return ReferenceError
|
|
651
|
+
}
|
|
652
|
+
return Error
|
|
653
|
+
},
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
const constructError = (message, type, name) => {
|
|
657
|
+
const ErrorConstructor = GetErrorConstructor.getErrorConstructor(message, type)
|
|
658
|
+
if (ErrorConstructor === DOMException && name) {
|
|
659
|
+
return new ErrorConstructor(message, name)
|
|
660
|
+
}
|
|
661
|
+
if (ErrorConstructor === Error) {
|
|
662
|
+
const error = new Error(message)
|
|
663
|
+
if (name && name !== 'VError') {
|
|
664
|
+
error.name = name
|
|
665
|
+
}
|
|
666
|
+
return error
|
|
667
|
+
}
|
|
668
|
+
return new ErrorConstructor(message)
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
const JsonRpcErrorCode = {
|
|
672
|
+
MethodNotFound: -32601,
|
|
673
|
+
Custom: -32001,
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
class JsonRpcError extends Error {
|
|
677
|
+
constructor(message) {
|
|
678
|
+
super(message)
|
|
679
|
+
this.name = 'JsonRpcError'
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
const RestoreJsonRpcError = {
|
|
684
|
+
restoreJsonRpcError(error) {
|
|
685
|
+
if (error && error instanceof Error) {
|
|
686
|
+
return error
|
|
687
|
+
}
|
|
688
|
+
if (error && error.code && error.code === JsonRpcErrorCode.MethodNotFound) {
|
|
689
|
+
const restoredError = new JsonRpcError(error.message)
|
|
690
|
+
restoredError.stack = error.stack
|
|
691
|
+
return restoredError
|
|
692
|
+
}
|
|
693
|
+
if (error && error.message) {
|
|
694
|
+
const restoredError = constructError(error.message, error.type, error.name)
|
|
695
|
+
if (error.data) {
|
|
696
|
+
if (error.data.stack) {
|
|
697
|
+
restoredError.stack = error.message + '\n' + error.data.stack
|
|
698
|
+
|
|
699
|
+
if (error.data.codeFrame) {
|
|
700
|
+
// @ts-ignore
|
|
701
|
+
restoredError.codeFrame = error.data.codeFrame
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
} else if (error.stack) {
|
|
705
|
+
// TODO accessing stack might be slow
|
|
706
|
+
const lowerStack = restoredError.stack
|
|
707
|
+
// @ts-ignore
|
|
708
|
+
const indexNewLine = lowerStack.indexOf('\n')
|
|
709
|
+
// @ts-ignore
|
|
710
|
+
restoredError.stack = error.stack + lowerStack.slice(indexNewLine)
|
|
711
|
+
}
|
|
712
|
+
return restoredError
|
|
713
|
+
}
|
|
714
|
+
if (typeof error === 'string') {
|
|
715
|
+
return new Error(`JsonRpc Error: ${error}`)
|
|
716
|
+
}
|
|
717
|
+
return new Error(`JsonRpc Error: ${error}`)
|
|
718
|
+
},
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
const JsonRpc = {
|
|
722
|
+
async invoke(ipc, method, ...params) {
|
|
723
|
+
const { id, promise } = Callback.registerPromise()
|
|
724
|
+
ipc.send({
|
|
725
|
+
jsonrpc: JsonRpcVersion.Two,
|
|
726
|
+
method,
|
|
727
|
+
params,
|
|
728
|
+
id,
|
|
729
|
+
})
|
|
730
|
+
const responseMessage = await promise
|
|
731
|
+
if ('error' in responseMessage) {
|
|
732
|
+
const restoredError = RestoreJsonRpcError.restoreJsonRpcError(responseMessage.error)
|
|
733
|
+
throw restoredError
|
|
734
|
+
}
|
|
735
|
+
if ('result' in responseMessage) {
|
|
736
|
+
return responseMessage.result
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
throw new Error('unexpected response message')
|
|
740
|
+
},
|
|
741
|
+
async invokeAndTransfer(ipc, method, ...params) {
|
|
742
|
+
const { id, promise } = Callback.registerPromise()
|
|
743
|
+
ipc.sendAndTransfer({
|
|
744
|
+
jsonrpc: JsonRpcVersion.Two,
|
|
745
|
+
method,
|
|
746
|
+
params,
|
|
747
|
+
id,
|
|
748
|
+
})
|
|
749
|
+
const responseMessage = await promise
|
|
750
|
+
if ('error' in responseMessage) {
|
|
751
|
+
const restoredError = RestoreJsonRpcError.restoreJsonRpcError(responseMessage.error)
|
|
752
|
+
throw restoredError
|
|
753
|
+
}
|
|
754
|
+
if ('result' in responseMessage) {
|
|
755
|
+
return responseMessage.result
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
throw new Error('unexpected response message')
|
|
759
|
+
},
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
const SharedProcess = {
|
|
763
|
+
/**
|
|
764
|
+
* @type {any}
|
|
765
|
+
*/
|
|
766
|
+
ipc: undefined,
|
|
767
|
+
async invoke(method, ...params) {
|
|
768
|
+
return JsonRpc.invoke(this.ipc, method, ...params)
|
|
769
|
+
},
|
|
770
|
+
async invokeAndTransfer(method, ...params) {
|
|
771
|
+
return JsonRpc.invokeAndTransfer(this.ipc, method, ...params)
|
|
772
|
+
},
|
|
773
|
+
async listen() {
|
|
774
|
+
this.ipc = await IpcChild.listen({ module: IpcChildWithSharedProcess })
|
|
775
|
+
},
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
const ProcessExplorer = {
|
|
779
|
+
/**
|
|
780
|
+
* @type {any}
|
|
781
|
+
*/
|
|
782
|
+
ipc: undefined,
|
|
783
|
+
async invoke(method, ...params) {
|
|
784
|
+
return JsonRpc.invoke(this.ipc, method, ...params)
|
|
785
|
+
},
|
|
786
|
+
async listen() {
|
|
787
|
+
this.ipc = await IpcChild.listen({ module: IpcChildWithProcessExplorer })
|
|
788
|
+
},
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
const listProcessesWithMemoryUsage = (rootPid) => {
|
|
792
|
+
return ProcessExplorer.invoke('ListProcessesWithMemoryUsage.listProcessesWithMemoryUsage', rootPid)
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
const handleMessageFromWindow = (event) => {
|
|
796
|
+
const { data } = event
|
|
797
|
+
if ('method' in data) {
|
|
798
|
+
return
|
|
799
|
+
}
|
|
800
|
+
Callback.resolve(data.id, data)
|
|
801
|
+
window.removeEventListener('message', handleMessageFromWindow)
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
const unwrapJsonRpcResult = (responseMessage) => {
|
|
805
|
+
if ('error' in responseMessage) {
|
|
806
|
+
const restoredError = RestoreJsonRpcError.restoreJsonRpcError(responseMessage.error)
|
|
807
|
+
throw restoredError
|
|
808
|
+
}
|
|
809
|
+
if ('result' in responseMessage) {
|
|
810
|
+
return responseMessage.result
|
|
811
|
+
}
|
|
812
|
+
return undefined
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
const IpcId = {
|
|
816
|
+
ProcessExplorerRenderer: 33,
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
const getPort = async (type, name) => {
|
|
820
|
+
// @ts-ignore
|
|
821
|
+
window.addEventListener('message', handleMessageFromWindow)
|
|
822
|
+
const { id, promise } = Callback.registerPromise()
|
|
823
|
+
const { port1, port2 } = new MessageChannel()
|
|
824
|
+
const message = {
|
|
825
|
+
jsonrpc: JsonRpcVersion.Two,
|
|
826
|
+
id,
|
|
827
|
+
method: 'CreateMessagePort.createMessagePort',
|
|
828
|
+
params: [IpcId.ProcessExplorerRenderer],
|
|
829
|
+
}
|
|
830
|
+
// @ts-ignore
|
|
831
|
+
if (!globalThis.isElectron) {
|
|
832
|
+
throw new Error('Electron api was requested but is not available')
|
|
833
|
+
}
|
|
834
|
+
window.postMessage(message, '*', [port1])
|
|
835
|
+
const responseMessage = await promise
|
|
836
|
+
unwrapJsonRpcResult(responseMessage)
|
|
837
|
+
return port2
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
const getTransfer = (params) => {
|
|
841
|
+
return params.filter((value) => value instanceof MessagePort)
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
const fixElectronParams = (message) => {
|
|
845
|
+
const { params } = message
|
|
846
|
+
const newParams = []
|
|
847
|
+
const transfer = getTransfer(params)
|
|
848
|
+
for (const param of params) {
|
|
849
|
+
if (!transfer.includes(param)) {
|
|
850
|
+
newParams.push(param)
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
return {
|
|
854
|
+
newValue: {
|
|
855
|
+
...message,
|
|
856
|
+
params: newParams,
|
|
857
|
+
},
|
|
858
|
+
transfer,
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
const IpcChildWithSharedProcess = {
|
|
863
|
+
async create() {
|
|
864
|
+
const port = await getPort('shared-process', 'Shared Process')
|
|
865
|
+
return port
|
|
866
|
+
},
|
|
867
|
+
wrap(port) {
|
|
868
|
+
return {
|
|
869
|
+
port,
|
|
870
|
+
/**
|
|
871
|
+
* @type {any}
|
|
872
|
+
*/
|
|
873
|
+
wrappedListener: null,
|
|
874
|
+
send(message) {
|
|
875
|
+
this.port.postMessage(message)
|
|
876
|
+
},
|
|
877
|
+
sendAndTransfer(message) {
|
|
878
|
+
const { newValue, transfer } = fixElectronParams(message)
|
|
879
|
+
this.port.postMessage(newValue, transfer)
|
|
880
|
+
},
|
|
881
|
+
set onmessage(listener) {
|
|
882
|
+
this.wrappedListener = (event) => {
|
|
883
|
+
listener(event.data)
|
|
884
|
+
}
|
|
885
|
+
this.port.onmessage = this.wrappedListener
|
|
886
|
+
},
|
|
887
|
+
get onmessage() {
|
|
888
|
+
return this.wrappedListener
|
|
889
|
+
},
|
|
890
|
+
}
|
|
891
|
+
},
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
const IpcChildWithProcessExplorer = {
|
|
895
|
+
async create() {
|
|
896
|
+
const { port1, port2 } = new MessageChannel()
|
|
897
|
+
await SharedProcess.invokeAndTransfer('HandleMessagePortForProcessExplorer.handleMessagePortForProcessExplorer', port1)
|
|
898
|
+
return port2
|
|
899
|
+
},
|
|
900
|
+
wrap(port) {
|
|
901
|
+
return {
|
|
902
|
+
port,
|
|
903
|
+
/**
|
|
904
|
+
* @type {any}
|
|
905
|
+
*/
|
|
906
|
+
wrappedListener: null,
|
|
907
|
+
send(message) {
|
|
908
|
+
this.port.postMessage(message)
|
|
909
|
+
},
|
|
910
|
+
set onmessage(listener) {
|
|
911
|
+
this.wrappedListener = (event) => {
|
|
912
|
+
listener(event.data)
|
|
913
|
+
}
|
|
914
|
+
this.port.onmessage = this.wrappedListener
|
|
915
|
+
},
|
|
916
|
+
get onmessage() {
|
|
917
|
+
return this.wrappedListener
|
|
918
|
+
},
|
|
919
|
+
}
|
|
920
|
+
},
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
const IpcChild = {
|
|
924
|
+
async listen({ module }) {
|
|
925
|
+
const rawIpc = await module.create()
|
|
926
|
+
const ipc = module.wrap(rawIpc)
|
|
927
|
+
HandleIpc.handleIpc(ipc)
|
|
928
|
+
return ipc
|
|
929
|
+
},
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
const handleError = (event) => {
|
|
933
|
+
console.error(event)
|
|
934
|
+
document.body.textContent = `${event}`
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
const handleUnhandledRejection = (event) => {
|
|
938
|
+
console.error(event.reason)
|
|
939
|
+
document.body.textContent = `${event.reason}`
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
const isResultMessage = (message) => {
|
|
943
|
+
return 'result' in message
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
const isErrorMessage = (message) => {
|
|
947
|
+
return 'error' in message
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
const Signal = {
|
|
951
|
+
SIGTERM: 'SIGTERM',
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
const Process = {
|
|
955
|
+
kill(pid) {
|
|
956
|
+
return ProcessExplorer.invoke('Process.kill', pid, Signal.SIGTERM)
|
|
957
|
+
},
|
|
958
|
+
debug(pid) {
|
|
959
|
+
// TODO
|
|
960
|
+
console.log({ pid })
|
|
961
|
+
},
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
const getContextMenuFn = (label) => {
|
|
965
|
+
switch (label) {
|
|
966
|
+
case 'Kill Process':
|
|
967
|
+
return Process.kill
|
|
968
|
+
case 'Debug Process':
|
|
969
|
+
return Process.debug
|
|
970
|
+
default:
|
|
971
|
+
throw new Error(`context menu function not found ${label}`)
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
const ElectronContextMenu = {
|
|
976
|
+
handleSelect(label, customData) {
|
|
977
|
+
const { pid } = customData
|
|
978
|
+
const fn = getContextMenuFn(label)
|
|
979
|
+
return fn(pid)
|
|
980
|
+
},
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
const CommandMap = {
|
|
984
|
+
commandMap: {
|
|
985
|
+
'ElectronContextMenu.handleSelect': ElectronContextMenu.handleSelect,
|
|
986
|
+
},
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
const Command = {
|
|
990
|
+
execute(method, ...params) {
|
|
991
|
+
const fn = CommandMap.commandMap[method]
|
|
992
|
+
if (!fn) {
|
|
993
|
+
return
|
|
994
|
+
}
|
|
995
|
+
return fn(...params)
|
|
996
|
+
},
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
const handleMessage = (message) => {
|
|
1000
|
+
if (message.id && (isResultMessage(message) || isErrorMessage(message))) {
|
|
1001
|
+
Callback.resolve(message.id, message)
|
|
1002
|
+
return
|
|
1003
|
+
}
|
|
1004
|
+
if (message.method) {
|
|
1005
|
+
return Command.execute(message.method, ...message.params)
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
const getPid = () => {
|
|
1010
|
+
return ProcessExplorer.invoke('ProcessId.getMainProcessId')
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
const sleep = (timeout) => {
|
|
1014
|
+
return new Promise((resolve) => {
|
|
1015
|
+
setTimeout(resolve, timeout)
|
|
1016
|
+
})
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
const HandleIpc = {
|
|
1020
|
+
handleIpc(ipc) {
|
|
1021
|
+
ipc.onmessage = handleMessage
|
|
1022
|
+
},
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
const main = async () => {
|
|
1026
|
+
onerror = handleError
|
|
1027
|
+
onunhandledrejection = handleUnhandledRejection
|
|
1028
|
+
await SharedProcess.listen()
|
|
1029
|
+
await ProcessExplorer.listen()
|
|
1030
|
+
const pid = await getPid()
|
|
1031
|
+
const refreshInterval = 1000
|
|
1032
|
+
while (true) {
|
|
1033
|
+
const processesWithMemoryUsage = await listProcessesWithMemoryUsage(pid)
|
|
1034
|
+
renderProcesses(processesWithMemoryUsage)
|
|
1035
|
+
await sleep(refreshInterval)
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
main()
|