命令行交互原理
正在加载今日诗词....
2022-04-20

学习路径

  • 掌握:readline / events / stream / ansi-escapes / rxjs
  • 掌握命令行交互的实现原理,并实现一个可交互的列表
  • 分析 inquirer 源码掌握其中的关键实现

ANSI-escape-code查阅文档:https://handwiki.org/wiki/ANSI_escape_code

readline 源码分析

  • 强制将函数转换为构建函数
if (!(this instanceof Interface)) {
  return new Interface(input, output, completer, terminal);
}
  • 获得事件驱动能力
EventEmitter.call(this);
  • 监听键盘事件
emitKeypressEvents(input, this);

// `input` usually refers to stdin
input.on('keypress', onkeypress);
input.on('end', ontermend);

readline 核心实现原理:

图片描述

注:readline利用了Generator函数的特性,还不熟悉Generator函数的同学可以查看:https://es6.ruanyifeng.com/#docs/generator

手写简单版readline

function stepRead(callback) {
  const input = process.stdin;
  const output = process.stdout;
  let line = '';
  function onKeyPress(s) {
    output.write(s)
    line += s;
    switch (s) {
      case '\r':
        input.pause();
        callback(line);
        break;
    }
  }
  emitkeyPressEvents(input)
  input.on('keypress', onKeyPress)

  input.setRawMode(true)
  input.resume()
}



function emitkeyPressEvents(stream) {
  const onData = (chunk) => {
    g.next(chunk.toString())
  }
  const g = emitKeys(stream)
  g.next()

  stream.on('data', onData)
}

function* emitKeys(stream) {
  while(true) {
    let ch = yield
    stream.emit('keypress', ch)
  }
}

stepRead((s) => {
  console.log('answer: ' + s)
})

如何开发命令行交互列表

实现原理

图片描述

获取字符串的核心实现:

getContent = () => {
  if (!this.haveSelected) {
    let title = '\x1B[32m?\x1B[39m \x1B[1m' + this.message + '\x1B[22m\x1B[0m \x1B[0m\x1B[2m(Use arrow keys)\x1B[22m\n';
    this.choices.forEach((choice, index) => {
      if (index === this.selected) {
        if (index === this.choices.length - 1) {
          title += '\x1B[36m❯ ' + choice.name + '\x1B[39m ';
        } else {
          title += '\x1B[36m❯ ' + choice.name + '\x1B[39m \n';
        }
      } else {
        if (index === this.choices.length - 1) {
          title += `  ${choice.name} `;
        } else {
          title += `  ${choice.name} \n`;
        }
      }
    });
    this.height = this.choices.length + 1;
    return title;
  } else {
    const name = this.choices[this.selected].name;
    let title = '\x1B[32m?\x1B[39m \x1B[1m' + this.message + '\x1B[22m\x1B[0m \x1B[36m' + name + '\x1B[39m\x1B[0m \n';
    return title;
  }
};

架构图

图片描述

Copyright © 2022 @filway

  • ☀️
  • 🌑