UNPKG

2.34 kBJavaScriptView Raw
1'use strict';
2/**
3 * `editor` type prompt
4 */
5
6const chalk = require('chalk');
7const { editAsync } = require('external-editor');
8const Base = require('./base');
9const observe = require('../utils/events');
10const { Subject } = require('rxjs');
11
12class EditorPrompt extends Base {
13 /**
14 * Start the Inquiry session
15 * @param {Function} cb Callback when prompt is done
16 * @return {this}
17 */
18
19 _run(cb) {
20 this.done = cb;
21
22 this.editorResult = new Subject();
23
24 // Open Editor on "line" (Enter Key)
25 const events = observe(this.rl);
26 this.lineSubscription = events.line.subscribe(this.startExternalEditor.bind(this));
27
28 // Trigger Validation when editor closes
29 const validation = this.handleSubmitEvents(this.editorResult);
30 validation.success.forEach(this.onEnd.bind(this));
31 validation.error.forEach(this.onError.bind(this));
32
33 // Prevents default from being printed on screen (can look weird with multiple lines)
34 this.currentText = this.opt.default;
35 this.opt.default = null;
36
37 // Init
38 this.render();
39
40 return this;
41 }
42
43 /**
44 * Render the prompt to screen
45 * @return {EditorPrompt} self
46 */
47
48 render(error) {
49 let bottomContent = '';
50 let message = this.getQuestion();
51
52 if (this.status === 'answered') {
53 message += chalk.dim('Received');
54 } else {
55 message += chalk.dim('Press <enter> to launch your preferred editor.');
56 }
57
58 if (error) {
59 bottomContent = chalk.red('>> ') + error;
60 }
61
62 this.screen.render(message, bottomContent);
63 }
64
65 /**
66 * Launch $EDITOR on user press enter
67 */
68
69 startExternalEditor() {
70 // Pause Readline to prevent stdin and stdout from being modified while the editor is showing
71 this.rl.pause();
72 editAsync(this.currentText, this.endExternalEditor.bind(this));
73 }
74
75 endExternalEditor(error, result) {
76 this.rl.resume();
77 if (error) {
78 this.editorResult.error(error);
79 } else {
80 this.editorResult.next(result);
81 }
82 }
83
84 onEnd(state) {
85 this.editorResult.unsubscribe();
86 this.lineSubscription.unsubscribe();
87 this.answer = state.value;
88 this.status = 'answered';
89 // Re-render prompt
90 this.render();
91 this.screen.done();
92 this.done(this.answer);
93 }
94
95 onError(state) {
96 this.render(state.isValid);
97 }
98}
99
100module.exports = EditorPrompt;