基于ANSI转义序列来构建命令行工具

栏目: JavaScript · 发布时间: 6年前

内容简介:命令行工具在输出时,如果是简单的进度更新,可以使用已有不少成熟的命令行工具库,如

命令行 工具 在输出时,如果是简单的进度更新,可以使用 \r\b 来达成刷新行的效果,但如果要更复杂些的如字体颜色、背景颜色、光标位置移动等功能,那就需要使用 ANSI 转移序列了。

已有不少成熟的命令行工具库,如 ReadlineJLinePython Prompt Toolkit ,基于这些库创造了如 mycliipython 等好用的工具。

ANSI 转义序列 有比较悠久的历史,不同平台支持的功能不完全一致,这里学习到的是比较简单常用的,包括字体颜色、背景色和其它装饰的富文本和光标操作。

\u001b 即 ESC 的 ASCII 码, \u001b[0m 是清除之前的设定。

适用于 *nix 的系统。

富文本

前景色

8 色

\u001b[?m ,其中 ? ∈ [30, 37]

\u001b[30m
\u001b[31m
\u001b[32m
\u001b[33m
\u001b[34m
\u001b[35m
\u001b[36m
\u001b[37m
\u001b[0m

16 色

在 8 色的基础上对字体加粗,颜色加亮,得到另外 8 种,加起来就是 16 色。

\u001b[?;1m ,其中 ? ∈ [30, 37]

\u001b[30;1m
\u001b[31;1m
\u001b[32;1m
\u001b[33;1m
\u001b[34;1m
\u001b[35;1m
\u001b[36;1m
\u001b[37;1m
const out = process.stdout;

function colors8(pre, post, startCode = 30) {
  const codePointA = 'A'.codePointAt(0);

  let i = 0;
  while (i < 8) {
    const colorCode = startCode + i;
    const char = String.fromCodePoint(codePointA + i);
    out.write(`${pre}${colorCode}${post}${char} `);
    i++;
  }
  console.log('\u001b[0m');
}

function fgColors8() {
  colors8('\u001b[', 'm');
}

function fgColors8Bright() {
  colors8('\u001b[', ';1m');
}

fgColors8();
fgColors8Bright();

基于ANSI转义序列来构建命令行工具

256 色

\u001b[38;5;?m ,其中 ? ∈ [0, 255]

function colors256(pre, post) {
  let i = 0;
  while (i < 16) {
    let j = 0;
    while (j < 16) {
      const colorCode = i * 16 + j;
      const text = `${colorCode}`.padEnd(4);
      out.write(`${pre}${colorCode}${post}${text}`);
      j++;
    }
    console.log('\u001b[0m');
    i++;
  }
}

function fgColors256() {
  colors256('\u001b[38;5;', 'm');
}

fgColors256();

基于ANSI转义序列来构建命令行工具

背景色

背景色和前景色的方案一致,只是 code 不同而已。

8 色

\u001b[?m ,其中 ? ∈ [40, 47]

\u001b[40m
\u001b[41m
\u001b[42m
\u001b[43m
\u001b[44m
\u001b[45m
\u001b[46m
\u001b[47m

16 色

\u001b[?;1m ,其中 ? ∈ [40, 47]

\u001b[40;1m
\u001b[41;1m
\u001b[42;1m
\u001b[43;1m
\u001b[44;1m
\u001b[45;1m
\u001b[46;1m
\u001b[47;1m
function bgColors8() {
  colors8('\u001b[', 'm', 40);
}

function bgColors8Bright() {
  colors8('\u001b[', ';1m', 40);
}

bgColors8();
bgColors8Bright();

基于ANSI转义序列来构建命令行工具

256 色

\u001b[48;5;?m ,其中 ? ∈ [0, 255]

function bgColors256() {
  colors256('\u001b[48;5;', 'm');
}

bgColors256();

基于ANSI转义序列来构建命令行工具

装饰

\u001b[1m
\u001b[2m
\u001b[3m
\u001b[4m
\u001b[7m

可以单独使用,也可以组合使用(如 \u001b[1m\u001b[4m\u001b[7m 表示加粗、下划线和反色)。

还可以和颜色结合一起使用,如 \u001b[1m\u001b[4m\u001b[44m\u001b[31m Blue Background Red Color Bold Underline

function decorations() {
  const codes = [
    [1, 'High'],
    [2, 'Low'],
    [3, 'Italic'],
    [4, 'Underline'],
    [7, 'Reverse']
  ];

  for (let c of codes) {
    out.write(`\u001b[${c[0]}m${c[1]} \u001b[0m`);
  }
  console.log();
  console.log('\u001b[1m\u001b[4m\u001b[44m\u001b[31mBlue Background Red Color Bold Underline\u001b[0m');
}

decorations();

基于ANSI转义序列来构建命令行工具

光标操作

  • 上: \u001b[{n}A ,光标上移 n
  • 下: \u001b[{n}B ,光标下移 n
  • 右: \u001b[{n}C ,光标右移 n 个位置
  • 左: \u001b[{n}D ,光标左移 n 个位置
  • 下几行行首: \u001b[{n}E
  • 上几行行首: \u001b[{n}F
  • 指定列: \u001b[{n}G
  • 指定位置: \u001b[{n};{m}H ,移动光标到 nm
  • 清屏: \u001b[{n}J
    n=0
    n=1
    n=2
    
  • 清行: \u001b[{n}K
    n=0
    n=1
    n=2
    
function sleep(ms) {
  return new Promise(resolve => {
    setTimeout(resolve, ms);
  });
}

async function progressIndicator() {
  console.log('Loading...');
  let i = 0;
  while(i <= 100) {
    await sleep(10);
    out.write(`\u001b[1000D${i}%`);
    i++;
  }
  // 清除进度信息(上两行)然后输出 Done!
  console.log('\u001b[2F\u001b[0JDone!');
}

(async () => {
  await progressIndicator();
})();

基于ANSI转义序列来构建命令行工具

async function progressBars(count = 1) {
  const list = [];
  let i = 0;
  while (i++ < count) {
    list[i] = 0;
  }

  // 占位提供空间
  out.write(list.map(i => '').join('\n'));

  while(list.some(i => i< 100)) {
    await sleep(10);

    const unfinished = list.reduce((p, c, i) => {
      if (c < 100) p.push(i);
      return p;
    }, []);
    const randomIndex = unfinished[Math.floor(Math.random() * unfinished.length)];
    list[randomIndex] += 1;

    out.write('\u001b[1000D');
    out.write('\u001b[' + count + 'A');
    list.forEach(p => {
      const width = Math.floor(p / 4);
      console.log('[' + '#'.repeat(width) + ' '.repeat(25-width) + ']');
    });
  }

  console.log(`\u001b[1000D\u001b[${count}A\u001b[0JDone!`);
}

(async () => {
  console.log('Single progress');
  await progressBars();

  console.log();
  console.log('Multiple progress');
  await progressBars(4);
})();

基于ANSI转义序列来构建命令行工具

参考


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

VISUAL BASIC 6.0 WINDOWS API讲座

VISUAL BASIC 6.0 WINDOWS API讲座

王国荣 / 人民邮电出版社 / 1999-06-01 / 76.00元

本书全面介绍了在Visual Basic 6.0中如何调用Windows API的技术,特别是结合读者在应用中经常遇到的具体问题编写了许多应用范例,书中还给出了API函数的速查表。本书主要内容包括: Windows API的基本概念和调用方法,资源文件的使用,Windows的消息系统及其应用,API在绘图中的应用,多媒体文件的播放,特殊命令按钮的制作等。 本书适用于已熟悉Visual Basic的一起来看看 《VISUAL BASIC 6.0 WINDOWS API讲座》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具