[6a3a178] | 1 | 'use strict';
|
---|
| 2 | /**
|
---|
| 3 | * `editor` type prompt
|
---|
| 4 | */
|
---|
| 5 |
|
---|
| 6 | const chalk = require('chalk');
|
---|
| 7 | const { editAsync } = require('external-editor');
|
---|
| 8 | const Base = require('./base');
|
---|
| 9 | const observe = require('../utils/events');
|
---|
| 10 | const { Subject } = require('rxjs');
|
---|
| 11 |
|
---|
| 12 | class 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 |
|
---|
| 100 | module.exports = EditorPrompt;
|
---|