|
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) => { |
|
|
|
const input = context?.input ?? process.stdin; |
|
|
|
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) { |
|
|
|
setImmediate(() => { |
|
onExit(); |
|
|
|
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(); |
|
|
|
|
|
|
|
|
|
store.rl.input.on('keypress', checkCursorPos); |
|
}); |
|
}); |
|
answer.cancel = cancel; |
|
return answer; |
|
}; |
|
return prompt; |
|
} |
|
|