Comparing version 2.3.0-beta.3 to 2.3.0-beta.4
{ | ||
"name": "run-pty", | ||
"version": "2.3.0-beta.3", | ||
"version": "2.3.0-beta.4", | ||
"author": "Simon Lydell", | ||
@@ -5,0 +5,0 @@ "license": "MIT", |
167
run-pty.js
@@ -69,2 +69,5 @@ #!/usr/bin/env node | ||
const SHOW_CURSOR = "\x1B[?25h"; | ||
const CURSOR_UP = "\x1B[A"; | ||
const CURSOR_DOWN = "\x1B[B"; | ||
const ENABLE_ALTERNATE_SCREEN = "\x1B[?1049h"; | ||
const DISABLE_ALTERNATE_SCREEN = "\x1B[?1049l"; | ||
@@ -301,3 +304,2 @@ const DISABLE_BRACKETED_PASTE_MODE = "\x1B[?2004l"; | ||
// Newlines at the end are wanted here. | ||
return ` | ||
@@ -340,25 +342,16 @@ ${finalLines} | ||
const runningText = (pid) => | ||
// Newlines at the start/end are wanted here. | ||
` | ||
${shortcut(KEYS.kill)} kill ${dim(`(pid ${pid})`)} | ||
${shortcut(KEYS.dashboard)} dashboard | ||
`.trimEnd(); | ||
`; | ||
/** | ||
* @param {CommandText} command | ||
* @param {number} pid | ||
* @returns {string} | ||
*/ | ||
const killingText = (command, pid) => | ||
// Newlines at the start/end are wanted here. | ||
const killingText = (pid) => | ||
` | ||
${killingIndicator}${EMOJI_WIDTH_FIX} ${ | ||
command.formattedCommandWithTitle | ||
}${RESET_COLOR} | ||
${cwdText(command)}killing… | ||
${shortcut(KEYS.kill)} kill ${dim(`(double-press to force) (pid ${pid})`)} | ||
${shortcut(KEYS.dashboard)} dashboard | ||
`; | ||
`.trimEnd(); | ||
@@ -372,3 +365,2 @@ /** | ||
const exitText = (commands, command, exitCode) => | ||
// Newlines at the start/end are wanted here. | ||
` | ||
@@ -383,3 +375,3 @@ ${exitIndicator(exitCode)}${EMOJI_WIDTH_FIX} ${ | ||
${shortcut(KEYS.dashboard)} dashboard | ||
`; | ||
`.trimEnd(); | ||
@@ -442,2 +434,23 @@ /** | ||
/** | ||
* @param {string} string | ||
* @returns {string} | ||
*/ | ||
const moveBack = (string) => | ||
`${CURSOR_UP.repeat(string.split("\n").length - 1)}\r`; | ||
/** | ||
* Assumes that `moveBack` has been run first and that the first line shouldn’t | ||
* be cleared. | ||
* | ||
* @param {string} string | ||
* @returns {string} | ||
*/ | ||
const erase = (string) => { | ||
const numLines = string.split("\n").length; | ||
return `\r${`${CURSOR_DOWN}${CLEAR_RIGHT}`.repeat( | ||
numLines - 1 | ||
)}${CURSOR_UP.repeat(numLines - 1)}`; | ||
}; | ||
/** | ||
* @param {Array<string>} command | ||
@@ -1009,47 +1022,73 @@ * @returns {string} | ||
let cursorIndex = undefined; | ||
/** @type {string | undefined} */ | ||
let lastExtraText = undefined; | ||
/** | ||
* @param {Command} command | ||
* @param {string} data | ||
* @returns {undefined} | ||
*/ | ||
const printHistoryAndExtraText = (command) => { | ||
process.stdout.write( | ||
SHOW_CURSOR + | ||
DISABLE_ALTERNATE_SCREEN + | ||
DISABLE_MOUSE + | ||
RESET_COLOR + | ||
CLEAR + | ||
command.history | ||
); | ||
const printExtraText = (command, data) => { | ||
const eraser = lastExtraText === undefined ? "" : erase(lastExtraText); | ||
const maybeNewline = EMPTY_LAST_LINE.test(command.history) ? "" : "\n"; | ||
switch (command.status.tag) { | ||
case "Running": | ||
if (command.history.endsWith("\n")) { | ||
process.stdout.write( | ||
RESET_COLOR + runningText(command.status.terminal.pid) | ||
); | ||
} | ||
lastExtraText = command.history.endsWith("\n") | ||
? RESET_COLOR + runningText(command.status.terminal.pid) | ||
: undefined; | ||
process.stdout.write( | ||
eraser + | ||
data + | ||
(lastExtraText === undefined | ||
? "" | ||
: lastExtraText + moveBack(lastExtraText)) | ||
); | ||
return undefined; | ||
case "Killing": | ||
if (command.status.slow) { | ||
process.stdout.write( | ||
HIDE_CURSOR + | ||
RESET_COLOR + | ||
maybeNewline + | ||
killingText(command, command.status.terminal.pid) | ||
); | ||
} | ||
return undefined; | ||
case "Killing": { | ||
const match = /\n((?:\^C)*)$/.exec(command.history); | ||
// Visually this line does not need reprinting, but we do to get the | ||
// cursor at the end of it. | ||
const lastLine = match === null ? "" : match[1]; | ||
case "Exit": | ||
lastExtraText = !/\n((?:\^C)*)$/.test(command.history) | ||
? undefined | ||
: command.status.slow | ||
? RESET_COLOR + killingText(command.status.terminal.pid) | ||
: RESET_COLOR + runningText(command.status.terminal.pid); | ||
process.stdout.write( | ||
HIDE_CURSOR + | ||
RESET_COLOR + | ||
maybeNewline + | ||
exitText(commands, command, command.status.exitCode) | ||
eraser + | ||
data + | ||
(lastExtraText === undefined | ||
? "" | ||
: lastExtraText + moveBack(lastExtraText) + lastLine) | ||
); | ||
return undefined; | ||
} | ||
case "Exit": { | ||
const isOnAlternateScreen = | ||
command.history.lastIndexOf(ENABLE_ALTERNATE_SCREEN) > | ||
command.history.lastIndexOf(DISABLE_ALTERNATE_SCREEN); | ||
const maybeNewline = | ||
!isOnAlternateScreen && EMPTY_LAST_LINE.test(command.history) | ||
? "" | ||
: "\n"; | ||
// This has the side effect of moving the cursor, so only do it if needed. | ||
const disableAlternateScreen = isOnAlternateScreen | ||
? DISABLE_ALTERNATE_SCREEN | ||
: ""; | ||
lastExtraText = | ||
HIDE_CURSOR + | ||
RESET_COLOR + | ||
disableAlternateScreen + | ||
maybeNewline + | ||
exitText(commands, command, command.status.exitCode); | ||
process.stdout.write(eraser + data + lastExtraText); | ||
return undefined; | ||
} | ||
} | ||
@@ -1088,3 +1127,14 @@ }; | ||
} | ||
printHistoryAndExtraText(command); | ||
process.stdout.write( | ||
SHOW_CURSOR + | ||
DISABLE_ALTERNATE_SCREEN + | ||
DISABLE_MOUSE + | ||
RESET_COLOR + | ||
CLEAR | ||
); | ||
lastExtraText = undefined; | ||
printExtraText(command, command.history); | ||
}; | ||
@@ -1138,10 +1188,5 @@ | ||
case "Running": | ||
process.stdout.write(data); | ||
return undefined; | ||
case "Killing": | ||
// Redraw with killingText at the bottom. | ||
printHistoryAndExtraText(command); | ||
printExtraText(command, data); | ||
return undefined; | ||
case "Exit": | ||
@@ -1177,4 +1222,3 @@ throw new Error( | ||
const command = commands[index]; | ||
// Redraw current command. | ||
printHistoryAndExtraText(command); | ||
printExtraText(command, ""); | ||
} | ||
@@ -1219,4 +1263,3 @@ return undefined; | ||
setCursor, | ||
killAll, | ||
printHistoryAndExtraText | ||
killAll | ||
); | ||
@@ -1269,3 +1312,2 @@ }); | ||
* @param {() => void} killAll | ||
* @param {(command: Command) => void} printHistoryAndExtraText | ||
* @returns {undefined} | ||
@@ -1281,4 +1323,3 @@ */ | ||
setCursor, | ||
killAll, | ||
printHistoryAndExtraText | ||
killAll | ||
) => { | ||
@@ -1301,2 +1342,6 @@ switch (current.tag) { | ||
default: | ||
command.status = { | ||
tag: "Running", | ||
terminal: command.status.terminal, | ||
}; | ||
command.status.terminal.write(data); | ||
@@ -1318,3 +1363,3 @@ return undefined; | ||
command.start({ isFocused: true }); | ||
printHistoryAndExtraText(command); | ||
switchToCommand(current.index); | ||
return undefined; | ||
@@ -1321,0 +1366,0 @@ |
52251
1343