@ecmaos/coreutils 0.5.0 → 0.5.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 +22 -0
- package/dist/commands/dd.d.ts +4 -0
- package/dist/commands/dd.d.ts.map +1 -0
- package/dist/commands/dd.js +525 -0
- package/dist/commands/dd.js.map +1 -0
- package/dist/commands/ls.d.ts.map +1 -1
- package/dist/commands/ls.js +51 -15
- package/dist/commands/ls.js.map +1 -1
- package/dist/commands/lsx.d.ts +4 -0
- package/dist/commands/lsx.d.ts.map +1 -0
- package/dist/commands/lsx.js +308 -0
- package/dist/commands/lsx.js.map +1 -0
- package/dist/commands/mkdir.d.ts.map +1 -1
- package/dist/commands/mkdir.js +155 -10
- package/dist/commands/mkdir.js.map +1 -1
- package/dist/commands/sed.d.ts.map +1 -1
- package/dist/commands/sed.js +63 -63
- package/dist/commands/sed.js.map +1 -1
- package/dist/commands/view.d.ts.map +1 -1
- package/dist/commands/view.js +0 -2
- package/dist/commands/view.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/commands/dd.ts +547 -0
- package/src/commands/ls.ts +58 -16
- package/src/commands/mkdir.ts +150 -10
- package/src/commands/sed.ts +69 -70
- package/src/commands/view.ts +0 -3
- package/src/index.ts +3 -1
package/src/commands/ls.ts
CHANGED
|
@@ -14,6 +14,33 @@ List information about the FILEs (the current directory by default).
|
|
|
14
14
|
writelnStderr(process, terminal, usage)
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
function truncateInfo(text: string, maxWidth: number = 40): string {
|
|
18
|
+
if (!text) return text
|
|
19
|
+
|
|
20
|
+
// Strip ANSI codes to get visible length
|
|
21
|
+
const ansiRegex = /\x1b\[[0-9;]*m/g
|
|
22
|
+
const plainText = text.replace(ansiRegex, '')
|
|
23
|
+
|
|
24
|
+
if (plainText.length <= maxWidth) return text
|
|
25
|
+
|
|
26
|
+
// Extract all ANSI codes from the original text
|
|
27
|
+
const codes: string[] = []
|
|
28
|
+
let match
|
|
29
|
+
const codeRegex = /\x1b\[[0-9;]*m/g
|
|
30
|
+
while ((match = codeRegex.exec(text)) !== null) {
|
|
31
|
+
codes.push(match[0])
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Truncate plain text and add ellipsis
|
|
35
|
+
const truncated = plainText.substring(0, maxWidth - 3)
|
|
36
|
+
|
|
37
|
+
// Reconstruct with original color codes at the start
|
|
38
|
+
const prefixCodes = codes.length > 0 ? codes[0] : ''
|
|
39
|
+
const resetCode = '\x1b[0m'
|
|
40
|
+
|
|
41
|
+
return `${prefixCodes}${truncated}...${resetCode}`
|
|
42
|
+
}
|
|
43
|
+
|
|
17
44
|
export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal): TerminalCommand {
|
|
18
45
|
return new TerminalCommand({
|
|
19
46
|
command: 'ls',
|
|
@@ -36,8 +63,6 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
36
63
|
|
|
37
64
|
if (targets.length === 0) targets.push(shell.cwd)
|
|
38
65
|
|
|
39
|
-
const descriptions = kernel.filesystem.descriptions(kernel.i18n.t)
|
|
40
|
-
|
|
41
66
|
// Process each target and collect all entries
|
|
42
67
|
// We'll determine if each entry is a directory when we stat it later
|
|
43
68
|
const allEntries: Array<{ fullPath: string, entry: string }> = []
|
|
@@ -110,6 +135,8 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
110
135
|
return ''
|
|
111
136
|
}
|
|
112
137
|
|
|
138
|
+
const descriptions = kernel.filesystem.descriptions(kernel.i18n.ns.filesystem)
|
|
139
|
+
|
|
113
140
|
const filesMap = await Promise.all(allEntries
|
|
114
141
|
.map(async ({ fullPath: entryFullPath, entry }) => {
|
|
115
142
|
const target = path.resolve(entryFullPath, entry)
|
|
@@ -181,7 +208,9 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
181
208
|
|
|
182
209
|
// Check if any entry is in /dev directory
|
|
183
210
|
const isDevDirectory = allEntries.some(e => e.fullPath.startsWith('/dev'))
|
|
184
|
-
const columns = isDevDirectory
|
|
211
|
+
const columns = isDevDirectory
|
|
212
|
+
? [kernel.i18n.ns.common('Name'), kernel.i18n.ns.common('Mode'), kernel.i18n.ns.common('Owner'), kernel.i18n.ns.common('Info')]
|
|
213
|
+
: [kernel.i18n.ns.common('Name'), kernel.i18n.ns.common('Size'), kernel.i18n.ns.common('Modified'), kernel.i18n.ns.common('Mode'), kernel.i18n.ns.common('Owner'), kernel.i18n.ns.common('Info')]
|
|
185
214
|
|
|
186
215
|
const directoryRows = directories.sort((a, b) => a.name.localeCompare(b.name)).map(directory => {
|
|
187
216
|
const displayName = directory.linkTarget
|
|
@@ -201,15 +230,15 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
201
230
|
: chalk.green(displayName)
|
|
202
231
|
|
|
203
232
|
const row: Record<string, string> = {
|
|
204
|
-
Name: coloredName,
|
|
205
|
-
Mode: chalk.gray(modeString),
|
|
206
|
-
Owner: directory.stats ? chalk.gray(getOwnerString(directory.stats)) : '',
|
|
207
|
-
Info: chalk.gray(linkInfo)
|
|
233
|
+
[kernel.i18n.ns.common('Name')]: coloredName,
|
|
234
|
+
[kernel.i18n.ns.common('Mode')]: chalk.gray(modeString),
|
|
235
|
+
[kernel.i18n.ns.common('Owner')]: directory.stats ? chalk.gray(getOwnerString(directory.stats)) : '',
|
|
236
|
+
[kernel.i18n.ns.common('Info')]: truncateInfo(chalk.gray(linkInfo))
|
|
208
237
|
}
|
|
209
238
|
|
|
210
239
|
if (!isDevDirectory) {
|
|
211
|
-
row.Size = ''
|
|
212
|
-
row.Modified = directory.stats ? chalk.gray(getTimestampString(directory.stats.mtime)) : ''
|
|
240
|
+
row[kernel.i18n.ns.common('Size')] = ''
|
|
241
|
+
row[kernel.i18n.ns.common('Modified')] = directory.stats ? chalk.gray(getTimestampString(directory.stats.mtime)) : ''
|
|
213
242
|
}
|
|
214
243
|
|
|
215
244
|
return row
|
|
@@ -235,6 +264,16 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
235
264
|
const linkInfo = getLinkInfo(file.linkTarget, file.linkStats, file.stats)
|
|
236
265
|
if (linkInfo) return linkInfo
|
|
237
266
|
|
|
267
|
+
// Check if this is a command in /bin/ and use coreutils translations
|
|
268
|
+
if (file.target.startsWith('/bin/')) {
|
|
269
|
+
const commandName = path.basename(file.target)
|
|
270
|
+
const translatedDescription = kernel.i18n.ns.coreutils(commandName)
|
|
271
|
+
// Only use translation if it exists (i18next returns the key if translation is missing)
|
|
272
|
+
if (translatedDescription !== commandName) {
|
|
273
|
+
return translatedDescription
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
238
277
|
if (descriptions.has(file.target)) return descriptions.get(file.target) || ''
|
|
239
278
|
if (file.name.includes('.')) {
|
|
240
279
|
const ext = file.name.split('.').pop()
|
|
@@ -242,22 +281,25 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
242
281
|
}
|
|
243
282
|
if (!file.stats) return ''
|
|
244
283
|
if (file.stats.isBlockDevice() || file.stats.isCharacterDevice()) {
|
|
245
|
-
|
|
284
|
+
const devicePackage = kernel.devices.get(path.basename(file.target))
|
|
285
|
+
const description = devicePackage?.device?.pkg?.description || ''
|
|
286
|
+
const hasCLI = devicePackage?.device?.cli !== undefined
|
|
287
|
+
return `${description}${hasCLI ? ' ' + `${chalk.bold(`(${kernel.i18n.t('CLI')})`)}${chalk.reset()}` : ''}`
|
|
246
288
|
}
|
|
247
289
|
|
|
248
290
|
return ''
|
|
249
291
|
})()
|
|
250
292
|
|
|
251
293
|
const row: Record<string, string> = {
|
|
252
|
-
Name: coloredName,
|
|
253
|
-
Mode: chalk.gray(modeString),
|
|
254
|
-
Owner: file.stats ? chalk.gray(getOwnerString(file.stats)) : '',
|
|
255
|
-
Info: chalk.gray(info)
|
|
294
|
+
[kernel.i18n.ns.common('Name')]: coloredName,
|
|
295
|
+
[kernel.i18n.ns.common('Mode')]: chalk.gray(modeString),
|
|
296
|
+
[kernel.i18n.ns.common('Owner')]: file.stats ? chalk.gray(getOwnerString(file.stats)) : '',
|
|
297
|
+
[kernel.i18n.ns.common('Info')]: truncateInfo(chalk.gray(info))
|
|
256
298
|
}
|
|
257
299
|
|
|
258
300
|
if (!isDevDirectory) {
|
|
259
|
-
row.Size = file.stats ? chalk.gray(humanFormat(file.stats.size)) : ''
|
|
260
|
-
row.Modified = file.stats ? chalk.gray(getTimestampString(file.stats.mtime)) : ''
|
|
301
|
+
row[kernel.i18n.ns.common('Size')] = file.stats ? chalk.gray(humanFormat(file.stats.size)) : ''
|
|
302
|
+
row[kernel.i18n.ns.common('Modified')] = file.stats ? chalk.gray(getTimestampString(file.stats.mtime)) : ''
|
|
261
303
|
}
|
|
262
304
|
|
|
263
305
|
return row
|
package/src/commands/mkdir.ts
CHANGED
|
@@ -1,16 +1,31 @@
|
|
|
1
1
|
import path from 'path'
|
|
2
2
|
import type { Kernel, Process, Shell, Terminal } from '@ecmaos/types'
|
|
3
3
|
import { TerminalCommand } from '../shared/terminal-command.js'
|
|
4
|
-
import { writelnStderr } from '../shared/helpers.js'
|
|
4
|
+
import { writelnStderr, writelnStdout } from '../shared/helpers.js'
|
|
5
5
|
|
|
6
6
|
function printUsage(process: Process | undefined, terminal: Terminal): void {
|
|
7
7
|
const usage = `Usage: mkdir [OPTION]... DIRECTORY...
|
|
8
8
|
Create the DIRECTORY(ies), if they do not already exist.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Mandatory arguments to long options are mandatory for short options too.
|
|
11
|
+
-m, --mode=MODE set file mode (as in chmod), not a=rwx - umask
|
|
12
|
+
-p, --parents no error if existing, make parent directories as needed,
|
|
13
|
+
with their file modes unaffected by any -m option.
|
|
14
|
+
-v, --verbose print a message for each created directory
|
|
15
|
+
--help display this help and exit`
|
|
11
16
|
writelnStderr(process, terminal, usage)
|
|
12
17
|
}
|
|
13
18
|
|
|
19
|
+
function parseNumericMode(mode: string): number | null {
|
|
20
|
+
if (/^0?[0-7]{1,4}$/.test(mode)) {
|
|
21
|
+
return parseInt(mode, 8)
|
|
22
|
+
}
|
|
23
|
+
if (/^0o[0-7]{1,4}$/i.test(mode)) {
|
|
24
|
+
return parseInt(mode.slice(2), 8)
|
|
25
|
+
}
|
|
26
|
+
return null
|
|
27
|
+
}
|
|
28
|
+
|
|
14
29
|
export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal): TerminalCommand {
|
|
15
30
|
return new TerminalCommand({
|
|
16
31
|
command: 'mkdir',
|
|
@@ -26,7 +41,104 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
26
41
|
return 0
|
|
27
42
|
}
|
|
28
43
|
|
|
29
|
-
|
|
44
|
+
let parents = false
|
|
45
|
+
let verbose = false
|
|
46
|
+
let mode: number | undefined = undefined
|
|
47
|
+
const directories: string[] = []
|
|
48
|
+
|
|
49
|
+
let i = 0
|
|
50
|
+
while (i < argv.length) {
|
|
51
|
+
const arg = argv[i]
|
|
52
|
+
if (!arg) {
|
|
53
|
+
i++
|
|
54
|
+
continue
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (arg === '--') {
|
|
58
|
+
i++
|
|
59
|
+
while (i < argv.length) {
|
|
60
|
+
const dirArg = argv[i]
|
|
61
|
+
if (dirArg) {
|
|
62
|
+
directories.push(dirArg)
|
|
63
|
+
}
|
|
64
|
+
i++
|
|
65
|
+
}
|
|
66
|
+
break
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (arg.startsWith('--')) {
|
|
70
|
+
if (arg === '--parents') {
|
|
71
|
+
parents = true
|
|
72
|
+
} else if (arg === '--verbose') {
|
|
73
|
+
verbose = true
|
|
74
|
+
} else if (arg.startsWith('--mode=')) {
|
|
75
|
+
const modeStr = arg.slice(7)
|
|
76
|
+
const parsedMode = parseNumericMode(modeStr)
|
|
77
|
+
if (parsedMode === null) {
|
|
78
|
+
await writelnStderr(process, terminal, `mkdir: invalid mode '${modeStr}'`)
|
|
79
|
+
return 1
|
|
80
|
+
}
|
|
81
|
+
mode = parsedMode
|
|
82
|
+
} else if (arg === '--help' || arg === '-h') {
|
|
83
|
+
printUsage(process, terminal)
|
|
84
|
+
return 0
|
|
85
|
+
} else {
|
|
86
|
+
await writelnStderr(process, terminal, `mkdir: unrecognized option '${arg}'`)
|
|
87
|
+
await writelnStderr(process, terminal, "Try 'mkdir --help' for more information.")
|
|
88
|
+
return 1
|
|
89
|
+
}
|
|
90
|
+
} else if (arg.startsWith('-') && arg.length > 1) {
|
|
91
|
+
for (let j = 1; j < arg.length; j++) {
|
|
92
|
+
const flag = arg[j]
|
|
93
|
+
if (!flag) continue
|
|
94
|
+
|
|
95
|
+
if (flag === 'p') {
|
|
96
|
+
parents = true
|
|
97
|
+
} else if (flag === 'v') {
|
|
98
|
+
verbose = true
|
|
99
|
+
} else if (flag === 'm') {
|
|
100
|
+
if (j + 1 < arg.length) {
|
|
101
|
+
const modeStr = arg.slice(j + 1)
|
|
102
|
+
const parsedMode = parseNumericMode(modeStr)
|
|
103
|
+
if (parsedMode === null) {
|
|
104
|
+
await writelnStderr(process, terminal, `mkdir: invalid mode '${modeStr}'`)
|
|
105
|
+
return 1
|
|
106
|
+
}
|
|
107
|
+
mode = parsedMode
|
|
108
|
+
break
|
|
109
|
+
} else if (i + 1 < argv.length) {
|
|
110
|
+
const modeStr = argv[i + 1]
|
|
111
|
+
if (!modeStr) {
|
|
112
|
+
await writelnStderr(process, terminal, "mkdir: option requires an argument -- 'm'")
|
|
113
|
+
await writelnStderr(process, terminal, "Try 'mkdir --help' for more information.")
|
|
114
|
+
return 1
|
|
115
|
+
}
|
|
116
|
+
const parsedMode = parseNumericMode(modeStr)
|
|
117
|
+
if (parsedMode === null) {
|
|
118
|
+
await writelnStderr(process, terminal, `mkdir: invalid mode '${modeStr}'`)
|
|
119
|
+
return 1
|
|
120
|
+
}
|
|
121
|
+
mode = parsedMode
|
|
122
|
+
i++
|
|
123
|
+
break
|
|
124
|
+
} else {
|
|
125
|
+
await writelnStderr(process, terminal, "mkdir: option requires an argument -- 'm'")
|
|
126
|
+
await writelnStderr(process, terminal, "Try 'mkdir --help' for more information.")
|
|
127
|
+
return 1
|
|
128
|
+
}
|
|
129
|
+
} else {
|
|
130
|
+
await writelnStderr(process, terminal, `mkdir: invalid option -- '${flag}'`)
|
|
131
|
+
await writelnStderr(process, terminal, "Try 'mkdir --help' for more information.")
|
|
132
|
+
return 1
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
} else {
|
|
136
|
+
directories.push(arg)
|
|
137
|
+
}
|
|
138
|
+
i++
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (directories.length === 0) {
|
|
30
142
|
await writelnStderr(process, terminal, 'mkdir: missing operand')
|
|
31
143
|
await writelnStderr(process, terminal, "Try 'mkdir --help' for more information.")
|
|
32
144
|
return 1
|
|
@@ -34,17 +146,45 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
34
146
|
|
|
35
147
|
let hasError = false
|
|
36
148
|
|
|
37
|
-
for (const target of
|
|
38
|
-
if (!target
|
|
149
|
+
for (const target of directories) {
|
|
150
|
+
if (!target) continue
|
|
39
151
|
|
|
40
|
-
const fullPath =
|
|
152
|
+
const fullPath = path.resolve(shell.cwd, target)
|
|
41
153
|
|
|
42
154
|
try {
|
|
43
|
-
|
|
155
|
+
const mkdirOptions: { recursive?: boolean; mode?: number } = {}
|
|
156
|
+
if (parents) {
|
|
157
|
+
mkdirOptions.recursive = true
|
|
158
|
+
}
|
|
159
|
+
if (mode !== undefined) {
|
|
160
|
+
mkdirOptions.mode = mode
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
let existedBefore = false
|
|
164
|
+
if (parents) {
|
|
165
|
+
try {
|
|
166
|
+
await shell.context.fs.promises.stat(fullPath)
|
|
167
|
+
existedBefore = true
|
|
168
|
+
} catch {
|
|
169
|
+
existedBefore = false
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
await shell.context.fs.promises.mkdir(fullPath, mkdirOptions)
|
|
174
|
+
|
|
175
|
+
if (verbose && !existedBefore) {
|
|
176
|
+
const relativePath = path.relative(shell.cwd, fullPath) || target
|
|
177
|
+
await writelnStdout(process, terminal, `mkdir: created directory '${relativePath}'`)
|
|
178
|
+
}
|
|
44
179
|
} catch (error) {
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
180
|
+
const err = error as { code?: string; message?: string }
|
|
181
|
+
if (parents && err.code === 'EEXIST') {
|
|
182
|
+
continue
|
|
183
|
+
} else {
|
|
184
|
+
const errorMessage = error instanceof Error ? error.message : String(error)
|
|
185
|
+
await writelnStderr(process, terminal, `mkdir: ${target}: ${errorMessage}`)
|
|
186
|
+
hasError = true
|
|
187
|
+
}
|
|
48
188
|
}
|
|
49
189
|
}
|
|
50
190
|
|
package/src/commands/sed.ts
CHANGED
|
@@ -236,9 +236,9 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
236
236
|
const trimmed = arg.trim()
|
|
237
237
|
return (
|
|
238
238
|
trimmed.startsWith('s/') ||
|
|
239
|
-
trimmed
|
|
240
|
-
/^\d+[sd]
|
|
241
|
-
/^\d+,\d*[sd]
|
|
239
|
+
/^\/.+?\/[dp]$/.test(trimmed) ||
|
|
240
|
+
/^\d+[sd]$/.test(trimmed) ||
|
|
241
|
+
/^\d+,\d*[sd]$/.test(trimmed) ||
|
|
242
242
|
/^\d+s\//.test(trimmed) ||
|
|
243
243
|
/^\d+,\d*s\//.test(trimmed)
|
|
244
244
|
)
|
|
@@ -341,73 +341,6 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
341
341
|
return content.split('\n')
|
|
342
342
|
}
|
|
343
343
|
|
|
344
|
-
let inputLines: string[] = []
|
|
345
|
-
|
|
346
|
-
if (files.length > 0) {
|
|
347
|
-
for (const file of files) {
|
|
348
|
-
const expandedPath = shell.expandTilde(file)
|
|
349
|
-
const fullPath = path.resolve(shell.cwd, expandedPath)
|
|
350
|
-
const lines = await processFile(fullPath)
|
|
351
|
-
inputLines.push(...lines)
|
|
352
|
-
if (lines.length > 0 && inputLines.length > lines.length) {
|
|
353
|
-
inputLines.push('')
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
} else {
|
|
357
|
-
if (!process.stdin) {
|
|
358
|
-
await writelnStderr(process, terminal, 'sed: No input provided')
|
|
359
|
-
return 1
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
const reader = process.stdin.getReader()
|
|
363
|
-
const decoder = new TextDecoder()
|
|
364
|
-
const chunks: string[] = []
|
|
365
|
-
|
|
366
|
-
try {
|
|
367
|
-
while (true) {
|
|
368
|
-
const { done, value } = await reader.read()
|
|
369
|
-
if (done) break
|
|
370
|
-
chunks.push(decoder.decode(value, { stream: true }))
|
|
371
|
-
}
|
|
372
|
-
chunks.push(decoder.decode(new Uint8Array(), { stream: false }))
|
|
373
|
-
} finally {
|
|
374
|
-
reader.releaseLock()
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
const content = chunks.join('')
|
|
378
|
-
inputLines = content.split('\n')
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
const outputLines: string[] = []
|
|
382
|
-
const totalLines = inputLines.length
|
|
383
|
-
|
|
384
|
-
for (let i = 0; i < inputLines.length; i++) {
|
|
385
|
-
let line = inputLines[i] || ''
|
|
386
|
-
let lineNum = i + 1
|
|
387
|
-
let shouldPrint = false
|
|
388
|
-
|
|
389
|
-
for (const command of commands) {
|
|
390
|
-
const { result, shouldPrint: print } = applySedCommand(line, lineNum, totalLines, command)
|
|
391
|
-
if (result === null) {
|
|
392
|
-
line = null as unknown as string
|
|
393
|
-
break
|
|
394
|
-
}
|
|
395
|
-
line = result
|
|
396
|
-
if (print) {
|
|
397
|
-
shouldPrint = true
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
if (line !== null) {
|
|
402
|
-
outputLines.push(line)
|
|
403
|
-
if (shouldPrint && !quiet) {
|
|
404
|
-
outputLines.push(line)
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
const output = outputLines.join('\n')
|
|
410
|
-
|
|
411
344
|
if (inplace !== undefined && files.length > 0) {
|
|
412
345
|
for (const file of files) {
|
|
413
346
|
const expandedPath = shell.expandTilde(file)
|
|
@@ -455,6 +388,72 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
455
388
|
await shell.context.fs.promises.writeFile(fullPath, fileOutput)
|
|
456
389
|
}
|
|
457
390
|
} else {
|
|
391
|
+
let inputLines: string[] = []
|
|
392
|
+
|
|
393
|
+
if (files.length > 0) {
|
|
394
|
+
for (const file of files) {
|
|
395
|
+
const expandedPath = shell.expandTilde(file)
|
|
396
|
+
const fullPath = path.resolve(shell.cwd, expandedPath)
|
|
397
|
+
const lines = await processFile(fullPath)
|
|
398
|
+
inputLines.push(...lines)
|
|
399
|
+
if (lines.length > 0 && inputLines.length > lines.length) {
|
|
400
|
+
inputLines.push('')
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
} else {
|
|
404
|
+
if (!process.stdin) {
|
|
405
|
+
await writelnStderr(process, terminal, 'sed: No input provided')
|
|
406
|
+
return 1
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
const reader = process.stdin.getReader()
|
|
410
|
+
const decoder = new TextDecoder()
|
|
411
|
+
const chunks: string[] = []
|
|
412
|
+
|
|
413
|
+
try {
|
|
414
|
+
while (true) {
|
|
415
|
+
const { done, value } = await reader.read()
|
|
416
|
+
if (done) break
|
|
417
|
+
chunks.push(decoder.decode(value, { stream: true }))
|
|
418
|
+
}
|
|
419
|
+
chunks.push(decoder.decode(new Uint8Array(), { stream: false }))
|
|
420
|
+
} finally {
|
|
421
|
+
reader.releaseLock()
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
const content = chunks.join('')
|
|
425
|
+
inputLines = content.split('\n')
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
const outputLines: string[] = []
|
|
429
|
+
const totalLines = inputLines.length
|
|
430
|
+
|
|
431
|
+
for (let i = 0; i < inputLines.length; i++) {
|
|
432
|
+
let line = inputLines[i] || ''
|
|
433
|
+
let lineNum = i + 1
|
|
434
|
+
let shouldPrint = false
|
|
435
|
+
|
|
436
|
+
for (const command of commands) {
|
|
437
|
+
const { result, shouldPrint: print } = applySedCommand(line, lineNum, totalLines, command)
|
|
438
|
+
if (result === null) {
|
|
439
|
+
line = null as unknown as string
|
|
440
|
+
break
|
|
441
|
+
}
|
|
442
|
+
line = result
|
|
443
|
+
if (print) {
|
|
444
|
+
shouldPrint = true
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
if (line !== null) {
|
|
449
|
+
outputLines.push(line)
|
|
450
|
+
if (shouldPrint && !quiet) {
|
|
451
|
+
outputLines.push(line)
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
const output = outputLines.join('\n')
|
|
458
457
|
await writer.write(new TextEncoder().encode(output))
|
|
459
458
|
}
|
|
460
459
|
|
package/src/commands/view.ts
CHANGED
|
@@ -306,7 +306,6 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
306
306
|
}
|
|
307
307
|
|
|
308
308
|
// Read file
|
|
309
|
-
await writelnStdout(process, terminal, chalk.blue(`Loading: ${file}...`))
|
|
310
309
|
const fileData = await shell.context.fs.promises.readFile(fullPath)
|
|
311
310
|
const fileType = detectFileType(fullPath)
|
|
312
311
|
const mimeType = getMimeType(fullPath, fileType)
|
|
@@ -374,8 +373,6 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
374
373
|
})
|
|
375
374
|
|
|
376
375
|
win.mount(container)
|
|
377
|
-
|
|
378
|
-
await writelnStdout(process, terminal, chalk.green(`Viewing: ${file}`))
|
|
379
376
|
} else if (fileType === 'json') {
|
|
380
377
|
// Read and parse JSON file
|
|
381
378
|
const jsonText = new TextDecoder().decode(fileData)
|
package/src/index.ts
CHANGED
|
@@ -61,6 +61,7 @@ import { createCommand as createColumn } from './commands/column.js'
|
|
|
61
61
|
import { createCommand as createComm } from './commands/comm.js'
|
|
62
62
|
import { createCommand as createCurl } from './commands/curl.js'
|
|
63
63
|
import { createCommand as createCut } from './commands/cut.js'
|
|
64
|
+
import { createCommand as createDd } from './commands/dd.js'
|
|
64
65
|
import { createCommand as createDate } from './commands/date.js'
|
|
65
66
|
import { createCommand as createDiff } from './commands/diff.js'
|
|
66
67
|
import { createCommand as createDirname } from './commands/dirname.js'
|
|
@@ -147,6 +148,7 @@ export { createCommand as createCmp } from './commands/cmp.js'
|
|
|
147
148
|
export { createCommand as createColumn } from './commands/column.js'
|
|
148
149
|
export { createCommand as createCurl } from './commands/curl.js'
|
|
149
150
|
export { createCommand as createCut } from './commands/cut.js'
|
|
151
|
+
export { createCommand as createDd } from './commands/dd.js'
|
|
150
152
|
export { createCommand as createDate } from './commands/date.js'
|
|
151
153
|
export { createCommand as createDiff } from './commands/diff.js'
|
|
152
154
|
export { createCommand as createDirname } from './commands/dirname.js'
|
|
@@ -233,6 +235,7 @@ export function createAllCommands(kernel: Kernel, shell: Shell, terminal: Termin
|
|
|
233
235
|
comm: createComm(kernel, shell, terminal),
|
|
234
236
|
curl: createCurl(kernel, shell, terminal),
|
|
235
237
|
cut: createCut(kernel, shell, terminal),
|
|
238
|
+
dd: createDd(kernel, shell, terminal),
|
|
236
239
|
date: createDate(kernel, shell, terminal),
|
|
237
240
|
diff: createDiff(kernel, shell, terminal),
|
|
238
241
|
dirname: createDirname(kernel, shell, terminal),
|
|
@@ -275,4 +278,3 @@ export function createAllCommands(kernel: Kernel, shell: Shell, terminal: Termin
|
|
|
275
278
|
|
|
276
279
|
// For backward compatibility, export as TerminalCommands
|
|
277
280
|
export { createAllCommands as TerminalCommands }
|
|
278
|
-
|