text.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. "use strict";
  2. function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
  3. function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
  4. const color = require('kleur');
  5. const Prompt = require('./prompt');
  6. const _require = require('sisteransi'),
  7. erase = _require.erase,
  8. cursor = _require.cursor;
  9. const _require2 = require('../util'),
  10. style = _require2.style,
  11. clear = _require2.clear,
  12. lines = _require2.lines,
  13. figures = _require2.figures;
  14. /**
  15. * TextPrompt Base Element
  16. * @param {Object} opts Options
  17. * @param {String} opts.message Message
  18. * @param {String} [opts.style='default'] Render style
  19. * @param {String} [opts.initial] Default value
  20. * @param {Function} [opts.validate] Validate function
  21. * @param {Stream} [opts.stdin] The Readable stream to listen to
  22. * @param {Stream} [opts.stdout] The Writable stream to write readline data to
  23. * @param {String} [opts.error] The invalid error label
  24. */
  25. class TextPrompt extends Prompt {
  26. constructor(opts = {}) {
  27. super(opts);
  28. this.transform = style.render(opts.style);
  29. this.scale = this.transform.scale;
  30. this.msg = opts.message;
  31. this.initial = opts.initial || ``;
  32. this.validator = opts.validate || (() => true);
  33. this.value = ``;
  34. this.errorMsg = opts.error || `Please Enter A Valid Value`;
  35. this.cursor = Number(!!this.initial);
  36. this.clear = clear(``, this.out.columns);
  37. this.render();
  38. }
  39. set value(v) {
  40. if (!v && this.initial) {
  41. this.placeholder = true;
  42. this.rendered = color.gray(this.transform.render(this.initial));
  43. } else {
  44. this.placeholder = false;
  45. this.rendered = this.transform.render(v);
  46. }
  47. this._value = v;
  48. this.fire();
  49. }
  50. get value() {
  51. return this._value;
  52. }
  53. reset() {
  54. this.value = ``;
  55. this.cursor = Number(!!this.initial);
  56. this.fire();
  57. this.render();
  58. }
  59. exit() {
  60. this.abort();
  61. }
  62. abort() {
  63. this.value = this.value || this.initial;
  64. this.done = this.aborted = true;
  65. this.error = false;
  66. this.red = false;
  67. this.fire();
  68. this.render();
  69. this.out.write('\n');
  70. this.close();
  71. }
  72. validate() {
  73. var _this = this;
  74. return _asyncToGenerator(function* () {
  75. let valid = yield _this.validator(_this.value);
  76. if (typeof valid === `string`) {
  77. _this.errorMsg = valid;
  78. valid = false;
  79. }
  80. _this.error = !valid;
  81. })();
  82. }
  83. submit() {
  84. var _this2 = this;
  85. return _asyncToGenerator(function* () {
  86. _this2.value = _this2.value || _this2.initial;
  87. yield _this2.validate();
  88. if (_this2.error) {
  89. _this2.red = true;
  90. _this2.fire();
  91. _this2.render();
  92. return;
  93. }
  94. _this2.done = true;
  95. _this2.aborted = false;
  96. _this2.fire();
  97. _this2.render();
  98. _this2.out.write('\n');
  99. _this2.close();
  100. })();
  101. }
  102. next() {
  103. if (!this.placeholder) return this.bell();
  104. this.value = this.initial;
  105. this.cursor = this.rendered.length;
  106. this.fire();
  107. this.render();
  108. }
  109. moveCursor(n) {
  110. if (this.placeholder) return;
  111. this.cursor = this.cursor + n;
  112. }
  113. _(c, key) {
  114. let s1 = this.value.slice(0, this.cursor);
  115. let s2 = this.value.slice(this.cursor);
  116. this.value = `${s1}${c}${s2}`;
  117. this.red = false;
  118. this.cursor = this.placeholder ? 0 : s1.length + 1;
  119. this.render();
  120. }
  121. delete() {
  122. if (this.cursor === 0) return this.bell();
  123. let s1 = this.value.slice(0, this.cursor - 1);
  124. let s2 = this.value.slice(this.cursor);
  125. this.value = `${s1}${s2}`;
  126. this.red = false;
  127. this.moveCursor(-1);
  128. this.render();
  129. }
  130. deleteForward() {
  131. if (this.cursor * this.scale >= this.rendered.length || this.placeholder) return this.bell();
  132. let s1 = this.value.slice(0, this.cursor);
  133. let s2 = this.value.slice(this.cursor + 1);
  134. this.value = `${s1}${s2}`;
  135. this.red = false;
  136. this.render();
  137. }
  138. first() {
  139. this.cursor = 0;
  140. this.render();
  141. }
  142. last() {
  143. this.cursor = this.value.length;
  144. this.render();
  145. }
  146. left() {
  147. if (this.cursor <= 0 || this.placeholder) return this.bell();
  148. this.moveCursor(-1);
  149. this.render();
  150. }
  151. right() {
  152. if (this.cursor * this.scale >= this.rendered.length || this.placeholder) return this.bell();
  153. this.moveCursor(1);
  154. this.render();
  155. }
  156. render() {
  157. if (this.closed) return;
  158. if (!this.firstRender) {
  159. if (this.outputError) this.out.write(cursor.down(lines(this.outputError, this.out.columns) - 1) + clear(this.outputError, this.out.columns));
  160. this.out.write(clear(this.outputText, this.out.columns));
  161. }
  162. super.render();
  163. this.outputError = '';
  164. this.outputText = [style.symbol(this.done, this.aborted), color.bold(this.msg), style.delimiter(this.done), this.red ? color.red(this.rendered) : this.rendered].join(` `);
  165. if (this.error) {
  166. this.outputError += this.errorMsg.split(`\n`).reduce((a, l, i) => a + `\n${i ? ' ' : figures.pointerSmall} ${color.red().italic(l)}`, ``);
  167. }
  168. this.out.write(erase.line + cursor.to(0) + this.outputText + cursor.save + this.outputError + cursor.restore);
  169. }
  170. }
  171. module.exports = TextPrompt;