@ecmaos/coreutils 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +42 -0
- 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/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/head.d.ts.map +1 -1
- package/dist/commands/head.js +184 -77
- package/dist/commands/head.js.map +1 -1
- 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 +1041 -0
- package/dist/commands/mount.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 +104 -0
- package/dist/commands/umount.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/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/package.json +10 -2
- package/src/commands/cron.ts +115 -23
- package/src/commands/env.ts +143 -0
- package/src/commands/head.ts +176 -77
- package/src/commands/less.ts +1 -0
- package/src/commands/man.ts +4 -1
- package/src/commands/mount.ts +1193 -0
- package/src/commands/umount.ts +117 -0
- package/src/commands/view.ts +463 -73
- package/src/index.ts +9 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import chalk from 'chalk'
|
|
2
|
+
import type { Kernel, Process, Shell, Terminal } from '@ecmaos/types'
|
|
3
|
+
import { TerminalCommand } from '../shared/terminal-command.js'
|
|
4
|
+
import { writelnStderr, writeStdout } from '../shared/helpers.js'
|
|
5
|
+
|
|
6
|
+
function printUsage(process: Process | undefined, terminal: Terminal): void {
|
|
7
|
+
const usage = `Usage: env [OPTION]... [NAME=VALUE]... [COMMAND [ARG]...]
|
|
8
|
+
Set each NAME to VALUE in the environment and run COMMAND.
|
|
9
|
+
|
|
10
|
+
-i, --ignore-environment start with an empty environment
|
|
11
|
+
-u, --unset=NAME remove variable from the environment
|
|
12
|
+
-0, --null end each output line with NUL, not newline
|
|
13
|
+
--help display this help and exit`
|
|
14
|
+
writelnStderr(process, terminal, usage)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal): TerminalCommand {
|
|
18
|
+
return new TerminalCommand({
|
|
19
|
+
command: 'env',
|
|
20
|
+
description: 'Run a program in a modified environment',
|
|
21
|
+
kernel,
|
|
22
|
+
shell,
|
|
23
|
+
terminal,
|
|
24
|
+
run: async (pid: number, argv: string[]) => {
|
|
25
|
+
const process = kernel.processes.get(pid) as Process | undefined
|
|
26
|
+
|
|
27
|
+
if (argv.length > 0 && (argv[0] === '--help' || argv[0] === '-h')) {
|
|
28
|
+
printUsage(process, terminal)
|
|
29
|
+
return 0
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
let ignoreEnvironment = false
|
|
33
|
+
const unsetVars: string[] = []
|
|
34
|
+
let nullTerminated = false
|
|
35
|
+
const envVars: Record<string, string> = {}
|
|
36
|
+
let commandStartIndex = -1
|
|
37
|
+
|
|
38
|
+
let i = 0
|
|
39
|
+
while (i < argv.length) {
|
|
40
|
+
const arg = argv[i]
|
|
41
|
+
if (!arg) {
|
|
42
|
+
i++
|
|
43
|
+
continue
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (arg === '-i' || arg === '--ignore-environment') {
|
|
47
|
+
ignoreEnvironment = true
|
|
48
|
+
} else if (arg === '-0' || arg === '--null') {
|
|
49
|
+
nullTerminated = true
|
|
50
|
+
} else if (arg === '-u' || arg.startsWith('--unset=')) {
|
|
51
|
+
let varName: string
|
|
52
|
+
if (arg.startsWith('--unset=')) {
|
|
53
|
+
varName = arg.slice(8)
|
|
54
|
+
} else {
|
|
55
|
+
i++
|
|
56
|
+
varName = argv[i] || ''
|
|
57
|
+
if (!varName) {
|
|
58
|
+
await writelnStderr(process, terminal, chalk.red('env: option requires an argument -- \'u\''))
|
|
59
|
+
return 1
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (varName) {
|
|
63
|
+
unsetVars.push(varName)
|
|
64
|
+
}
|
|
65
|
+
} else if (arg.includes('=')) {
|
|
66
|
+
const [name, ...valueParts] = arg.split('=')
|
|
67
|
+
if (name && valueParts.length > 0) {
|
|
68
|
+
envVars[name] = valueParts.join('=')
|
|
69
|
+
}
|
|
70
|
+
} else {
|
|
71
|
+
commandStartIndex = i
|
|
72
|
+
break
|
|
73
|
+
}
|
|
74
|
+
i++
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const baseEnv = ignoreEnvironment ? {} : Object.fromEntries(shell.env.entries())
|
|
78
|
+
|
|
79
|
+
for (const varName of unsetVars) {
|
|
80
|
+
delete baseEnv[varName]
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const modifiedEnv = { ...baseEnv, ...envVars }
|
|
84
|
+
|
|
85
|
+
if (commandStartIndex === -1) {
|
|
86
|
+
const entries = Object.entries(modifiedEnv).sort(([a], [b]) => a.localeCompare(b))
|
|
87
|
+
const separator = nullTerminated ? '\0' : '\n'
|
|
88
|
+
|
|
89
|
+
for (const [key, value] of entries) {
|
|
90
|
+
const output = `${key}=${value}${separator}`
|
|
91
|
+
await writeStdout(process, terminal, output)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (!nullTerminated && entries.length > 0) {
|
|
95
|
+
await writeStdout(process, terminal, '\n')
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return 0
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const commandArgs = argv.slice(commandStartIndex)
|
|
102
|
+
const command = commandArgs[0]
|
|
103
|
+
if (!command) {
|
|
104
|
+
await writelnStderr(process, terminal, chalk.red('env: missing command'))
|
|
105
|
+
return 1
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const originalEnv = new Map(shell.env)
|
|
109
|
+
const originalProcessEnv = { ...globalThis.process.env }
|
|
110
|
+
|
|
111
|
+
for (const [key, value] of Object.entries(modifiedEnv)) {
|
|
112
|
+
shell.env.set(key, value)
|
|
113
|
+
globalThis.process.env[key] = value
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
for (const varName of unsetVars) {
|
|
117
|
+
shell.env.delete(varName)
|
|
118
|
+
delete globalThis.process.env[varName]
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
try {
|
|
122
|
+
const commandLine = commandArgs.join(' ')
|
|
123
|
+
const exitCode = await shell.execute(commandLine)
|
|
124
|
+
return exitCode ?? 1
|
|
125
|
+
} finally {
|
|
126
|
+
shell.env.clear()
|
|
127
|
+
for (const [key, value] of originalEnv.entries()) {
|
|
128
|
+
shell.env.set(key, value)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
for (const key in globalThis.process.env) {
|
|
132
|
+
if (!(key in originalProcessEnv)) {
|
|
133
|
+
delete globalThis.process.env[key]
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
for (const [key, value] of Object.entries(originalProcessEnv)) {
|
|
138
|
+
globalThis.process.env[key] = value
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
})
|
|
143
|
+
}
|
package/src/commands/head.ts
CHANGED
|
@@ -9,6 +9,7 @@ function printUsage(process: Process | undefined, terminal: Terminal): void {
|
|
|
9
9
|
Print the first 10 lines of each FILE to standard output.
|
|
10
10
|
|
|
11
11
|
-n, -nNUMBER print the first NUMBER lines instead of 10
|
|
12
|
+
-c, -cNUMBER print the first NUMBER bytes instead of lines
|
|
12
13
|
--help display this help and exit`
|
|
13
14
|
writelnStderr(process, terminal, usage)
|
|
14
15
|
}
|
|
@@ -31,6 +32,7 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
let numLines = 10
|
|
35
|
+
let numBytes: number | null = null
|
|
34
36
|
const files: string[] = []
|
|
35
37
|
|
|
36
38
|
for (let i = 0; i < argv.length; i++) {
|
|
@@ -52,6 +54,18 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
52
54
|
const num = parseInt(arg.slice(2), 10)
|
|
53
55
|
if (!isNaN(num)) numLines = num
|
|
54
56
|
}
|
|
57
|
+
} else if (arg === '-c' || arg.startsWith('-c')) {
|
|
58
|
+
if (arg === '-c' && i + 1 < argv.length) {
|
|
59
|
+
i++
|
|
60
|
+
const nextArg = argv[i]
|
|
61
|
+
if (nextArg !== undefined) {
|
|
62
|
+
const num = parseInt(nextArg, 10)
|
|
63
|
+
if (!isNaN(num)) numBytes = num
|
|
64
|
+
}
|
|
65
|
+
} else if (arg.startsWith('-c') && arg.length > 2) {
|
|
66
|
+
const num = parseInt(arg.slice(2), 10)
|
|
67
|
+
if (!isNaN(num)) numBytes = num
|
|
68
|
+
}
|
|
55
69
|
} else if (!arg.startsWith('-')) {
|
|
56
70
|
files.push(arg)
|
|
57
71
|
}
|
|
@@ -66,37 +80,83 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
66
80
|
}
|
|
67
81
|
|
|
68
82
|
const reader = process.stdin.getReader()
|
|
69
|
-
const decoder = new TextDecoder()
|
|
70
|
-
const lines: string[] = []
|
|
71
|
-
let buffer = ''
|
|
72
83
|
|
|
73
84
|
try {
|
|
74
|
-
|
|
75
|
-
let
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
85
|
+
if (numBytes !== null) {
|
|
86
|
+
let bytesRead = 0
|
|
87
|
+
const chunks: Uint8Array[] = []
|
|
88
|
+
|
|
89
|
+
while (bytesRead < numBytes) {
|
|
90
|
+
let readResult
|
|
91
|
+
try {
|
|
92
|
+
readResult = await reader.read()
|
|
93
|
+
} catch (error) {
|
|
94
|
+
if (error instanceof Error) {
|
|
95
|
+
throw error
|
|
96
|
+
}
|
|
97
|
+
break
|
|
81
98
|
}
|
|
82
|
-
|
|
99
|
+
|
|
100
|
+
const { done, value } = readResult
|
|
101
|
+
if (done) break
|
|
102
|
+
if (value) {
|
|
103
|
+
const remaining = numBytes - bytesRead
|
|
104
|
+
if (value.length <= remaining) {
|
|
105
|
+
chunks.push(value)
|
|
106
|
+
bytesRead += value.length
|
|
107
|
+
} else {
|
|
108
|
+
chunks.push(value.subarray(0, remaining))
|
|
109
|
+
bytesRead = numBytes
|
|
110
|
+
}
|
|
111
|
+
if (bytesRead >= numBytes) break
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0)
|
|
116
|
+
const result = new Uint8Array(totalLength)
|
|
117
|
+
let offset = 0
|
|
118
|
+
for (const chunk of chunks) {
|
|
119
|
+
result.set(chunk, offset)
|
|
120
|
+
offset += chunk.length
|
|
83
121
|
}
|
|
122
|
+
await writer.write(result)
|
|
123
|
+
} else {
|
|
124
|
+
const decoder = new TextDecoder()
|
|
125
|
+
const lines: string[] = []
|
|
126
|
+
let buffer = ''
|
|
84
127
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
128
|
+
while (true) {
|
|
129
|
+
let readResult
|
|
130
|
+
try {
|
|
131
|
+
readResult = await reader.read()
|
|
132
|
+
} catch (error) {
|
|
133
|
+
if (error instanceof Error) {
|
|
134
|
+
throw error
|
|
135
|
+
}
|
|
136
|
+
break
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const { done, value } = readResult
|
|
140
|
+
if (done) {
|
|
141
|
+
buffer += decoder.decode()
|
|
142
|
+
break
|
|
143
|
+
}
|
|
144
|
+
if (value) {
|
|
145
|
+
buffer += decoder.decode(value, { stream: true })
|
|
146
|
+
const newLines = buffer.split('\n')
|
|
147
|
+
buffer = newLines.pop() || ''
|
|
148
|
+
lines.push(...newLines)
|
|
149
|
+
if (lines.length >= numLines) break
|
|
150
|
+
}
|
|
89
151
|
}
|
|
90
|
-
if (
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
152
|
+
if (buffer && lines.length < numLines) {
|
|
153
|
+
lines.push(buffer)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const output = lines.slice(0, numLines).join('\n')
|
|
157
|
+
if (output) {
|
|
158
|
+
await writer.write(new TextEncoder().encode(output + '\n'))
|
|
96
159
|
}
|
|
97
|
-
}
|
|
98
|
-
if (buffer && lines.length < numLines) {
|
|
99
|
-
lines.push(buffer)
|
|
100
160
|
}
|
|
101
161
|
} finally {
|
|
102
162
|
try {
|
|
@@ -105,11 +165,6 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
105
165
|
}
|
|
106
166
|
}
|
|
107
167
|
|
|
108
|
-
const output = lines.slice(0, numLines).join('\n')
|
|
109
|
-
if (output) {
|
|
110
|
-
await writer.write(new TextEncoder().encode(output + '\n'))
|
|
111
|
-
}
|
|
112
|
-
|
|
113
168
|
return 0
|
|
114
169
|
}
|
|
115
170
|
|
|
@@ -130,66 +185,110 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
130
185
|
kernel.terminal.events.on(TerminalEvents.INTERRUPT, interruptHandler)
|
|
131
186
|
|
|
132
187
|
try {
|
|
133
|
-
if (
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
if (interrupted) break
|
|
188
|
+
if (numBytes !== null) {
|
|
189
|
+
if (!fullPath.startsWith('/dev')) {
|
|
190
|
+
const handle = await shell.context.fs.promises.open(fullPath, 'r')
|
|
191
|
+
const stat = await shell.context.fs.promises.stat(fullPath)
|
|
192
|
+
const readSize = Math.min(numBytes, stat.size)
|
|
193
|
+
const data = new Uint8Array(readSize)
|
|
194
|
+
await handle.read(data, 0, readSize, 0)
|
|
195
|
+
await writer.write(data)
|
|
196
|
+
} else {
|
|
197
|
+
const device = await shell.context.fs.promises.open(fullPath)
|
|
198
|
+
const chunkSize = 1024
|
|
145
199
|
const data = new Uint8Array(chunkSize)
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
const
|
|
149
|
-
buffer += decoder.decode(chunk, { stream: true })
|
|
150
|
-
const newLines = buffer.split('\n')
|
|
151
|
-
buffer = newLines.pop() || ''
|
|
152
|
-
lines.push(...newLines)
|
|
153
|
-
bytesRead += readSize
|
|
154
|
-
if (lines.length >= numLines) break
|
|
155
|
-
}
|
|
156
|
-
if (buffer && lines.length < numLines) {
|
|
157
|
-
lines.push(buffer)
|
|
158
|
-
}
|
|
200
|
+
let totalBytesRead = 0
|
|
201
|
+
let bytesRead = 0
|
|
202
|
+
const chunks: Uint8Array[] = []
|
|
159
203
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
204
|
+
do {
|
|
205
|
+
if (interrupted) break
|
|
206
|
+
const result = await device.read(data)
|
|
207
|
+
bytesRead = result.bytesRead
|
|
208
|
+
if (bytesRead > 0) {
|
|
209
|
+
const remaining = numBytes - totalBytesRead
|
|
210
|
+
if (bytesRead <= remaining) {
|
|
211
|
+
chunks.push(data.subarray(0, bytesRead))
|
|
212
|
+
totalBytesRead += bytesRead
|
|
213
|
+
} else {
|
|
214
|
+
chunks.push(data.subarray(0, remaining))
|
|
215
|
+
totalBytesRead = numBytes
|
|
216
|
+
}
|
|
217
|
+
if (totalBytesRead >= numBytes) break
|
|
218
|
+
}
|
|
219
|
+
} while (totalBytesRead < numBytes && bytesRead > 0)
|
|
220
|
+
|
|
221
|
+
const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0)
|
|
222
|
+
const result = new Uint8Array(totalLength)
|
|
223
|
+
let offset = 0
|
|
224
|
+
for (const chunk of chunks) {
|
|
225
|
+
result.set(chunk, offset)
|
|
226
|
+
offset += chunk.length
|
|
227
|
+
}
|
|
228
|
+
await writer.write(result)
|
|
163
229
|
}
|
|
164
230
|
} else {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
let buffer = ''
|
|
169
|
-
const chunkSize = 1024
|
|
170
|
-
const data = new Uint8Array(chunkSize)
|
|
171
|
-
let bytesRead = 0
|
|
231
|
+
if (!fullPath.startsWith('/dev')) {
|
|
232
|
+
const handle = await shell.context.fs.promises.open(fullPath, 'r')
|
|
233
|
+
const stat = await shell.context.fs.promises.stat(fullPath)
|
|
172
234
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
bytesRead =
|
|
177
|
-
|
|
178
|
-
|
|
235
|
+
const decoder = new TextDecoder()
|
|
236
|
+
const lines: string[] = []
|
|
237
|
+
let buffer = ''
|
|
238
|
+
let bytesRead = 0
|
|
239
|
+
const chunkSize = 1024
|
|
240
|
+
|
|
241
|
+
while (bytesRead < stat.size && lines.length < numLines) {
|
|
242
|
+
if (interrupted) break
|
|
243
|
+
const data = new Uint8Array(chunkSize)
|
|
244
|
+
const readSize = Math.min(chunkSize, stat.size - bytesRead)
|
|
245
|
+
await handle.read(data, 0, readSize, bytesRead)
|
|
246
|
+
const chunk = data.subarray(0, readSize)
|
|
247
|
+
buffer += decoder.decode(chunk, { stream: true })
|
|
179
248
|
const newLines = buffer.split('\n')
|
|
180
249
|
buffer = newLines.pop() || ''
|
|
181
250
|
lines.push(...newLines)
|
|
251
|
+
bytesRead += readSize
|
|
182
252
|
if (lines.length >= numLines) break
|
|
183
253
|
}
|
|
184
|
-
|
|
254
|
+
if (buffer && lines.length < numLines) {
|
|
255
|
+
lines.push(buffer)
|
|
256
|
+
}
|
|
185
257
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
258
|
+
const output = lines.slice(0, numLines).join('\n')
|
|
259
|
+
if (output) {
|
|
260
|
+
await writer.write(new TextEncoder().encode(output + '\n'))
|
|
261
|
+
}
|
|
262
|
+
} else {
|
|
263
|
+
const device = await shell.context.fs.promises.open(fullPath)
|
|
264
|
+
const decoder = new TextDecoder()
|
|
265
|
+
const lines: string[] = []
|
|
266
|
+
let buffer = ''
|
|
267
|
+
const chunkSize = 1024
|
|
268
|
+
const data = new Uint8Array(chunkSize)
|
|
269
|
+
let bytesRead = 0
|
|
189
270
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
271
|
+
do {
|
|
272
|
+
if (interrupted) break
|
|
273
|
+
const result = await device.read(data)
|
|
274
|
+
bytesRead = result.bytesRead
|
|
275
|
+
if (bytesRead > 0) {
|
|
276
|
+
buffer += decoder.decode(data.subarray(0, bytesRead), { stream: true })
|
|
277
|
+
const newLines = buffer.split('\n')
|
|
278
|
+
buffer = newLines.pop() || ''
|
|
279
|
+
lines.push(...newLines)
|
|
280
|
+
if (lines.length >= numLines) break
|
|
281
|
+
}
|
|
282
|
+
} while (bytesRead > 0 && lines.length < numLines)
|
|
283
|
+
|
|
284
|
+
if (buffer && lines.length < numLines) {
|
|
285
|
+
lines.push(buffer)
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const output = lines.slice(0, numLines).join('\n')
|
|
289
|
+
if (output) {
|
|
290
|
+
await writer.write(new TextEncoder().encode(output + '\n'))
|
|
291
|
+
}
|
|
193
292
|
}
|
|
194
293
|
}
|
|
195
294
|
} finally {
|
package/src/commands/less.ts
CHANGED
|
@@ -144,6 +144,7 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
144
144
|
|
|
145
145
|
if (linesRendered > 0) {
|
|
146
146
|
terminal.write(ansi.cursor.up(linesRendered))
|
|
147
|
+
terminal.write('\r')
|
|
147
148
|
}
|
|
148
149
|
|
|
149
150
|
const endLine = Math.min(currentLine + displayRows, lines.length)
|
package/src/commands/man.ts
CHANGED
|
@@ -409,7 +409,10 @@ async function displayManPage(
|
|
|
409
409
|
if (horizontalOffset > maxHorizontalOffset) horizontalOffset = maxHorizontalOffset
|
|
410
410
|
if (horizontalOffset < 0) horizontalOffset = 0
|
|
411
411
|
|
|
412
|
-
if (linesRendered > 0)
|
|
412
|
+
if (linesRendered > 0) {
|
|
413
|
+
terminal.write(ansi.cursor.up(linesRendered))
|
|
414
|
+
terminal.write('\r')
|
|
415
|
+
}
|
|
413
416
|
|
|
414
417
|
const endLine = Math.min(currentLine + displayRows, lines.length)
|
|
415
418
|
linesRendered = 0
|