bottom-bar.js 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. /**
  2. * Sticky bottom bar user interface
  3. */
  4. import through from 'through';
  5. import Base from './baseUI.js';
  6. import * as rlUtils from '../utils/readline.js';
  7. export default class BottomBar extends Base {
  8. constructor(opt = {}) {
  9. super(opt);
  10. this.log = through(this.writeLog.bind(this));
  11. this.bottomBar = opt.bottomBar || '';
  12. this.render();
  13. }
  14. /**
  15. * Render the prompt to screen
  16. * @return {BottomBar} self
  17. */
  18. render() {
  19. this.write(this.bottomBar);
  20. return this;
  21. }
  22. clean() {
  23. rlUtils.clearLine(this.rl, this.bottomBar.split('\n').length);
  24. return this;
  25. }
  26. /**
  27. * Update the bottom bar content and rerender
  28. * @param {String} bottomBar Bottom bar content
  29. * @return {BottomBar} self
  30. */
  31. updateBottomBar(bottomBar) {
  32. rlUtils.clearLine(this.rl, 1);
  33. this.rl.output.unmute();
  34. this.clean();
  35. this.bottomBar = bottomBar;
  36. this.render();
  37. this.rl.output.mute();
  38. return this;
  39. }
  40. /**
  41. * Write out log data
  42. * @param {String} data - The log data to be output
  43. * @return {BottomBar} self
  44. */
  45. writeLog(data) {
  46. this.rl.output.unmute();
  47. this.clean();
  48. this.rl.output.write(this.enforceLF(data.toString()));
  49. this.render();
  50. this.rl.output.mute();
  51. return this;
  52. }
  53. /**
  54. * Make sure line end on a line feed
  55. * @param {String} str Input string
  56. * @return {String} The input string with a final line feed
  57. */
  58. enforceLF(str) {
  59. return str.match(/[\r\n]$/) ? str : str + '\n';
  60. }
  61. /**
  62. * Helper for writing message in Prompt
  63. * @param {String} message - The message to be output
  64. */
  65. write(message) {
  66. const msgLines = message.split(/\n/);
  67. this.height = msgLines.length;
  68. // Write message to screen and setPrompt to control backspace
  69. this.rl.setPrompt(msgLines[msgLines.length - 1]);
  70. if (this.rl.output.rows === 0 && this.rl.output.columns === 0) {
  71. /* When it's a tty through serial port there's no terminal info and the render will malfunction,
  72. so we need enforce the cursor to locate to the leftmost position for rendering. */
  73. rlUtils.left(this.rl, message.length + this.rl.line.length);
  74. }
  75. this.rl.output.write(message);
  76. }
  77. }