@ecmaos/coreutils 0.3.1 → 0.4.2
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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +48 -0
- package/dist/commands/awk.d.ts +4 -0
- package/dist/commands/awk.d.ts.map +1 -0
- package/dist/commands/awk.js +324 -0
- package/dist/commands/awk.js.map +1 -0
- package/dist/commands/chgrp.d.ts +4 -0
- package/dist/commands/chgrp.d.ts.map +1 -0
- package/dist/commands/chgrp.js +187 -0
- package/dist/commands/chgrp.js.map +1 -0
- package/dist/commands/chmod.d.ts.map +1 -1
- package/dist/commands/chmod.js +139 -2
- package/dist/commands/chmod.js.map +1 -1
- package/dist/commands/chown.d.ts +4 -0
- package/dist/commands/chown.d.ts.map +1 -0
- package/dist/commands/chown.js +257 -0
- package/dist/commands/chown.js.map +1 -0
- package/dist/commands/cksum.d.ts +4 -0
- package/dist/commands/cksum.d.ts.map +1 -0
- package/dist/commands/cksum.js +124 -0
- package/dist/commands/cksum.js.map +1 -0
- package/dist/commands/cmp.d.ts +4 -0
- package/dist/commands/cmp.d.ts.map +1 -0
- package/dist/commands/cmp.js +120 -0
- package/dist/commands/cmp.js.map +1 -0
- package/dist/commands/column.d.ts +4 -0
- package/dist/commands/column.d.ts.map +1 -0
- package/dist/commands/column.js +274 -0
- package/dist/commands/column.js.map +1 -0
- package/dist/commands/cp.d.ts.map +1 -1
- package/dist/commands/cp.js +81 -4
- package/dist/commands/cp.js.map +1 -1
- package/dist/commands/cron.d.ts.map +1 -1
- package/dist/commands/cron.js +116 -23
- package/dist/commands/cron.js.map +1 -1
- package/dist/commands/curl.d.ts +4 -0
- package/dist/commands/curl.d.ts.map +1 -0
- package/dist/commands/curl.js +238 -0
- package/dist/commands/curl.js.map +1 -0
- package/dist/commands/du.d.ts +4 -0
- package/dist/commands/du.d.ts.map +1 -0
- package/dist/commands/du.js +168 -0
- package/dist/commands/du.js.map +1 -0
- package/dist/commands/echo.d.ts.map +1 -1
- package/dist/commands/echo.js +125 -2
- package/dist/commands/echo.js.map +1 -1
- package/dist/commands/env.d.ts +4 -0
- package/dist/commands/env.d.ts.map +1 -0
- package/dist/commands/env.js +129 -0
- package/dist/commands/env.js.map +1 -0
- package/dist/commands/expand.d.ts +4 -0
- package/dist/commands/expand.d.ts.map +1 -0
- package/dist/commands/expand.js +197 -0
- package/dist/commands/expand.js.map +1 -0
- package/dist/commands/factor.d.ts +4 -0
- package/dist/commands/factor.d.ts.map +1 -0
- package/dist/commands/factor.js +141 -0
- package/dist/commands/factor.js.map +1 -0
- package/dist/commands/fmt.d.ts +4 -0
- package/dist/commands/fmt.d.ts.map +1 -0
- package/dist/commands/fmt.js +278 -0
- package/dist/commands/fmt.js.map +1 -0
- package/dist/commands/fold.d.ts +4 -0
- package/dist/commands/fold.d.ts.map +1 -0
- package/dist/commands/fold.js +253 -0
- package/dist/commands/fold.js.map +1 -0
- package/dist/commands/groups.d.ts +4 -0
- package/dist/commands/groups.d.ts.map +1 -0
- package/dist/commands/groups.js +61 -0
- package/dist/commands/groups.js.map +1 -0
- package/dist/commands/head.d.ts.map +1 -1
- package/dist/commands/head.js +184 -77
- package/dist/commands/head.js.map +1 -1
- package/dist/commands/hostname.d.ts +4 -0
- package/dist/commands/hostname.d.ts.map +1 -0
- package/dist/commands/hostname.js +80 -0
- package/dist/commands/hostname.js.map +1 -0
- package/dist/commands/less.d.ts.map +1 -1
- package/dist/commands/less.js +1 -0
- package/dist/commands/less.js.map +1 -1
- package/dist/commands/man.d.ts.map +1 -1
- package/dist/commands/man.js +3 -1
- package/dist/commands/man.js.map +1 -1
- package/dist/commands/mount.d.ts +4 -0
- package/dist/commands/mount.d.ts.map +1 -0
- package/dist/commands/mount.js +1136 -0
- package/dist/commands/mount.js.map +1 -0
- package/dist/commands/od.d.ts +4 -0
- package/dist/commands/od.d.ts.map +1 -0
- package/dist/commands/od.js +342 -0
- package/dist/commands/od.js.map +1 -0
- package/dist/commands/pr.d.ts +4 -0
- package/dist/commands/pr.d.ts.map +1 -0
- package/dist/commands/pr.js +298 -0
- package/dist/commands/pr.js.map +1 -0
- package/dist/commands/printf.d.ts +4 -0
- package/dist/commands/printf.d.ts.map +1 -0
- package/dist/commands/printf.js +271 -0
- package/dist/commands/printf.js.map +1 -0
- package/dist/commands/readlink.d.ts +4 -0
- package/dist/commands/readlink.d.ts.map +1 -0
- package/dist/commands/readlink.js +104 -0
- package/dist/commands/readlink.js.map +1 -0
- package/dist/commands/realpath.d.ts +4 -0
- package/dist/commands/realpath.d.ts.map +1 -0
- package/dist/commands/realpath.js +111 -0
- package/dist/commands/realpath.js.map +1 -0
- package/dist/commands/rev.d.ts +4 -0
- package/dist/commands/rev.d.ts.map +1 -0
- package/dist/commands/rev.js +134 -0
- package/dist/commands/rev.js.map +1 -0
- package/dist/commands/shuf.d.ts +4 -0
- package/dist/commands/shuf.d.ts.map +1 -0
- package/dist/commands/shuf.js +221 -0
- package/dist/commands/shuf.js.map +1 -0
- package/dist/commands/sleep.d.ts +4 -0
- package/dist/commands/sleep.d.ts.map +1 -0
- package/dist/commands/sleep.js +102 -0
- package/dist/commands/sleep.js.map +1 -0
- package/dist/commands/strings.d.ts +4 -0
- package/dist/commands/strings.d.ts.map +1 -0
- package/dist/commands/strings.js +170 -0
- package/dist/commands/strings.js.map +1 -0
- package/dist/commands/tac.d.ts +4 -0
- package/dist/commands/tac.d.ts.map +1 -0
- package/dist/commands/tac.js +130 -0
- package/dist/commands/tac.js.map +1 -0
- package/dist/commands/time.d.ts +4 -0
- package/dist/commands/time.d.ts.map +1 -0
- package/dist/commands/time.js +126 -0
- package/dist/commands/time.js.map +1 -0
- package/dist/commands/umount.d.ts +4 -0
- package/dist/commands/umount.d.ts.map +1 -0
- package/dist/commands/umount.js +103 -0
- package/dist/commands/umount.js.map +1 -0
- package/dist/commands/uname.d.ts +4 -0
- package/dist/commands/uname.d.ts.map +1 -0
- package/dist/commands/uname.js +149 -0
- package/dist/commands/uname.js.map +1 -0
- package/dist/commands/unexpand.d.ts +4 -0
- package/dist/commands/unexpand.d.ts.map +1 -0
- package/dist/commands/unexpand.js +286 -0
- package/dist/commands/unexpand.js.map +1 -0
- package/dist/commands/uptime.d.ts +4 -0
- package/dist/commands/uptime.d.ts.map +1 -0
- package/dist/commands/uptime.js +62 -0
- package/dist/commands/uptime.js.map +1 -0
- package/dist/commands/view.d.ts +1 -0
- package/dist/commands/view.d.ts.map +1 -1
- package/dist/commands/view.js +408 -66
- package/dist/commands/view.js.map +1 -1
- package/dist/commands/yes.d.ts +4 -0
- package/dist/commands/yes.d.ts.map +1 -0
- package/dist/commands/yes.js +58 -0
- package/dist/commands/yes.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +82 -0
- package/dist/index.js.map +1 -1
- package/package.json +12 -3
- package/src/commands/awk.ts +340 -0
- package/src/commands/chmod.ts +141 -2
- package/src/commands/chown.ts +321 -0
- package/src/commands/cksum.ts +133 -0
- package/src/commands/cmp.ts +126 -0
- package/src/commands/column.ts +273 -0
- package/src/commands/cp.ts +93 -4
- package/src/commands/cron.ts +115 -23
- package/src/commands/curl.ts +231 -0
- package/src/commands/echo.ts +122 -2
- package/src/commands/env.ts +143 -0
- package/src/commands/expand.ts +207 -0
- package/src/commands/factor.ts +151 -0
- package/src/commands/fmt.ts +293 -0
- package/src/commands/fold.ts +257 -0
- package/src/commands/groups.ts +72 -0
- package/src/commands/head.ts +176 -77
- package/src/commands/hostname.ts +81 -0
- package/src/commands/less.ts +1 -0
- package/src/commands/man.ts +4 -1
- package/src/commands/mount.ts +1302 -0
- package/src/commands/od.ts +327 -0
- package/src/commands/pr.ts +291 -0
- package/src/commands/printf.ts +271 -0
- package/src/commands/readlink.ts +102 -0
- package/src/commands/realpath.ts +126 -0
- package/src/commands/rev.ts +143 -0
- package/src/commands/shuf.ts +218 -0
- package/src/commands/sleep.ts +109 -0
- package/src/commands/strings.ts +176 -0
- package/src/commands/tac.ts +138 -0
- package/src/commands/time.ts +144 -0
- package/src/commands/umount.ts +116 -0
- package/src/commands/uname.ts +130 -0
- package/src/commands/unexpand.ts +305 -0
- package/src/commands/uptime.ts +73 -0
- package/src/commands/view.ts +463 -73
- package/src/index.ts +82 -0
- package/tsconfig.json +4 -0
package/dist/commands/view.js
CHANGED
|
@@ -1,36 +1,40 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
|
+
import { marked } from 'marked';
|
|
4
|
+
import '@alenaksu/json-viewer';
|
|
3
5
|
import { TerminalCommand } from '../shared/terminal-command.js';
|
|
4
6
|
import { writelnStderr, writelnStdout } from '../shared/helpers.js';
|
|
5
7
|
function detectFileType(filePath) {
|
|
6
8
|
const ext = path.extname(filePath).toLowerCase();
|
|
7
9
|
// PDF
|
|
8
|
-
if (ext === '.pdf')
|
|
10
|
+
if (ext === '.pdf')
|
|
9
11
|
return 'pdf';
|
|
10
|
-
|
|
12
|
+
// Markdown
|
|
13
|
+
const markdownExts = ['.md', '.markdown', '.mdown', '.mkd', '.mkdn'];
|
|
14
|
+
if (markdownExts.includes(ext))
|
|
15
|
+
return 'markdown';
|
|
16
|
+
// JSON
|
|
17
|
+
const jsonExts = ['.json', '.jsonl', '.jsonc', '.jsonld'];
|
|
18
|
+
if (jsonExts.includes(ext))
|
|
19
|
+
return 'json';
|
|
11
20
|
// Images
|
|
12
21
|
const imageExts = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp', '.svg', '.ico', '.tiff', '.tif'];
|
|
13
|
-
if (imageExts.includes(ext))
|
|
22
|
+
if (imageExts.includes(ext))
|
|
14
23
|
return 'image';
|
|
15
|
-
}
|
|
16
24
|
// Audio
|
|
17
25
|
const audioExts = ['.mp3', '.wav', '.ogg', '.oga', '.opus', '.m4a', '.aac', '.flac', '.webm', '.wma', '.aiff', '.aif', '.3gp', '.amr'];
|
|
18
|
-
if (audioExts.includes(ext))
|
|
26
|
+
if (audioExts.includes(ext))
|
|
19
27
|
return 'audio';
|
|
20
|
-
}
|
|
21
28
|
// Video
|
|
22
29
|
const videoExts = ['.mp4', '.webm', '.ogg', '.ogv', '.mov', '.avi', '.mkv', '.m4v', '.flv', '.wmv', '.3gp'];
|
|
23
|
-
if (videoExts.includes(ext))
|
|
30
|
+
if (videoExts.includes(ext))
|
|
24
31
|
return 'video';
|
|
25
|
-
|
|
26
|
-
// Default to image for unknown types (might be an image without extension)
|
|
27
|
-
return 'image';
|
|
32
|
+
return 'application/octet-stream';
|
|
28
33
|
}
|
|
29
34
|
function getMimeType(filePath, fileType) {
|
|
30
35
|
const ext = path.extname(filePath).toLowerCase();
|
|
31
|
-
if (fileType === 'pdf')
|
|
36
|
+
if (fileType === 'pdf')
|
|
32
37
|
return 'application/pdf';
|
|
33
|
-
}
|
|
34
38
|
if (fileType === 'image') {
|
|
35
39
|
const mimeTypes = {
|
|
36
40
|
'.jpg': 'image/jpeg',
|
|
@@ -81,11 +85,13 @@ function getMimeType(filePath, fileType) {
|
|
|
81
85
|
};
|
|
82
86
|
return mimeTypes[ext] || 'video/mp4';
|
|
83
87
|
}
|
|
88
|
+
if (fileType === 'json')
|
|
89
|
+
return 'application/json';
|
|
84
90
|
return 'application/octet-stream';
|
|
85
91
|
}
|
|
86
92
|
function printUsage(process, terminal) {
|
|
87
93
|
const usage = `Usage: view [OPTIONS] [FILE...]
|
|
88
|
-
View files in a new window. Supports PDF, images, audio, and video files.
|
|
94
|
+
View files in a new window. Supports PDF, markdown, JSON, images, audio, and video files.
|
|
89
95
|
|
|
90
96
|
--help display this help and exit
|
|
91
97
|
|
|
@@ -102,13 +108,15 @@ Audio/Video Options (for audio and video files):
|
|
|
102
108
|
|
|
103
109
|
Examples:
|
|
104
110
|
view document.pdf view a PDF file
|
|
111
|
+
view README.md view a markdown file
|
|
112
|
+
view data.json view a JSON file
|
|
105
113
|
view image.png view an image
|
|
106
114
|
view song.mp3 view/play an audio file
|
|
107
115
|
view movie.mp4 view/play a video file
|
|
108
|
-
view --loop music.mp3
|
|
109
|
-
view --no-autoplay video.mp4
|
|
110
|
-
view --volume 50 track.mp3
|
|
111
|
-
view --fullscreen movie.mp4
|
|
116
|
+
view --loop music.mp3 play audio in a loop
|
|
117
|
+
view --no-autoplay video.mp4 load video without auto-playing
|
|
118
|
+
view --volume 50 track.mp3 play at 50% volume
|
|
119
|
+
view --fullscreen movie.mp4 play video in fullscreen mode`;
|
|
112
120
|
writelnStderr(process, terminal, usage);
|
|
113
121
|
}
|
|
114
122
|
async function loadAudioMetadata(audioElement) {
|
|
@@ -158,6 +166,10 @@ function formatDuration(seconds) {
|
|
|
158
166
|
}
|
|
159
167
|
return `${minutes}:${secs.toString().padStart(2, '0')}`;
|
|
160
168
|
}
|
|
169
|
+
function generateRandomClass(prefix) {
|
|
170
|
+
const randomSuffix = Math.random().toString(36).substring(2, 8);
|
|
171
|
+
return `${prefix}-${randomSuffix}`;
|
|
172
|
+
}
|
|
161
173
|
export function createCommand(kernel, shell, terminal) {
|
|
162
174
|
return new TerminalCommand({
|
|
163
175
|
command: 'view',
|
|
@@ -272,7 +284,278 @@ export function createCommand(kernel, shell, terminal) {
|
|
|
272
284
|
const windowTitle = files.length > 1
|
|
273
285
|
? `${path.basename(file)} (${files.indexOf(file) + 1}/${files.length})`
|
|
274
286
|
: path.basename(file);
|
|
275
|
-
if (fileType === '
|
|
287
|
+
if (fileType === 'markdown') {
|
|
288
|
+
// Read and parse markdown file
|
|
289
|
+
const markdownText = new TextDecoder().decode(fileData);
|
|
290
|
+
const htmlContent = await marked.parse(markdownText);
|
|
291
|
+
const containerClass = generateRandomClass('markdown-container');
|
|
292
|
+
const container = document.createElement('div');
|
|
293
|
+
container.className = containerClass;
|
|
294
|
+
container.style.width = '100%';
|
|
295
|
+
container.style.height = '100%';
|
|
296
|
+
container.style.display = 'flex';
|
|
297
|
+
container.style.flexDirection = 'column';
|
|
298
|
+
container.style.background = '#1e1e1e';
|
|
299
|
+
container.style.overflow = 'auto';
|
|
300
|
+
container.style.padding = '40px';
|
|
301
|
+
container.style.boxSizing = 'border-box';
|
|
302
|
+
container.style.fontFamily = "-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif";
|
|
303
|
+
container.style.color = '#e0e0e0';
|
|
304
|
+
container.style.lineHeight = '1.6';
|
|
305
|
+
const contentWrapper = document.createElement('div');
|
|
306
|
+
contentWrapper.style.maxWidth = '800px';
|
|
307
|
+
contentWrapper.style.margin = '0 auto';
|
|
308
|
+
contentWrapper.style.width = '100%';
|
|
309
|
+
contentWrapper.innerHTML = htmlContent;
|
|
310
|
+
const style = document.createElement('style');
|
|
311
|
+
style.textContent = `
|
|
312
|
+
.${containerClass} h1, .${containerClass} h2, .${containerClass} h3, .${containerClass} h4, .${containerClass} h5, .${containerClass} h6 { color: #fff; margin-top: 1.5em; margin-bottom: 0.5em; }
|
|
313
|
+
.${containerClass} h1 { font-size: 2em; border-bottom: 1px solid #444; padding-bottom: 0.3em; }
|
|
314
|
+
.${containerClass} h2 { font-size: 1.5em; border-bottom: 1px solid #444; padding-bottom: 0.3em; }
|
|
315
|
+
.${containerClass} h3 { font-size: 1.25em; }
|
|
316
|
+
.${containerClass} code { background-color: #2d2d2d; padding: 2px 6px; border-radius: 3px; font-family: 'Courier New', monospace; color: #f8f8f2; }
|
|
317
|
+
.${containerClass} pre { background-color: #2d2d2d; padding: 16px; border-radius: 6px; overflow-x: auto; }
|
|
318
|
+
.${containerClass} pre code { background-color: transparent; padding: 0; }
|
|
319
|
+
.${containerClass} a { color: #4a9eff; text-decoration: none; }
|
|
320
|
+
.${containerClass} a:hover { text-decoration: underline; }
|
|
321
|
+
.${containerClass} blockquote { border-left: 4px solid #4a9eff; padding-left: 16px; margin-left: 0; color: #b0b0b0; }
|
|
322
|
+
.${containerClass} table { border-collapse: collapse; width: 100%; margin: 1em 0; }
|
|
323
|
+
.${containerClass} th, .${containerClass} td { border: 1px solid #444; padding: 8px 12px; text-align: left; }
|
|
324
|
+
.${containerClass} th { background-color: #2d2d2d; font-weight: bold; }
|
|
325
|
+
.${containerClass} tr:nth-child(even) { background-color: #252525; }
|
|
326
|
+
.${containerClass} img { max-width: 100%; height: auto; }
|
|
327
|
+
.${containerClass} ul, .${containerClass} ol { padding-left: 2em; }
|
|
328
|
+
.${containerClass} hr { border: none; border-top: 1px solid #444; margin: 2em 0; }
|
|
329
|
+
`;
|
|
330
|
+
container.appendChild(style);
|
|
331
|
+
container.appendChild(contentWrapper);
|
|
332
|
+
const win = kernel.windows.create({
|
|
333
|
+
title: windowTitle,
|
|
334
|
+
width: 900,
|
|
335
|
+
height: 700,
|
|
336
|
+
max: false
|
|
337
|
+
});
|
|
338
|
+
win.mount(container);
|
|
339
|
+
await writelnStdout(process, terminal, chalk.green(`Viewing: ${file}`));
|
|
340
|
+
}
|
|
341
|
+
else if (fileType === 'json') {
|
|
342
|
+
// Read and parse JSON file
|
|
343
|
+
const jsonText = new TextDecoder().decode(fileData);
|
|
344
|
+
let jsonData;
|
|
345
|
+
try {
|
|
346
|
+
jsonData = JSON.parse(jsonText);
|
|
347
|
+
}
|
|
348
|
+
catch (error) {
|
|
349
|
+
await writelnStderr(process, terminal, chalk.red(`view: invalid JSON in ${file}: ${error instanceof Error ? error.message : 'Unknown error'}`));
|
|
350
|
+
continue;
|
|
351
|
+
}
|
|
352
|
+
const containerClass = generateRandomClass('json-container');
|
|
353
|
+
const container = document.createElement('div');
|
|
354
|
+
container.className = containerClass;
|
|
355
|
+
container.style.width = '100%';
|
|
356
|
+
container.style.height = '100%';
|
|
357
|
+
container.style.display = 'flex';
|
|
358
|
+
container.style.flexDirection = 'column';
|
|
359
|
+
container.style.background = '#2a2f3a';
|
|
360
|
+
container.style.overflow = 'hidden';
|
|
361
|
+
const buttonBar = document.createElement('div');
|
|
362
|
+
buttonBar.style.cssText = `
|
|
363
|
+
display: flex;
|
|
364
|
+
flex-wrap: wrap;
|
|
365
|
+
gap: 6px;
|
|
366
|
+
padding: 6px;
|
|
367
|
+
background: #2a2f3a;
|
|
368
|
+
border-bottom: 1px solid #3c3c3c;
|
|
369
|
+
align-items: center;
|
|
370
|
+
`;
|
|
371
|
+
const createInput = (placeholder) => {
|
|
372
|
+
const input = document.createElement('input');
|
|
373
|
+
input.type = 'text';
|
|
374
|
+
input.placeholder = placeholder;
|
|
375
|
+
input.style.cssText = `
|
|
376
|
+
background: #263040;
|
|
377
|
+
border: 1px solid #3c3c3c;
|
|
378
|
+
border-radius: 3px;
|
|
379
|
+
color: #fff;
|
|
380
|
+
padding: 0 8px;
|
|
381
|
+
font-size: 11px;
|
|
382
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
383
|
+
width: 120px;
|
|
384
|
+
height: 22px;
|
|
385
|
+
box-sizing: border-box;
|
|
386
|
+
line-height: 22px;
|
|
387
|
+
margin: 0;
|
|
388
|
+
vertical-align: middle;
|
|
389
|
+
`;
|
|
390
|
+
return input;
|
|
391
|
+
};
|
|
392
|
+
const createButton = (text) => {
|
|
393
|
+
const button = document.createElement('button');
|
|
394
|
+
button.textContent = text;
|
|
395
|
+
button.style.cssText = `
|
|
396
|
+
background: #263040;
|
|
397
|
+
border: 1px solid #263040;
|
|
398
|
+
border-radius: 3px;
|
|
399
|
+
color: #fff;
|
|
400
|
+
cursor: pointer;
|
|
401
|
+
font-size: 11px;
|
|
402
|
+
font-weight: 600;
|
|
403
|
+
padding: 0;
|
|
404
|
+
height: 22px;
|
|
405
|
+
box-sizing: border-box;
|
|
406
|
+
line-height: 22px;
|
|
407
|
+
white-space: nowrap;
|
|
408
|
+
display: flex;
|
|
409
|
+
align-items: center;
|
|
410
|
+
justify-content: center;
|
|
411
|
+
padding-left: 8px;
|
|
412
|
+
padding-right: 8px;
|
|
413
|
+
margin: 0;
|
|
414
|
+
vertical-align: middle;
|
|
415
|
+
`;
|
|
416
|
+
button.onmouseenter = () => {
|
|
417
|
+
button.style.background = '#333';
|
|
418
|
+
button.style.borderColor = '#333';
|
|
419
|
+
};
|
|
420
|
+
button.onmouseleave = () => {
|
|
421
|
+
button.style.background = '#263040';
|
|
422
|
+
button.style.borderColor = '#263040';
|
|
423
|
+
};
|
|
424
|
+
button.onmousedown = () => {
|
|
425
|
+
button.style.background = '#263040';
|
|
426
|
+
};
|
|
427
|
+
button.onmouseup = () => {
|
|
428
|
+
button.style.background = '#333';
|
|
429
|
+
};
|
|
430
|
+
return button;
|
|
431
|
+
};
|
|
432
|
+
const createSection = (label) => {
|
|
433
|
+
const section = document.createElement('div');
|
|
434
|
+
section.style.cssText = `
|
|
435
|
+
display: flex;
|
|
436
|
+
align-items: center;
|
|
437
|
+
gap: 4px;
|
|
438
|
+
height: 22px;
|
|
439
|
+
`;
|
|
440
|
+
const labelEl = document.createElement('span');
|
|
441
|
+
labelEl.textContent = label;
|
|
442
|
+
labelEl.style.cssText = `
|
|
443
|
+
color: #f8f8f2;
|
|
444
|
+
font-size: 11px;
|
|
445
|
+
font-weight: 600;
|
|
446
|
+
width: 50px;
|
|
447
|
+
flex-shrink: 0;
|
|
448
|
+
line-height: 22px;
|
|
449
|
+
display: flex;
|
|
450
|
+
align-items: center;
|
|
451
|
+
height: 22px;
|
|
452
|
+
`;
|
|
453
|
+
section.appendChild(labelEl);
|
|
454
|
+
return section;
|
|
455
|
+
};
|
|
456
|
+
const filterSection = createSection('Filter:');
|
|
457
|
+
const filterInput = createInput('Regex or path');
|
|
458
|
+
filterSection.appendChild(filterInput);
|
|
459
|
+
const expandSection = createSection('Expand:');
|
|
460
|
+
const expandInput = createInput('Regex or path');
|
|
461
|
+
const expandButton = createButton('Expand');
|
|
462
|
+
const expandAllButton = createButton('Expand All');
|
|
463
|
+
expandSection.appendChild(expandInput);
|
|
464
|
+
expandSection.appendChild(expandButton);
|
|
465
|
+
expandSection.appendChild(expandAllButton);
|
|
466
|
+
const collapseSection = createSection('Collapse:');
|
|
467
|
+
const collapseInput = createInput('Regex or path');
|
|
468
|
+
const collapseButton = createButton('Collapse');
|
|
469
|
+
const collapseAllButton = createButton('Collapse All');
|
|
470
|
+
collapseSection.appendChild(collapseInput);
|
|
471
|
+
collapseSection.appendChild(collapseButton);
|
|
472
|
+
collapseSection.appendChild(collapseAllButton);
|
|
473
|
+
buttonBar.appendChild(filterSection);
|
|
474
|
+
buttonBar.appendChild(expandSection);
|
|
475
|
+
buttonBar.appendChild(collapseSection);
|
|
476
|
+
const jsonViewer = document.createElement('json-viewer');
|
|
477
|
+
jsonViewer.style.width = '100%';
|
|
478
|
+
jsonViewer.style.flex = '1';
|
|
479
|
+
jsonViewer.style.padding = '0.5rem';
|
|
480
|
+
jsonViewer.style.overflow = 'auto';
|
|
481
|
+
jsonViewer.data = jsonData;
|
|
482
|
+
jsonViewer.style.setProperty('--background-color', '#2a2f3a');
|
|
483
|
+
jsonViewer.style.setProperty('--color', '#f8f8f2');
|
|
484
|
+
jsonViewer.style.setProperty('--font-family', "'Courier New', monospace");
|
|
485
|
+
jsonViewer.style.setProperty('--string-color', '#a3eea0');
|
|
486
|
+
jsonViewer.style.setProperty('--number-color', '#d19a66');
|
|
487
|
+
jsonViewer.style.setProperty('--boolean-color', '#4ba7ef');
|
|
488
|
+
jsonViewer.style.setProperty('--null-color', '#df9cf3');
|
|
489
|
+
jsonViewer.style.setProperty('--property-color', '#6fb3d2');
|
|
490
|
+
jsonViewer.style.setProperty('--preview-color', '#deae8f');
|
|
491
|
+
jsonViewer.style.setProperty('--highlight-color', '#c92a2a');
|
|
492
|
+
filterInput.addEventListener('input', () => {
|
|
493
|
+
const value = filterInput.value.trim();
|
|
494
|
+
if (value) {
|
|
495
|
+
try {
|
|
496
|
+
const regex = new RegExp(value);
|
|
497
|
+
jsonViewer.filter(regex);
|
|
498
|
+
}
|
|
499
|
+
catch {
|
|
500
|
+
jsonViewer.filter(value);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
else {
|
|
504
|
+
jsonViewer.resetFilter();
|
|
505
|
+
}
|
|
506
|
+
});
|
|
507
|
+
expandButton.onclick = () => {
|
|
508
|
+
const value = expandInput.value.trim();
|
|
509
|
+
if (value) {
|
|
510
|
+
try {
|
|
511
|
+
const regex = new RegExp(value);
|
|
512
|
+
jsonViewer.expand(regex);
|
|
513
|
+
}
|
|
514
|
+
catch {
|
|
515
|
+
jsonViewer.expand(value);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
};
|
|
519
|
+
expandAllButton.onclick = () => {
|
|
520
|
+
jsonViewer.expandAll();
|
|
521
|
+
};
|
|
522
|
+
collapseButton.onclick = () => {
|
|
523
|
+
const value = collapseInput.value.trim();
|
|
524
|
+
if (value) {
|
|
525
|
+
try {
|
|
526
|
+
const regex = new RegExp(value);
|
|
527
|
+
jsonViewer.collapse(regex);
|
|
528
|
+
}
|
|
529
|
+
catch {
|
|
530
|
+
jsonViewer.collapse(value);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
};
|
|
534
|
+
collapseAllButton.onclick = () => {
|
|
535
|
+
jsonViewer.collapseAll();
|
|
536
|
+
};
|
|
537
|
+
const handleEnterKey = (input, button) => {
|
|
538
|
+
input.addEventListener('keydown', (e) => {
|
|
539
|
+
if (e.key === 'Enter') {
|
|
540
|
+
button.click();
|
|
541
|
+
}
|
|
542
|
+
});
|
|
543
|
+
};
|
|
544
|
+
handleEnterKey(expandInput, expandButton);
|
|
545
|
+
handleEnterKey(collapseInput, collapseButton);
|
|
546
|
+
container.appendChild(buttonBar);
|
|
547
|
+
container.appendChild(jsonViewer);
|
|
548
|
+
// Create window
|
|
549
|
+
const win = kernel.windows.create({
|
|
550
|
+
title: windowTitle,
|
|
551
|
+
width: 900,
|
|
552
|
+
height: 700,
|
|
553
|
+
max: false
|
|
554
|
+
});
|
|
555
|
+
win.mount(container);
|
|
556
|
+
await writelnStdout(process, terminal, chalk.green(`Viewing: ${file}`));
|
|
557
|
+
}
|
|
558
|
+
else if (fileType === 'pdf') {
|
|
276
559
|
// Convert PDF to base64 and display in object tag
|
|
277
560
|
// Use chunked encoding to avoid argument limit issues with large files
|
|
278
561
|
const uint8Array = new Uint8Array(fileData);
|
|
@@ -284,41 +567,73 @@ export function createCommand(kernel, shell, terminal) {
|
|
|
284
567
|
}
|
|
285
568
|
const base64Data = btoa(binaryString);
|
|
286
569
|
const dataUrl = `data:application/pdf;base64,${base64Data}`;
|
|
287
|
-
const
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
570
|
+
const containerClass = generateRandomClass('pdf-container');
|
|
571
|
+
const container = document.createElement('div');
|
|
572
|
+
container.className = containerClass;
|
|
573
|
+
container.style.width = '100%';
|
|
574
|
+
container.style.height = '100%';
|
|
575
|
+
container.style.display = 'flex';
|
|
576
|
+
container.style.flexDirection = 'column';
|
|
577
|
+
container.style.background = '#1e1e1e';
|
|
578
|
+
container.style.overflow = 'hidden';
|
|
579
|
+
const object = document.createElement('object');
|
|
580
|
+
object.data = dataUrl;
|
|
581
|
+
object.type = 'application/pdf';
|
|
582
|
+
object.style.width = '100%';
|
|
583
|
+
object.style.height = '100%';
|
|
584
|
+
object.style.flex = '1';
|
|
585
|
+
const fallback = document.createElement('p');
|
|
586
|
+
fallback.style.color = '#fff';
|
|
587
|
+
fallback.style.padding = '20px';
|
|
588
|
+
fallback.style.textAlign = 'center';
|
|
589
|
+
fallback.textContent = 'Your browser does not support PDFs. ';
|
|
590
|
+
const downloadLink = document.createElement('a');
|
|
591
|
+
downloadLink.href = dataUrl;
|
|
592
|
+
downloadLink.download = path.basename(file);
|
|
593
|
+
downloadLink.style.color = '#4a9eff';
|
|
594
|
+
downloadLink.textContent = 'Download PDF';
|
|
595
|
+
fallback.appendChild(downloadLink);
|
|
596
|
+
object.appendChild(fallback);
|
|
597
|
+
container.appendChild(object);
|
|
598
|
+
const win = kernel.windows.create({
|
|
298
599
|
title: windowTitle,
|
|
299
|
-
html: pdfHtml,
|
|
300
600
|
width: 800,
|
|
301
601
|
height: 600,
|
|
302
602
|
max: false
|
|
303
603
|
});
|
|
604
|
+
win.mount(container);
|
|
304
605
|
await writelnStdout(process, terminal, chalk.green(`Viewing: ${file}`));
|
|
305
606
|
}
|
|
306
607
|
else if (fileType === 'image') {
|
|
307
608
|
// Display image directly
|
|
308
609
|
const blob = new Blob([new Uint8Array(fileData)], { type: mimeType });
|
|
309
610
|
const url = URL.createObjectURL(blob);
|
|
310
|
-
const
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
611
|
+
const containerClass = generateRandomClass('image-container');
|
|
612
|
+
const container = document.createElement('div');
|
|
613
|
+
container.className = containerClass;
|
|
614
|
+
container.style.width = '100%';
|
|
615
|
+
container.style.height = '100%';
|
|
616
|
+
container.style.display = 'flex';
|
|
617
|
+
container.style.alignItems = 'center';
|
|
618
|
+
container.style.justifyContent = 'center';
|
|
619
|
+
container.style.background = '#1e1e1e';
|
|
620
|
+
container.style.overflow = 'auto';
|
|
621
|
+
container.style.padding = '20px';
|
|
622
|
+
container.style.boxSizing = 'border-box';
|
|
623
|
+
const img = document.createElement('img');
|
|
624
|
+
img.src = url;
|
|
625
|
+
img.alt = path.basename(file);
|
|
626
|
+
img.style.maxWidth = '100%';
|
|
627
|
+
img.style.maxHeight = '100%';
|
|
628
|
+
img.style.objectFit = 'contain';
|
|
629
|
+
container.appendChild(img);
|
|
630
|
+
const win = kernel.windows.create({
|
|
316
631
|
title: windowTitle,
|
|
317
|
-
html: imageHtml,
|
|
318
632
|
width: 800,
|
|
319
633
|
height: 600,
|
|
320
634
|
max: false
|
|
321
635
|
});
|
|
636
|
+
win.mount(container);
|
|
322
637
|
await writelnStdout(process, terminal, chalk.green(`Viewing: ${file}`));
|
|
323
638
|
}
|
|
324
639
|
else if (fileType === 'audio') {
|
|
@@ -362,29 +677,50 @@ export function createCommand(kernel, shell, terminal) {
|
|
|
362
677
|
else {
|
|
363
678
|
// Create a simple audio player window
|
|
364
679
|
const audioId = `audio-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
365
|
-
const
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
680
|
+
const containerClass = generateRandomClass('audio-container');
|
|
681
|
+
const container = document.createElement('div');
|
|
682
|
+
container.className = containerClass;
|
|
683
|
+
container.style.width = '100%';
|
|
684
|
+
container.style.height = '100%';
|
|
685
|
+
container.style.display = 'flex';
|
|
686
|
+
container.style.flexDirection = 'column';
|
|
687
|
+
container.style.alignItems = 'center';
|
|
688
|
+
container.style.justifyContent = 'center';
|
|
689
|
+
container.style.background = '#1e1e1e';
|
|
690
|
+
container.style.color = '#fff';
|
|
691
|
+
container.style.fontFamily = 'monospace';
|
|
692
|
+
container.style.padding = '20px';
|
|
693
|
+
container.style.boxSizing = 'border-box';
|
|
694
|
+
const title = document.createElement('div');
|
|
695
|
+
title.textContent = path.basename(file);
|
|
696
|
+
title.style.fontSize = '18px';
|
|
697
|
+
title.style.marginBottom = '20px';
|
|
698
|
+
title.style.textAlign = 'center';
|
|
699
|
+
title.style.wordBreak = 'break-word';
|
|
700
|
+
const audio = document.createElement('audio');
|
|
701
|
+
audio.id = audioId;
|
|
702
|
+
audio.src = url;
|
|
703
|
+
audio.controls = true;
|
|
704
|
+
audio.style.width = '100%';
|
|
705
|
+
audio.style.maxWidth = '600px';
|
|
706
|
+
if (options.autoplay)
|
|
707
|
+
audio.autoplay = true;
|
|
708
|
+
if (options.loop)
|
|
709
|
+
audio.loop = true;
|
|
710
|
+
if (options.muted)
|
|
711
|
+
audio.muted = true;
|
|
712
|
+
audio.volume = options.volume / 100;
|
|
713
|
+
audio.addEventListener('play', () => console.log(`Playing: ${file}`));
|
|
714
|
+
audio.addEventListener('ended', () => console.log(`Finished: ${file}`));
|
|
715
|
+
container.appendChild(title);
|
|
716
|
+
container.appendChild(audio);
|
|
717
|
+
const win = kernel.windows.create({
|
|
382
718
|
title: windowTitle,
|
|
383
|
-
html: audioHtml,
|
|
384
719
|
width: 500,
|
|
385
720
|
height: 200,
|
|
386
721
|
max: false
|
|
387
722
|
});
|
|
723
|
+
win.mount(container);
|
|
388
724
|
if (duration > 0) {
|
|
389
725
|
const durationStr = formatDuration(duration);
|
|
390
726
|
await writelnStdout(process, terminal, chalk.green(`Playing: ${file} (${durationStr})`));
|
|
@@ -446,26 +782,32 @@ export function createCommand(kernel, shell, terminal) {
|
|
|
446
782
|
// Ensure minimum size
|
|
447
783
|
windowWidth = Math.max(windowWidth, 320);
|
|
448
784
|
windowHeight = Math.max(windowHeight, 180);
|
|
449
|
-
|
|
450
|
-
const
|
|
785
|
+
const containerClass = generateRandomClass('video-container');
|
|
786
|
+
const container = document.createElement('div');
|
|
787
|
+
container.className = containerClass;
|
|
788
|
+
container.style.width = '100%';
|
|
789
|
+
container.style.height = '100%';
|
|
790
|
+
const video = document.createElement('video');
|
|
791
|
+
video.src = url;
|
|
792
|
+
video.style.width = '100%';
|
|
793
|
+
video.style.height = '100%';
|
|
794
|
+
video.style.objectFit = 'contain';
|
|
451
795
|
if (options.autoplay)
|
|
452
|
-
|
|
796
|
+
video.autoplay = true;
|
|
453
797
|
if (options.controls)
|
|
454
|
-
|
|
798
|
+
video.controls = true;
|
|
455
799
|
if (options.loop)
|
|
456
|
-
|
|
800
|
+
video.loop = true;
|
|
457
801
|
if (options.muted)
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
const
|
|
461
|
-
// Create window
|
|
462
|
-
kernel.windows.create({
|
|
802
|
+
video.muted = true;
|
|
803
|
+
container.appendChild(video);
|
|
804
|
+
const win = kernel.windows.create({
|
|
463
805
|
title: windowTitle,
|
|
464
|
-
html: videoHtml,
|
|
465
806
|
width: windowWidth,
|
|
466
807
|
height: windowHeight,
|
|
467
808
|
max: options.fullscreen
|
|
468
809
|
});
|
|
810
|
+
win.mount(container);
|
|
469
811
|
if (duration > 0) {
|
|
470
812
|
const minutes = Math.floor(duration / 60);
|
|
471
813
|
const seconds = Math.floor(duration % 60);
|