控制粗体字体渲染的终端模拟器设置

控制粗体字体渲染的终端模拟器设置

粗体字体(ANSI:)的效果CSI 1 m似乎取决于终端仿真器。例如,在不同的终端模拟器上运行以下脚本

#!/bin/sh
echo "TERM = $TERM"
for mode in 0 2 1 '1;2'; do
    printf '\033[%s;38;5;%dm\033[48;5;%dm%s\033[0m\n' "$mode" 0 15 "testing ($mode)"
done

给出以下输出

在此输入图像描述

在测试的终端模拟器中,仅xterm正确呈现粗体文本 (mode=1)。其他终端模拟器似乎为粗体字体选择了更亮的颜色(通常也将其与粗体字体组合)。奇怪的是,st当给定参数 时,会生成正确着色的粗体文本1;2,对应于bold;faint

我认为这些终端模拟器可能需要不同的粗体控制序列,我检查了terminfo,但发现一致

$ for term in xterm-256color st-256color rxvt-unicode-256color tmux-256color; do printf "%-24s" "$term"; TERM=$term tput bold | cat -v; echo; done
xterm-256color          ^[[1m
st-256color             ^[[1m
rxvt-unicode-256color   ^[[1m
tmux-256color           ^[[1m

这就引出了一个问题,哪些终端仿真器参数控制粗体字体的效果?如何防止向更亮的颜色转变?可以通过定制来解决这个问题Xresources吗? terminfo(顺便说一句, 是否有相应的参数vim?它显示了类似的行为,不一定与运行它的终端仿真器的行为相对应。)

答案1

CSI 1 m正如您所注意到的,只有一种转义序列会导致粗体字体。

正因为如此,没有真的一种可以从应用程序(例如vim)端更改行为的方法,甚至不需要通过诸如 terminfo 定义之类的配置。 (我将稍后完善此声明。)

实现所需行为的方法是相应地配置终端仿真器。您正在寻找xterm +pcurxvt +is,或其相应的 Xresource 设置,如其手册中所示。不知道st有没有这样的选择。

我真的不认为tmux有这样的选项,因为它无法控制图形模拟器的实际行为。从理论上讲,它可能会尝试我稍后会提到的技巧,但我真的不认为它会这样做。


给出一些历史背景:

按照标准,CSI 1 m意味着“大胆或者加大强度”,所以严格来说,这两种行为都是正确的。从历史上看,图形终端模拟器同时支持这两种功能。

这对于传统的 8/16 调色板来说有点意义。对于后来广泛使用的扩展 256 色调色板来说,情况就不是这样了,对于当今大多数图形终端仿真器都支持的 RGB 来说,情况也不是这样。非常糟糕的是,没有转义序列能够可靠地以粗体字体生成前 8 种调色板颜色(实际上是用户最喜欢的 8 种颜色)。

看到这一点,最近几个终端模拟器转向不使颜色变亮,只使字体更粗(您正在寻找的内容)。我认为您提到的任何终端都没有对默认设置进行此更改,但我对它们的了解可能很容易过时。


我提到过那里可能是改变应用程序行为的一种方式。

有两个转义序列可请求前 8 种调色板颜色之一:传统颜色 ( CSI 30..37 m) 和具有此类索引的 256 色颜色 ( CSI 38;5;0..7 m)。如果与粗体/明亮属性结合使用,某些终端仿真器的某些版本对于两者的行为可能会有所不同CSI 1 m。例如,如果我没记错的话,某些版本xterm仅在使用旧颜色转义时才会更改为更亮的颜色,但如果使用 256 色转义则不会。如果我没记错的话,xterm 后来改变了这种行为。

无论如何,如果您碰巧使用这样的终端模拟器,解决方法可能是setaf在 terminfo 中进行修改,以发出前 8 种颜色的 256 色序列,而不是旧代码。

这不会改变CSI 1 m默认前景色上粗体/明亮的行为,我绝对建议配置终端模拟器,而不是使用这个 terminfo hack。


如果您对更多有趣/毛茸茸的细节感兴趣,您可能会对这些链接以及从那里链接的其他页面感兴趣:
https://bugzilla.gnome.org/show_bug.cgi?id=762247
https://bugzilla.gnome.org/show_bug.cgi?id=791596

答案2

作为埃格蒙特 指出,可以通过运行xterm或 来抑制粗体明亮的行为。对于那些想知道的人urxvtxterm +pcurxvt +isst,其大胆如亮的行为是xdrawglyphfontspecs()xc,

/* Change basic system colors [0-7] to bright system colors [8-15] */
if ((base.mode & ATTR_BOLD_FAINT) == ATTR_BOLD && BETWEEN(base.fg, 0, 7))
    fg = &dc.col[base.fg + 8];

BETWEEN()顾名思义,哪里是

#define BETWEEN(x, a, b)    ((a) <= (x) && (x) <= (b))

该替换仅适用于传统 8/16 调色板的前 8 种颜色,这与埃格蒙特的言论一致。标题圣赫定义ATTR_BOLD_FAINT为 和 的按位ATTR_BOLD = 1<<0ATTR_FAINT = 1<<1。因此,仅当设置了粗体属性但未设置微弱属性时才会发生颜色重新映射。无论是有意还是无意,传递粗体 ( CSI 1 m) 和微弱 ( ) 属性的转义序列都会CSI 2 m通过不满足此条件来产生粗体字体,如问题所示。

原则上,可以利用粗体但不微弱的条件来获取粗体文本,方法是更改​​粗体属性的转义序列圣信息从其规范值 ( \E[1m) 到\E[1;2m,或者通过在设置粗体属性时设置微弱属性(通过case 1修改tsetattr()in不锈钢term.c.attr.mode |= (ATTR_BOLD | ATTR_FAINT))。尽管这些更改中的任何一个都会产生所需的结果(使用问题),两者都不推荐(出于多种原因)。

一种更直接(也是首选)的方法是简单地删除 中的粗体亮条件xdrawglyphfontspecs(),并且事实证明,已经有一个修补正是这样做的。

相关内容