我正在从头开始编写自己的 shell(
shark
- shell of ark)。 Ark 只是我名字的缩写。
大多数事情都运转良好,例如箭头/历史记录/命令执行,使用 VTIME 和 VMIN 输入缓冲区超时来处理 ascii esc 序列。
大多数时候我使用一个简单的硬编码提示,只是为了有一个,但带有颜色:
&tty.stdout.write(b"\x1b[1;32m[ shark ]\x1b[0m $");
这效果很好,但我想从 rc 文件中获取我的环境,
.sharkrc
。
在这个文件中我有简单的代码:
PS1='\x1b[1;32m[ shark ]\x1b[0m $ '
在 shell 开始时,读取并解析 rc 文件,然后提示符如下所示:
\x1b[1;32m[ shark ]\x1b[0m $
没有颜色,我知道问题实际上是什么:它是一个纯字符串,并且将打印为字符串,即使它是:
prompt.as_bytes()
,
没有
\x1b[..
序列,只有字符 \
然后 x
然后 1
然后 b
等等。
但问题是,我想从头开始执行此操作,因此我需要一些帮助,以在字符串来自文件时处理 ansi esc 代码。
我的最后一个想法是使用正则表达式并从字符串中查找所有 ansi 代码,然后单独编写。
但是有没有更简单的方法呢?
我自己解决了,代码还是有点乱,但是是通过尝试和错误。现在它可以工作了,我知道如何处理 ANSI EscCodes。
这里是代码:
pub fn parse_from_str( text: &str, tty: &Terminal ) {
let mut ansi_code = false;
let mut ansi_blk : Vec<char> = Vec::new();
let mut non_ansi_blk : Vec<char> = Vec::new();
let ansi_scan : [char; 4 ] = [ '\\', 'x', 'b', 'm' ];
for (index, byte) in text.chars().enumerate() {
if byte == '\\' {
ansi_code = true;
//println!("\rfound \\");
if !non_ansi_blk.is_empty() {
write!(&tty.stdout, "{}", non_ansi_blk.iter().collect::<String>());
non_ansi_blk.clear();
}
} else if ansi_code == true && !ansi_scan.contains(&byte) {
if text.as_bytes()[index - 1] == b'x' { continue; }
//println!("\rPush ANSI: {}", byte);
ansi_blk.push(byte);
} else if ansi_code == true && byte == 'm' {
ansi_code = false;
write!(&tty.stdout, "\x1b{}m", ansi_blk.iter().collect::<String>());
ansi_blk.clear();
} else if ansi_code == false {
//println!("\rPush non ANSI: {}", byte);
non_ansi_blk.push(byte);
}
}
if !non_ansi_blk.is_empty() {
write!(&tty.stdout, "{}", non_ansi_blk.iter().collect::<String>());
non_ansi_blk.clear();
}
}