term alternate screen - hanyong/note GitHub Wiki
TERM alternate screen
date: 2015-12-09
less 可以控制是否使用 alternate-screen, 我们希望 tmux 不要使用 alternate-screen, 其他绝大多数场景使用 alternate-screen 都是没有问题的.
sudo apt-get source less
把 less 的源码拉下来,
尝试分析 less 如何控制是否使用 alternate-screen.
# man less
-X or --no-init
Disables sending the termcap initialization and deinitialization strings to the terminal. This is sometimes
desirable if the deinitialization string does something unnecessary, like clearing the screen.
# vim opttbl.c
public int no_init; /* Disable sending ti/te termcap strings */
# man 5 termcap
te End program that uses cursor motion
ti Begin program that uses cursor motion
// screen.c
/*
* Initialize terminal
*/
public void
init()
{
#if !MSDOS_COMPILER
if (!no_init)
tputs(sc_init, sc_height, putchr);
if (!no_keypad)
tputs(sc_s_keypad, sc_height, putchr);
if (top_scroll)
{
int i;
/*
* This is nice to terminals with no alternate screen,
* but with saved scrolled-off-the-top lines. This way,
* no previous line is lost, but we start with a whole
* screen to ourself.
*/
for (i = 1; i < sc_height; i++)
putchr('\n');
} else
line_left();
#else
#if MSDOS_COMPILER==WIN32C
if (!no_init)
win32_init_term();
#endif
initcolor();
flush();
#endif
init_done = 1;
}
/*
* Deinitialize terminal
*/
public void
deinit()
{
if (!init_done)
return;
#if !MSDOS_COMPILER
if (!no_keypad)
tputs(sc_e_keypad, sc_height, putchr);
if (!no_init)
tputs(sc_deinit, sc_height, putchr);
#else
/* Restore system colors. */
SETCOLORS(sy_fg_color, sy_bg_color);
#if MSDOS_COMPILER==WIN32C
if (!no_init)
win32_deinit_term();
#else
/* Need clreol to make SETCOLORS take effect. */
clreol();
#endif
#endif
init_done = 0;
}
sc_init
, sc_deinit
是什么呢? 再从源码中找到:
sc_init = ltgetstr("ti", &sp);
if (sc_init == NULL)
sc_init = "";
sc_deinit= ltgetstr("te", &sp);
if (sc_deinit == NULL)
sc_deinit = "";
less 的源码中没找到 tputs()
的源码, 猜想应该是 ncurses 的一个函数,
apt-get build-dep less
安装 less 编译依赖, 果然看到安装了 libncurses5-dev
.
确认 tputs()
是在 ncurses 的头文件中定义的:
$ grep -F -e 'tputs' $(dpkg -L libncurses5-dev | grep -F '.h')
... ...
/usr/include/term.h:extern NCURSES_EXPORT(int) tputs (const char *, int, int (*)(int));
/usr/include/term.h:extern NCURSES_EXPORT(int) NCURSES_SP_NAME(tputs) (SCREEN*, const char *, int, NCURSES_SP_OUTC);
奇怪的是 ltgetstr 在系统所有头文件中都没找到, 原来这是 less 基于 tgetstr 包装的一个函数,
而 tgetstr 也在 term.h
头文件中定义.
apt-get install ncurses-doc
安装 ncurses 文档后, 即可通过 man tputs
查看相关函数的说明文档.
找到这两个根源函数, 尝试分析 tmux 的代码. 很遗憾, tmux 源码中没发现使用这两个函数的地方. 可能是被其他更高层次的函数包装了(?).
ncurses 接口封装默认就会使用 alternate-screen, 除非应用刻意使用了 python2 -c 'import sys, time, curses; curses.initscr() ; range(5); print "hello\r\n", ; sys.stdout.flush(); time.sleep(3); curses.endwin()'
vim -c 'tab help t_ti'
t_te out of "termcap" mode *t_te* *'t_te'*
t_ti put terminal in "termcap" mode *t_ti* *'t_ti'*
不修改应用, 可以重新编译 terminfo 去掉 smcup, rmcup:
( x=xterm f=$(mktemp tmp_termXXXX.src) && infocmp -l $x | sed -r -e 's#^'$x'\|#'$x'-noalt|#' -e 's#[rs]mcup=[^,]*, ?##' > $f && test -n "$(cat $f)" && tic $f && rm $f && echo success)
sudo rsync -av .terminfo/ /usr/share/terminfo/
最后发现 tmux 可通过一个设置修改 smcup, rmcup, 参考 Use terminal scrollbar with tmux
set -ga terminal-overrides ',xterm*:smcup=:rmcup='
控制台控制序列文档可参考 man console_codes
,
完整 xterm 控制序列文档可参考 XTerm Control Sequences.
其他相关讨论和文档:
Exorcising the Evil Alternate Screen
http://www.shallowsky.com/linux/noaltscreen.html
Stop gnome-terminal screen clear
http://fixlog.blogspot.com/2006/09/stop-gnome-terminal-screen-clear.html
Why doesn't the screen clear when running vi?
http://invisible-island.net/xterm/xterm.faq.html#xterm_tite
The alternate screen terminal emulator plague
https://utcc.utoronto.ca/~cks/space/blog/unix/AlternateScreenPlague