经过测试(我的环境上),矮人要塞的菜单界面在不同模式/环境下的显示情况有所不同:
环境 | 模式 | 效果 |
---|---|---|
st | TEXT | NG |
st & tmux | TEXT | NG |
kitty | TEXT | NG |
kitty & tmux | TEXT | NG |
xterm | TEXT | GOOD |
xterm & tmux | TEXT | GOOD |
tty | TEXT | GOOD |
tty & tmux | TEXT | GOOD |
/ | 2D | GOOD |
对比一下效果:
df的TEXT模式目测是用ncurses
库的,我将问题定位分为软件、配色、终端三个方向。当我在tty
和st
使用同一个tmux session时,tty
显示了GOOD的效果,但是在st下还是NG,这一现象很关键,基本可以排除软件问题。配色方向经过重新编译st验证也被排除了。
只剩一个方向,既然是显示在终端上,那程序必须要输出字符,这里有两种方式可以捕获到这些字符。
# tmux
tmux capture-pane -peJ -t {pane_id} > xxx.log
# 通用
script xxx.log
...
<Ctrl-D>
根据日志,可以发现基本都是使用esc控制字符来实现各种颜色的。下面给出问题的最小重现样例。
echo "^[[1m^[[30m^[[40mcontinue"
# PS: ^[需要使用<c-v> + <esc>键入
在公司摸鱼的时候就往这个方向去探索,最后发现了根因。这类^[
格式的字符是ANSI的转义字符,官方标准中,样例中的各字符功能如下:
字符 | 功能 |
---|---|
[1m | 加粗或增加前景强度 |
[30m | 设置前景色为黑色(0号颜色) |
[40m | 设置背景色为黑色(0号颜色) |
背景和前景色都用黑色,那当然应该是NG的效果,只有将前景色的颜色加深了,才能看到文本内容。所以st
和kitty
处理转义字符^[[1m
时是进行了加粗处理,其他使用了后者的处理。
下面给出patch。
diff --git a/st.c b/st.c
index 6fbf4e2..e53de0c 100644
--- a/st.c
+++ b/st.c
@@ -1413,7 +1413,7 @@ tsetattr(const int *attr, int l)
{
int i;
int32_t idx;
-
+ static char enhance = 0;
for (i = 0; i < l; i++) {
switch (attr[i]) {
case 0:
@@ -1428,9 +1428,14 @@ tsetattr(const int *attr, int l)
ATTR_STRUCK );
term.c.attr.fg = defaultfg;
term.c.attr.bg = defaultbg;
+ enhance = 0;
break;
case 1:
term.c.attr.mode |= ATTR_BOLD;
+ enhance = 1;
+ if (term.c.attr.fg < 8) {
+ term.c.attr.fg |= 8;
+ }
break;
case 2:
term.c.attr.mode |= ATTR_FAINT;
@@ -1492,7 +1497,7 @@ tsetattr(const int *attr, int l)
break;
default:
if (BETWEEN(attr[i], 30, 37)) {
- term.c.attr.fg = attr[i] - 30;
+ term.c.attr.fg = (attr[i] - 30) + (enhance * 8);
} else if (BETWEEN(attr[i], 40, 47)) {
term.c.attr.bg = attr[i] - 40;
} else if (BETWEEN(attr[i], 90, 97)) {