Sylvain Filoni
update gradio client
9ada4bc
raw
history blame
3.73 kB
import * as readline from 'node:readline';
import { CancelablePromise } from '@inquirer/type';
import MuteStream from 'mute-stream';
import { onExit as onSignalExit } from 'signal-exit';
import ScreenManager from './screen-manager.mjs';
import { withHooks, effectScheduler } from './hook-engine.mjs';
import { CancelPromptError, ExitPromptError } from './errors.mjs';
export function createPrompt(view) {
const prompt = (config, context) => {
// Default `input` to stdin
const input = context?.input ?? process.stdin;
// Add mute capabilities to the output
const output = new MuteStream();
output.pipe(context?.output ?? process.stdout);
const rl = readline.createInterface({
terminal: true,
input,
output,
});
const screen = new ScreenManager(rl);
let cancel = () => { };
const answer = new CancelablePromise((resolve, reject) => {
withHooks(rl, (store) => {
function checkCursorPos() {
screen.checkCursorPos();
}
const removeExitListener = onSignalExit((code, signal) => {
onExit();
reject(new ExitPromptError(`User force closed the prompt with ${code} ${signal}`));
});
function onExit() {
try {
store.hooksCleanup.forEach((cleanFn) => {
cleanFn?.();
});
}
catch (error) {
reject(error);
}
if (context?.clearPromptOnDone) {
screen.clean();
}
else {
screen.clearContent();
}
screen.done();
removeExitListener();
store.rl.input.removeListener('keypress', checkCursorPos);
}
cancel = () => {
onExit();
reject(new CancelPromptError());
};
function done(value) {
// Delay execution to let time to the hookCleanup functions to registers.
setImmediate(() => {
onExit();
// Finally we resolve our promise
resolve(value);
});
}
function workLoop() {
store.index = 0;
try {
const nextView = view(config, done);
const [content, bottomContent] = typeof nextView === 'string' ? [nextView] : nextView;
screen.render(content, bottomContent);
effectScheduler.run();
}
catch (error) {
onExit();
reject(error);
}
}
store.handleChange = () => workLoop();
workLoop();
// Re-renders only happen when the state change; but the readline cursor could change position
// and that also requires a re-render (and a manual one because we mute the streams).
// We set the listener after the initial workLoop to avoid a double render if render triggered
// by a state change sets the cursor to the right position.
store.rl.input.on('keypress', checkCursorPos);
});
});
answer.cancel = cancel;
return answer;
};
return prompt;
}