终端里正确设置 ALT 键和 BS 键

不管你在终端下使用 vim/neovim, emacs, nano 或者 zsh,你都会碰到使用 ALT 键的情况(终端下叫做 meta键),而由于历史原因,大部分终端软件的默认设置都无法正确使用 ALT 键。

要在终端下正确使用 ALT键最简单的做法是:首先将终端软件的 “使用 Alt键作为 Meta键” 的功能打开,意思是如果你在终端下按下 ALT+X,那么终端软件将会发送 <ESC>x 两个字节过去,字节码为:0x27, 0x78。

SecureCRT:终端设置

XShell4 终端设置:

其他终端软件里:

  • Putty/MinTTY 默认ALT+X 就是发送 <ESC>x过去
  • Mac下面的 iTerm2/Terminal.app 需要跟 XShell / SecureCRT一样设置一下
  • Ubuntu 下面的 GnomeTerminal 默认也是发送 <ESC>x过去的
  • 任意平台下面的 xterm 可以配置 ~/.Xdefaults 来设置这个行为。

这样的话,终端里的软件就能识别你的 ALT 组合键了,设置好以后,你可以在终端下使用命令:

showkey -a

来查看自己的设置正确不,是不是按下 ALT_a 后正确发送了 0x1b, 0x61 两个字节过去了?

功能键超时

那么终端里按下 ALT_X 和先按 ESC 键再按 X键有什么区别呢?答案是没有区别,你在 emacs 中快速先后按下 ESC 和 v 的话,emacs 就会以为你按了 ALT_v,然后给你来个上翻页了。

远程主机一般靠超时来区别到底是 ALT_X 还是先按 ESC 再按 X 键,如果你 100 毫秒内先后发送了 ESC 和 X 过来,远程主机会识别成 ALT_X 键,否则识别成 ESC 和 X 两个键,这个超时时间可以设置,一般设置成 100ms 或者 50ms ,但不要低于 25ms,否则网络一卡可能有概率会判断错误。

在 Vim/NeoVim 中你可以通过 ttimeoutlen 来设置功能键超时检测为 50 毫秒,比如:

:set ttimeout ttimeoutlen=50

而 tmux 中,也有类似配置,比如:

set-option -g escape-time 50

就连 ncurses 库中也有类似功能键超时检测的设置,来区别到底是功能键/组合键,还是数个单独的按键。这里你可能觉得这样靠超时检测很不可靠,那你要问 VT100, VT220 的标准制定者了。不过我个人常年设置成 50 毫秒后,连接到各种国内外速度不一的主机上并没有被网速慢把功能键卡成两个键的情况,应该是终端软件中本身也在尽量保证同一组按键序列能够尽量同时发送,所以我链接到国外 rtt=400 左右的主机上工作时,尽管网速经常不稳定,也没有发生错误识别的问题,那其他网速正常的主机就更不用担心了。

更友好的终端设置

上面在 SecureCRT / XShell 中设置了将 alt 键作为发送 +ESC x 的 meta 键后,你会发现,终端软件中固有的一些 ALT 组合键全部失效了,比如原来在终端中 ALT_1 到 ALT_9 可以切换终端的 TAB,ALT_B 可以打开链接管理器,这下都全部用不了了,这是件比较坑爹的事情,能不能保留有限的几个 ALT 组合键给终端软件使用,剩下的全部当作 meta 键呢?答案是可以的,先取消终端里 ALT 当作 meta 键的设置,恢复成默认状态,然后打开终端软件 keymap 设置窗口,将你不需要保留的 ALT 组合键全部设置成发送 +ESC x 字符串。

那么一个个设置可能有些麻烦,对于 SecureCRT 的话,我生成了一个配置文件:

A   VK_A                    "\033a"
A   VK_D                    "\033d"
A   VK_E                    "\033e"
A   VK_G                    "\033g"
A   VK_H                    "\033h"
....
AS  VK_A                    "\033A"
AS  VK_B                    "\033B"
AS  VK_C                    "\033C"
AS  VK_D                    "\033D"

可以到 这里 下载现成的,在 keymap editor 窗口中加载进去即可。

这份 keymap 配置除了保留了 SecureCRT 常用的 ALT_1 – ALT_9 ,ALT_B, ALT_R 和 ALT_I 外,其他的 alt 组合都设置成了 +ESC x 的 meta 键序列。并且将 ALT_SHIFT_1 到 ALT_SHIFT_9 映射到了终端里的 +ESC 1 到 +ESC 9 ,也就是说你的 ALT+数字 被保留给软件切换TAB用了,而 ALT+SHIFT+数字 被映射成了终端链接中的 ALT+数字,这样在终端里碰到需要 ALT+数字 的地方,可以用 ALT+SHIFT+数字 来代替。

设置好以后,可以继续使用 Linux 下的 showkey -a 命令查看一下是否正常。

Vim里识别 ALT 键

前面在终端软件里配置好 ALT键,但是 Vim 的话,由于历史原因,需要在你的 vimrc 里加一段键盘码配置:

function! Terminal_MetaMode(mode)
    set ttimeout
    if $TMUX != ''
        set ttimeoutlen=30
    elseif &ttimeoutlen > 80 || &ttimeoutlen <= 0
        set ttimeoutlen=80
    endif
    if has('nvim') || has('gui_running')
        return
    endif
    function! s:metacode(mode, key)
        if a:mode == 0
            exec "set <M-".a:key.">=\e".a:key
        else
            exec "set <M-".a:key.">=\e]{0}".a:key."~"
        endif
    endfunc
    for i in range(10)
        call s:metacode(a:mode, nr2char(char2nr('0') + i))
    endfor
    for i in range(26)
        call s:metacode(a:mode, nr2char(char2nr('a') + i))
        call s:metacode(a:mode, nr2char(char2nr('A') + i))
    endfor
    if a:mode != 0
        for c in [',', '.', '/', ';', '[', ']', '{', '}']
            call s:metacode(a:mode, c)
        endfor
        for c in ['?', ':', '-', '_']
            call s:metacode(a:mode, c)
        endfor
    else
        for c in [',', '.', '/', ';', '{', '}']
            call s:metacode(a:mode, c)
        endfor
        for c in ['?', ':', '-', '_']
            call s:metacode(a:mode, c)
        endfor
    endif
endfunc

call Terminal_MetaMode(0)

然后你就可以正确在 Vim 映射 ALT 键了,具体原理见 :help set-termcap 以及:

http://www.skywind.me/blog/archives/1846

其他的诸如 emacs, nano 和 neovim 等都不需要额外设置。

终端里正确设置 BS 键

还是 VT100 的历史原因,BACKSPACE 键和 CTRL-H 给混淆起来了,默认情况下,终端里不管按 CTRL-H 还是 BACKSPACE 时都是发送 ASCII 码为 0x08 的 ^H 过去。导致我们想在 Vim/Emacs 中映射 CTRL-H 去干别的事情时会影响到 BACKSPACE 键的使用。

因此得按照 VT220 的新标准修改一下 BACKSPACE 的设置,让它发送 ASCII 码 0x7f 即 ^? 过去:

  • SecureCRT: Session Options -> Terminal -> Emulation -> Mapped Keys, 勾选 Backspace sends delete
  • XShell: Properties -> Terminal -> Keyboard 里,把<BS>设置成 127,而 <DEL>设置成 VT220 Del
  • Putty: 好像默认是 ^? 的不过需要到:Configuration -> Terminal -> Keyboard 下面下确认下 The Backspace key 是 Control-? (127)
  • Terminal.app: 好像默认是发送 ^? 的,你也可以到 Profiles Advanced 下面确认下 “Delete sends Control-H” 没有勾选。
  • iTerm2: 默认也是发送 ^? 的,可以到 Profiles -> Keys下面确认一下 “Delete key sends ^H” 没有被勾选。
  • Gnome-Terminal: 默认发送 ^? 的,参见具体文本配置文件。
  • MinTTY: 设置 vt220/xterm 的话,默认发送 ^? 的,似乎还不能改。

你要深究原因的话,可以见:

http://www.skywind.me/blog/archives/1857

修改好以后可以继续运行:

showkey -a

检查一下,你的 BACKSPACE 键被按下时是否正确发送了 0x7f 字符过去。设置成功的话,终端下 CTRL-h 和 backspace 就不会出现混淆问题了。

Loading

Posted in 随笔 | Tagged | 19 Comments

C语言如何编译出一个不需要操作系统的程序

来个更短的,没有其他乱七八糟的东西,只有一个简短的 C文件,不需要 linux 环境:

miniboot.c

asm(".long 0x1badb002, 0, (-(0x1badb002 + 0))");

unsigned char *videobuf = (unsigned char*)0xb8000;
const char *str = "Hello, World !! ";

int start_entry(void)
{
    int i;
    for (i = 0; str[i]; i++) {
        videobuf[i * 2 + 0] = str[i];
        videobuf[i * 2 + 1] = 0x17;
    }
    for (; i < 80 * 25; i++) {
        videobuf[i * 2 + 0] = ' ';
        videobuf[i * 2 + 1] = 0x17;
    }
    while (1) { }
    return 0;
}

编译:

gcc -c -fno-builtin -ffreestanding -nostdlib -m32 miniboot.c -o miniboot.o
ld -e start_entry -m elf_i386 -Ttext-seg=0x100000 miniboot.o -o miniboot.elf

运行:

qemu-system-i386 -kernel miniboot.elf

结果:

满足条件:

  • 只用纯 C 开发,可以使用 gcc 编译
  • 编译出来的东西真的可以运行
  • 不需要依赖操作系统
  • 不需要包含系统调用的 glibc
  • 连 libgcc 都不需要

解释一下:

Continue reading

Loading

Posted in 编程技术 | Tagged , | Leave a comment

程序员总会遇到一个瓶颈期,该怎么解决?

是不是程序员总会遇到一个瓶颈期,觉得自己没有进步了,该怎么解决?

这问题不光你碰到,很多知名大公司早就面对过了,看看华为怎么解决的,

人家是站在企业文化的高度上来解决,不管内训还是办公室的墙上都有句反复提及的格言,叫做:

简单的事情重复做,你就是专家。

重复的事情用心做,你就是赢家。

整个公司/部门层面上,把这种观念贯(hu)彻(you)下去,你的问题将迎刃而解。

为啥呢?公司目标和个人目标的差异性问题,公司不是学校,最大的目标是挣钱,这是对所有人负责的大目标。再此基础上,最好的时候,两者是重合的,但不是一直都能重合,更不能 100%的重合,二者本质上是矛盾的。主管当然需要协调让两个目标重叠部分增多,然而根本上来讲,你不可能彻底解决这个问题。

二者重叠度下降难以统一时,员工会选择离职,或者能动性下降。公司目标不能随意改变,作为主管能做只有鼓励员工自学加深岗位相关知识的理解,帮员工调岗,更换工作内容让他从事更重要或者新的工作;然而缺乏锻炼机会的自学是有限的,调岗换工作内容并非容易操作之事,所以对于这些大公司而言,最有效的就是通过文化和思想工作改(xi)变(nao)员工的认识。

所以,主管碰到这类问题再原地死磕通常是没辙的,平时看看励志书也不是绝对没用的。

什么工匠精神,什么拥抱变化,什么专注之类的流行词汇,平时也要及时掌握,深入理解

出门请右转,仔细阅读:成功法则(一):简单的事情重复做、重复的事情用心做

还有该说法的姐妹篇《机会总是留给有准备的人》,搭配始用效果最佳,后者我再一篇文章里展开过:

做主程序员是怎样的体验?

只能帮你到这里了。

Loading

Posted in 大浪淘沙 | Tagged | 1 Comment

基础优化-最不坏的哈希表

哈希表性能优化的方法有很多,比如:

  • 使用双 hash 检索冲突
  • 使用开放+封闭混合寻址法组织哈希表
  • 使用跳表快速定位冲突
  • 使用 LRU 缓存最近访问过的键值,不管表内数据多大,短时内访问的总是那么几个
  • 使用更好的分配器来管理 key_value_pair 这个节点对象

上面只要随便选两条你都能得到一个比 unordered_map 快不少的哈希表,类似的方法还有很多,比如使用除以质数来归一化哈希值(x86下性能最好,整数除法非常快,但非x86就不行了,arm还没有整数除法指令,要靠软件模拟,代价很大)。

哈希表最大的问题就是过分依赖哈希函数得到一个正态分布的哈希值,特别是开放寻址法(内存更小,速度更快,但是更怕哈希冲突),一旦冲突多了,或者 load factor 上去了,性能就急剧下降。

Python 的哈希表就是开放寻址的,速度是快了,但是面对哈希碰撞攻击时,挂的也是最惨的,早先爆出的哈希碰撞漏洞,攻击者可以通过哈希碰撞来计算成千上万的键值,导致 Python / Php / Java / V8 等一大批语言写成的服务完全瘫痪。

后续 Python 推出了修正版本,解决方案是增加一个哈希种子,用随机数来初始化它,这都不彻底,开放寻址法对hash函数的好坏仍然高度敏感,碰到特殊的数据,性能下降很厉害。

经过最近几年的各种事件,让人们不得不把目光从“如何实现个更快的哈希表”转移到 “如何实现一个最不坏的哈希表”来,以这个新思路重新思考 hash 表的设计。

哈希表定位主要靠下面一个操作:

index_pos = hash(key) % index_size;

来决定一个键值到底存储在什么地方,虽然 hash(key) 返回的数值在 0-0xffffffff 之前,但是索引表是有大小限制的,在 hash 值用 index_size 取模以后,大量不同哈希值取模后可能得到相同的索引位置,所以即使哈希值不一样最终取模后还是会碰撞

第一种思路是尽量避免冲突,比如双哈希,比如让索引大小 index_size 保持质数式增长,但是他们都太过依赖于哈希函数本身;所以第二种思路是把注意力放在碰撞发生了该怎么处理上,比如多层哈希,开放+封闭混合寻址法,跳表,封闭寻址+平衡二叉树。

优化方向

今天我们就来实现一下最后一种,也是最彻底的做法:封闭寻址+平衡二叉树,看看最终性能如何?能否达到我们的要求?实现起来有哪些坑?其原理简单说起来就是,将原来封闭寻址的链表,改为平衡二叉树:

传统的封闭寻址哈希表,也是 Linux / STL 等大部分哈希表的实现,碰到碰撞时链表一长就挂掉,所谓哈希表+平衡二叉树就是:

将原来的链表(有序或者无序)换成平衡二叉树,这是复杂度最高的做法,同时也是最可靠的做法。发生碰撞时能将时间复杂度由 O(N) 降低到 O(logN),10个节点,链表的复杂度就是 10,而使用平衡二叉树的复杂度是 3;100个节点前者的时间是100,后者只有6.6 越往后差距约明显。

面临问题

树表混合结构(哈希表+平衡二叉树)的方法,Hash table – Wikipedia 上面早有说明,之所以一直没有进入各大语言/SDK的主流实现主要有四个问题:

  • 比起封闭寻址(STL,Java)来讲,节点少时,维持平衡(旋转等)会比有序链表更慢。
  • 比起开放寻址(python,v8实现)来讲,内存不紧凑,缓存不够友好。
  • 占用更多内存:一个平衡二叉树节点需要更多指针。
  • 设计比其他任何哈希表都要复杂。

所以虽然早就有人提出,但是一直都是一个边缘方法,并未进入主流实现。而最近两年随着各大语言暴露出来的各种哈希碰撞攻击,和原有设计基本无力应对坏一些的情况,于是又开始寻求这种树表混合结构是否还有优化的空间。

先来解决第一个问题,如果二叉树节点只有3-5个,那还不如使用有序链表,这是公认的事实,Java 8 最新实现的树表混合结构里,引入了一个 TREEIFY_THRESHOLD = 8 的常量,同一个索引内(或者叫同一个桶/slot/bucket内),冲突键值小于 8 的,使用链表,大于这个阈值时当前 index 内所有节点进行树化操作(treeify)。

Java 8 靠这个方法有效的解决了第一个问题和第三个问题,最终代替了原有 java4-7 一直在使用的 HashMap 老实现,那么我们要使用 Java 8 的方法么?

不用,今天我们换种实现。

Continue reading

Loading

Posted in 编程技术 | Tagged | 2 Comments

AVL/RBTREE 实际比较

网上对 AVL被批的很惨,认为性能不如 rbtree,这里给 AVL 树平反昭雪。最近优化了一下我之前的 AVL 树,总体跑的和 linux 的 rbtree 一样快了:

他们都比 std::map 快很多(即便使用动态内存分配,为每个新插入节点临时分配个新内存)。

项目代码在:skywind3000/avlmini
其他 AVL/RBTREE 评测也有类似的结论,见:STL AVL Map

谣言1:RBTREE的平均统计性能比 AVL 好

统计下来一千万个节点插入 AVL 共旋转 7053316 次(先左后右算两次),RBTREE共旋转 5887217 次,RBTREE看起来少是吧?应该很快?但是别忘了 RBTREE 再平衡的操作除了旋转外还有再着色,每次再平衡噼里啪啦的改一片颜色,父亲节点,叔叔,祖父,兄弟节点都要访问一圈,这些都是代价,再者平均树高比 AVL 高也成为各项操作的成本。

谣言2:RBTREE 一般情况只比 AVL 高一两层,这个代价忽略不计

纯粹谣言,随便随机一下,一百万个节点的 RBTREE 树高27,和一千万个节点的 AVL树相同,而一千万个节点的 RBTREE 树高 33,比 AVL 多了 6 层,这还不是最坏情况,最坏情况 AVL 只有 1.440 * log(n + 2) – 0.328, 而 RBTREE 是 2 * log(n + 1),也就是说同样100万个节点,AVL最坏情况是 28 层,rbtree 最坏可以到 39 层。

谣言3:AVL树删除节点是需要回溯到根节点

我以前也是这么写 AVL 树的,后来发现根据 AVL 的定义,可以做出两个推论,再平衡向上回溯时:

插入更新时:如当前节点的高度没有改变,则上面所有父节点的高度和平衡也不会改变。
删除更新时:如当前节点的高度没有改变且平衡值在 [-1, 1] 区间,则所有父节点的高度和平衡都不会改变。

根据这两个推论,AVL的插入和删除大部分时候只需要向上回溯一两个节点即可,范围十分紧凑。

谣言4:虽然二者插入一万个节点总时间类似,但是rbtree树更平均,avl有时很快,有时慢很多,rbtree 只需要旋转两次重新染色就行了,比 avl 平均

完全说反了,avl是公认的比rbtree平均的数据结构,插入时间更为平均,rbtree才是不均衡,有时候直接插入就返回了(上面是黑色节点),有时候插入要染色几个节点但不旋转,有时候还要两次旋转再染色然后递归到父节点。该说法最大的问题是以为 rbtree 插入节点最坏情况是两次旋转加染色,可是忘记了一条,需要向父节点递归,比如:当前节点需要旋转两次重染色,然后递归到父节点再旋转两次重染色,再递归到父节点的父节点,直到满足 rbtree 的5个条件。这种说法直接把递归给搞忘记了,翻翻看 linux 的 rbtree 代码看看,再平衡时那一堆的 while 循环是在干嘛?不就是向父节点递归么?avl和rbtree 插入和删除的最坏情况都需要递归到根节点,都可能需要一路旋转上去,否则你设想下,假设你一直再树的最左边插入1000个新节点,每次都想再局部转两次染染色,而不去调整整棵树,不动根节点,可能么?只是说整个过程avl更加平均而已。

比较结论

Continue reading

Loading

Posted in 编程技术 | Tagged | 1 Comment

《简明英汉必应版》震撼发布-全网收词量最多的离线词典,词频考纲标注(432万词条)

相信大家都有类似的体验,现在各种桌面在线词典在盈利的压力下,广告越来越多,查个单词都要提示你注册用户,加入社区,添加好友,关注新闻,学习每日一句,推荐英语课程,搞得启动越来越慢,干扰太多了,稍不留神点错了就万劫不复了。

我就想要简单直接的查词即可,可惜商业免费词典都不满足我的需求,后来把《XX词霸》,《X道词典》都卸载了,转投免费开源的 GoldenDict(可以安装各种离线词典),挂载《21世纪》搭配《朗文》《剑桥高阶》等学习词典,确实很好用,可惜这些大部头词典的收词量太少了,查10个词,有3个查不出来,又得点开网页,有道搜不到去金山,金山查不出来去必应,必应再查不出来就要点开谷歌翻译和 wiktionary 和 Urban Dictionary 等,有时候网络不好,点不开,有时候 vps 抽风谷歌翻译用不了。

这年头难道就没有办法让你随心所欲简单快捷的查个单词?于是我找到一个解决方案:现在网上公开免费资源那么多,既然找不到现成的,自己做一个收词量超大的词典放到 GoldenDict / 手机欧陆 里不就完了?

然后我制作了 340 万收词量的开源词典《简明英汉增强版》(支持 GoldenDict, 欧陆词典,BlueDict,mdict,edwin,Kindle 等),受到很多网友们的欢迎,半年不到,积累了五万多的下载量。其后再接再厉,补充更多短语、谚语、新词、俚语和专业术语,并对前20万基础词汇使用必应释义进行了校对,最终发布这个收录 432 万词条的《简明英汉必应版》。

网上有的它有,网上没有的它也有!!收词量 432 万是什么概念,参考下面:

  • OALD8:7.2万词条
  • 朗文5:6.2万词条
  • Merriam-Webster’s Collegiate Dictionary:11.9万
  • 柯林斯 Cobuild 5:3.4万
  • 21世纪:37.7万
  • 有道本地增强版离线词库:40万
  • 欧陆离线词库:40万

整合了市面上各类免费和开源资料,利用 BNC/COCA 语料库进行词频矫正,并使用 NodeBox, WordNet 等自然语言处理工具包对各类时态语态,派生词等进行补充和标注。再根据考试大纲和柯林斯星级还有牛津 3000 核心词进行标注,让你一眼就能看出这个单词的重要性。

(点击 more/continue 继续)

Continue reading

Loading

Posted in 未分类 | Tagged , | 3 Comments

怎样的一句话能让男生瞬间不开心?

什么挖苦讽刺都太小儿科了,根据身边大数据,随便整理几条:

1:部门调整没去处是不是等于失业了?你看看你嘛,我早就说过,就你这性格,XXXX,瞧嘛,现在是不是和我说的一样?就你的脾气,早晚要吃亏,你还跟我狡辩,说说嘛,接下来怎么办呢?怎么办?

2:同事的男朋友对她超级好,每天来接她下班,碰到加班还在楼下等几个小时,是不是很优秀?

3:发奖金了?XXX发了多少啊?为啥比你多?平时他和领导是不是比你接触的更多?

4:今天和X姐出去吃饭,又认识了两个很牛逼的老板,他们是如何如何有钱的,如何如何牛逼的,其中一个非要给我算命,拉着我的手给我看了半天手相。。。。你说有意思不?

5:你怎么像个小孩一样?(当着朋友的时候)。

6:XXX和你一起进公司的,为何他发展的那么快?你有想过为什么么?

7:XXX 你少交往吧,你帮他那么多,他帮过你什么?

大家说,哪条最戳心啊?

Loading

Posted in 随笔 | Tagged | Leave a comment

如何优雅的使用 Vim

根据 Bram 前后几个关于高效使用 Vim的视频,大家每天需要花很多时间来编辑:代码、文档、邮件、日志 等等,除去这些外,还要分时间参加会议和人沟通,每个人的时间却都是不够的,优雅使用 Vim 无外乎:

  • 检测不高效的地方:你的整个工作流里,什么地方比较浪费时间?
  • 寻找一个更快的方式:官方文档,学习他人经验,自己编写 VimScript
  • 使它习惯化:开始使用,并且不断完善

以上三点反复循环,能让你的 Vim 越来越顺手。所以重点是根据自己的工作流不断迭代。而不是象大部分教程那样教你安装一大堆插件。插件都是别人写的为了解决通用需求而提炼的东西,和每个人的具体需求都有差别。上面这三点我屡试不爽,随着时间增长,有种越来越顺手的感觉,举几个我具体碰到的例子:

问题1:边开发边参考网上解决方案的问题

比如碰到问题搜到一段代码,需要试一下,一会又看会 Chrome ,一会又切回 GVim 里去写代码,反复 ALT_TAB,有时候中间使用了一下资源管理器或者其他程序,ALT_TAB 的顺序就会被打乱,你一切换就切跑了,十分低效。

于是我用 VimScript + 内嵌 Python 写了一个功能,按快捷键可以让 GVim 在透明/不透明两种状态间自由切换:

就是 VimScript 简单封装一个函数,里面用内嵌 Python 找到 GVim 的顶层 HWND,并设置透明度。平时默认不透明,需要参考其他资料时切换成透明,参考完了又快捷键切换回来,感觉比缘来切来切去顺畅很多。

问题2:浏览文档时的窗口滚动问题

比如你在抄写或者改写一段代码,窗口分为左右两个,左边是你引用参考的源代码,右边是你正在编辑的源代码。你抄着抄着,抄到左边最后一行了,或者你想前后看看正在引用的文本,你就需要将焦点从右边切换到左边,滚动,再切换交点回来,十分麻烦,于是撸一小段 VimScript 来解决这个问题:

" 0:up, 1:down, 2:pgup, 3:pgdown, 4:top, 5:bottom
function! Tools_PreviousCursor(mode)
    if winnr('$') <= 1
        return
    endif
    noautocmd silent! wincmd p
    if a:mode == 0
        exec "normal! \<c-y>"
    elseif a:mode == 1
        exec "normal! \<c-e>"
    elseif a:mode == 2
        exec "normal! ".winheight('.')."\<c-y>"
    elseif a:mode == 3
        exec "normal! ".winheight('.')."\<c-e>"
    elseif a:mode == 4
        normal! gg
    elseif a:mode == 5
        normal! G
    elseif a:mode == 6
        exec "normal! \<c-u>"
    elseif a:mode == 7
        exec "normal! \<c-d>"
    elseif a:mode == 8
        exec "normal! k"
    elseif a:mode == 9
        exec "normal! j"
    endif
    noautocmd silent! wincmd p
endfunc

把这个函数绑定到 ALT_U, ALT_D 两个按键上,你正在编辑着当前文档时,不用退出 INSERT 模式,更不用切换窗口交点,直接 ALT_U, ALT_D,就可以上下滚动正在参考的文档内容了,有了这个改进后,我的工作又高效了那么一点点。

同理,Quickfix 窗口经常用来查看编译错误,或者 Grep 结果,我也写了一个专门针对 Quickfix 窗口的滚屏函数,不用切焦点随时浏览 Quickfix 内容。

Continue reading

Loading

Posted in 随笔 | Tagged | 2 Comments