其实这是个我很久以前就遇到的问题,但是对tmux功能基本上 没有影响,所以一直忍啊忍,现在我终于忍不下去了……
tmux只有8种颜色?
就像这样:
好吧这不是世界末日,但是也够悲剧了:现在是21世纪,我 的显示器能显示2^32种颜色,可是我眼前的竟然是这种东西?!
这破事发生在我的linode主机上,而且只发生在我用putty登录
的时候;在gnome-terminal下用ssh直接连的话tmux能以256色
模式运行,tput colors
返回256,vim看起来也没那么可怜:
外事不决问google
Google一下tmux+color,发现到处都有人在问“怎么我的tmux颜 颜色不对”,答案也不尽相同,但是基本都是这两种说法:
-
tmux认为你在用的终端模拟程序弱到不支持256色,可 以通过
tmux -2
强制其进入256色模式,或者在.tmux.conf
里加入set -g default-terminal "screen-256color"
; -
远程主机上的shell进程认为你的终端模拟程序弱到不支持 256色,所以没有设对相应的环境变量,这样除了tmux,其 他程序颜色也会不正常;在
.bashrc
或者.bash_profile
里面加上export TERM=xterm-256color
就可以了。
试了一下,发现解释1里的两种设置方法都没用——vim的颜色还 是不对——但是两种设置方法都用上的话,vim的颜色竟然就坑爹 地对了……
解释2里的方法则是效果拔群;很显然tmux和vim的颜色模式会 受TERM环境变量影响,只有在TERM变量声明终端支持256色的时 候,tmux和vim才会工作在256色模式下。
终端模拟程序、tmux、命令行程序的行为模式
所以,TERM这个环境变量可以理解为终端导出的一个接口,供 shell和其他在终端下执行的命令行程序查询终端的类型,从 而适配不同的终端。
tmux这种特殊的程序,本身需要作为终端,处理命令行程序 的输入输出,同时又要做为命令行程序,在真正的终端下执行; 如果终端是插座,命令行程序是插头,那tmux就是排插……或者 如果你想装一下,叫它中间件也行。
所以,tmux一方面会去读终端提供的TERM变量,另一方面又会
给它体内的命令行程序提供TERM变量。在没做任何设置的情况
下,tmux外TERM的值是xterm
,而tmux内的值则是screen
.
上面效果拔群的方法2其实是让shell无视所有终端(包括tmux)
的TERM设置,直接将终端类型声明强制为支持256色——想象一
下你的业务逻辑代码越过操作系统抽象层直接call了系统调
用stime
把系统时间改了,有够恶心的对吧……如果真的有个
终端是不支持256色的,其他命令行程序也不可能知道了。
对tmux和终端运用软件工程提供的方法
好吧因为我在装,所以我认为方法2可行但是不正确。正确的 做法是,尊重别人给你的接口,不要越过系统边界。问 题的症结其实是,我在用的所有终端(包括tmux)都支持256色, 但是却都谎称自己不支持,所以只要通过设置让它们自己别再 说谎就可以了。
我这用的终端模拟器是putty,"Connection" -> "Data" -> "Terminal-type string"
这里可以设置对外宣称的终端类型,默认是xterm
,改为
xterm-256color
;tmux则是在.tmux.confi里加上
set -g default-terminal "screen-256color"
,让tmux宣称
自己是支持256色的screen. 这下看起来(各种意义上)舒服
多了吧……
不过这样搞还有个悲剧的问题:tmux中的TERM变量永远是
screen-256color
,不会根据外面终端支持的颜色数
改变——虽然tmux本身还是会在8色和256色模式下自动转换。
也就是说,tmux的工作模式和它宣称自己是哪个终端类型没
有关系,在8色模式下工作时可以宣称自己是256色的,反之
在256色模式下工作时也可以宣称自己是8色的……
为什么tmux要将这两个东西分开?大概tmux的作者也是出于 无奈,因为“终端类型”包含的信息太多了,除了支持的颜色数, 还有对各种转义串的兼容性等也靠“终端类型”来标识;我上面 将TERM变量称为“接口”,而这个接口红果果地违反了“只做一 件事情”的指导原则,导致副作用太多,结果就是不能随便改。