index.js 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. import { editAsync } from 'external-editor';
  2. import { createPrompt, useEffect, useState, useKeypress, usePrefix, isEnterKey, makeTheme, } from '@inquirer/core';
  3. const editorTheme = {
  4. validationFailureMode: 'keep',
  5. };
  6. export default createPrompt((config, done) => {
  7. const { waitForUseInput = true, file: { postfix = config.postfix ?? '.txt', ...fileProps } = {}, validate = () => true, } = config;
  8. const theme = makeTheme(editorTheme, config.theme);
  9. const [status, setStatus] = useState('idle');
  10. const [value = '', setValue] = useState(config.default);
  11. const [errorMsg, setError] = useState();
  12. const prefix = usePrefix({ status, theme });
  13. function startEditor(rl) {
  14. rl.pause();
  15. const editCallback = async (error, answer) => {
  16. rl.resume();
  17. if (error) {
  18. setError(error.toString());
  19. }
  20. else {
  21. setStatus('loading');
  22. const isValid = await validate(answer);
  23. if (isValid === true) {
  24. setError(undefined);
  25. setStatus('done');
  26. done(answer);
  27. }
  28. else {
  29. if (theme.validationFailureMode === 'clear') {
  30. setValue(config.default);
  31. }
  32. else {
  33. setValue(answer);
  34. }
  35. setError(isValid || 'You must provide a valid value');
  36. setStatus('idle');
  37. }
  38. }
  39. };
  40. editAsync(value, (error, answer) => void editCallback(error, answer), {
  41. postfix,
  42. ...fileProps,
  43. });
  44. }
  45. useEffect((rl) => {
  46. if (!waitForUseInput) {
  47. startEditor(rl);
  48. }
  49. }, []);
  50. useKeypress((key, rl) => {
  51. // Ignore keypress while our prompt is doing other processing.
  52. if (status !== 'idle') {
  53. return;
  54. }
  55. if (isEnterKey(key)) {
  56. startEditor(rl);
  57. }
  58. });
  59. const message = theme.style.message(config.message, status);
  60. let helpTip = '';
  61. if (status === 'loading') {
  62. helpTip = theme.style.help('Received');
  63. }
  64. else if (status === 'idle') {
  65. const enterKey = theme.style.key('enter');
  66. helpTip = theme.style.help(`Press ${enterKey} to launch your preferred editor.`);
  67. }
  68. let error = '';
  69. if (errorMsg) {
  70. error = theme.style.error(errorMsg);
  71. }
  72. return [[prefix, message, helpTip].filter(Boolean).join(' '), error];
  73. });