我的system-config使用指南

Not finished yet.

前一阵子,公司终于有一个同事开始正式用我的system-config了,赞。觉得应该好好说说我的system-config项目,是什么,干什么用的,怎么用。

System-config是github上的一个项目,里面包含了我的所有配置文件和脚本,比如.bashrc和.emacs文件等。你可以在Debian和Ubuntu系统上方便的使用它。

使用本文中描述的方法配置完system-config之后,你可以直接用上 beagrep, grep 2G source code in 0.23 second 等我的博客里几乎一切你看了觉得有意思的工具、软件。

说不定你还能学会一两个新工具的用法😁。

如果没有看过 高效文本编辑的七个习惯 的话,强烈推荐在看本文之前或/和之后看看,Vim作者写的,我翻译的。

(我后来录了一个两小时的视频,在bilibili上,我的十年Linux使用经验 ,欢迎上去吐槽。)

(后来又写了一篇 system-config原理与使用的简要说明 ,讲了一些原理性的东西,可以对照着看一下。)

1 system-config 是什么

system-config 是我在github上最早的一个代码库,里面包含了我所有配置文件和脚本。很多人都会配置一下自己的工作环境,但大多数人还没有意识到这些配置文件其实都是代码,都可以/应该用版本管理工具把它们管理起来。这样你才可以不断地提升自己的工作效率,因为你对自己工作环境的配置在持续地改进中。

system-config 里面最重要的可以分为几个部分:整个系统相关的部分,bash相关的部分,emacs相关的部分,其它工具相关的部分。

github上有一些跟system-config类似的项目,但好像还没有像我的这个这样,可以让我自己拿到一台新机器后,很方便地完整的重现自己的工作环境。比如这个项目:https://github.com/rupa/z ,允许你方便地跳转目录。但这些项目有一个问题,就是你不能拥有一个完整的工作环境。我这个属于一揽子解决方案。

我最早开始折腾这些配置,是在当年很有名的清华大学王垠的博客上,看到他把自己的配置一条一条地粘贴在自己的文章里,我就一条一条地拷贝下来。但这种拷贝做法中间经常容易出错,即使没有出错,我也非常担心自己是不是在拷贝的时候少拷了一行代码之类的,非常没有保证。有时候原作者不小心漏贴了某条关键的配置文本也是有可能的,碰到这些情况的话,还是非常痛苦的。所以后来我学会了svn之后就把这些配置放到了google-code上。后来学了git之后就转移到github了。不知道大家有没有过类似地从网上到处拷一小段配置、代码的经历😁。

接下来说一下如何使用我的system-config。(当你使用一段时间之后,你也可以fork这个项目,然后把你自己喜欢的一些设置加入到你的fork中。当然,如果你发现我写的有一些不够合理的地方,也欢迎在github上给我提pull request。)

2 如何配置system-config

注意: 此处给出的配置方法并不适用于锤子科技公司内部同事——你们用公司内部wiki上的那个配置方法是更方便的。

system-config的配置很简单,你只要运行这个命令就可以:

bash -c "$(curl -s http://baohaojun.github.io/system-config.sh)" system-config.sh

在运行的过程中,脚本会询问你是要简易版配置还是火力全开版:

confirm-which-system-config.png

如果是第一次配置system-config,建议使用简易版配置。

2.1 简易版配置

在上图的命令行提示下直接按回车,等待 Simple config OK. 这样的输出就表示配置成功了,可以开始试用。否则说明有Bug了,可以考虑给我提个Bug。

此过程中会问你几个问题,比如你的邮箱地址,因为在之后配git/repo的时候会用,请参考下图输入你自己的信息:

about-me-settings.png

2.2 完整版配置

此配置在简易版的基础上还会安装、编译我常用的一些软件。

在上面的命令行提示下输入 yes 再回车,最后输出 Full config OK 的话就表示成功了。中间可能需要回答几个问题。

这个配置第一步是下载system-config项目的代码。第二步则运行一些配置脚本,把我的工作环境能自动化配置的部分全部重新配置出来。这个配置的时间可能会有点长,尤其是如果你的Debian/Ubuntu机器是新装的,很多软件会在配置system-config的时候被自动安装,花的时间会更长一点。请一定要有耐心,相信最后的system-config会让你觉得是值得的😅。

运行的过程中可能需要你输入几次sudo密码,以及按几次回车、输入yes/no再回车等。其他的一般都已经尽量做到自动化了。

2.3 配置过程中出了问题怎么办

请拷贝下出错时的终端输出发邮件给我。当然,最喜欢的是能自己google解决问题的朋友了😆。

3 bash相关的操作

接下来要开始讲一些我的system-config下与一般的Linux系统不大一样的一些用法。

我在写system-config的时候绝大多数情况下都会尽量注意与原有的命令兼容,只会在一些本来应该出错的用法下对该命令进行扩展。比如cd命令,正常的用法是 cd DIR ,这里 DIRcd唯一 参数,比如可以是你想要进入的目录的绝对路径 /home/bhj/src/android/external/libsepol 。我对它进行扩展之后,我的 cd 用法就变成了 cd DIR_STEM1 DIR_STEM2 ,也就是说,我可以只打我想去的目录的几个关键字(可能是我觉得比较好记的),然后如果只有一个历史目录能“匹配”这几个关键字的话,system-config就直接帮我进入到那个目录了。(如果你发现我的一些改动会导致你原来的程序、使用习惯出错,请给我 提Bug

接下来要讲的很多内容就是那些不一样的地方,所以请一定在配置了我的system-config之后再来尝试这些命令。

3.1 cd命令

正常情况下,我的cd命令是跟系统自带的bash内置cd命令一模一样的:cd后面跟一个目录的名字,直接就改变当前目录到那个目录下。

但我的cd命令会默默地帮你做很多事(这个跟上面提到的那个 https://github.com/rupa/z 项目非常类似):

  1. cd DIR 会把 DIR 记到你的 ~/.cache/system-config/.where 文件里,按最近使用的在最前的方式排序。
  2. cd foo bar 会从你的 ~/.cache/system-config/.where 文件里过滤出符合条件的目录,如果只有一个,直接跳转过去,如果不只一个,会有一个简单有效的选择方法让你选(因为之前的排序方式是最近使用排最前,所以大多数情况下你直接回车就行,因为第一条往往就是你想要的那条)。

    比如我在终端里打 cd fra base ,在我的系统上会让我选哪个目录:

    cd-completion.png

    这个匹配的规则是这样的:一个目录想要匹配成功,必须:1. 绝对路径匹配cd的每一个参数;2. 最后一个子目录匹配cd的至少一个参数。

    可以参考图中红色标注的部分,注意最后一个子目录必须有匹配(已用红色标注)。

  3. 如果cd的后面跟的是一个文件,那就自动替换为cd到这个文件所在的目录下。因为有很多时候你比如会从邮件里拷贝到一个文件的路径,这时想cd到这个文件的目录下,你粘贴之后还需要删掉文件的那部分,我认为这个可以自动化一下😁。
  4. cd smb://windows-share-folder/path{cd '\\windows-share-folder\path'}

    如果你配过一些软链接的话,你可以通过这种用法直接在命令行上访问Windows的共享文件夹。在Linux下你用文件管理器访问过一个samba目录之后,会在某个gvfs mount的目录下生成一个跟这个共享文件夹对应的目录,比如我的是在 /run/user/1000/gvfs/smb-share:xxx 下,然后我在 ~/smb/ 目录下生成了这样的软链接:

    symlink-share-folders.png

    你在用文件管理器访问过某个共享目录后,可以用 smb-links 这个命令来直接生成相应的软链接。

3.2 putclip/getclip

putclip这个命令可以用于在命令行上把文本放到系统剪贴板里去,然后很方便的在邮件程序、网页编辑框里去粘贴。

getclip则可以用于在命令行上获取剪贴板里的内容。

3.3 up/wp/sup/swp/ap/gitp

这些命令是对putclip/getclip的进一步封装。在命令行上它们可以用特殊的格式把当前目录或你指定的文件的绝对路径放到剪贴板里去。因为前面我的特殊的cd的关系,你在命令行上找目录、找文件是特别方便的对不对?现在因为这些命令的关系,你找到一个文件并把它的路径放到剪贴板里的步骤也特别方便了。比如我在发邮件、发微博的时候想要上传一张图片的话,我是不会在浏览器的文件对话框里点来点去找文件的:

no-file-dialog.png

因为这个效率实在是不如在命令行上拷贝下文件的路径,然后直接在这个对话框里粘贴一下就好了。

你可以猜一下up/wp/sup/swp/ap/gitp分别都是什么意思😁。 想知道总共有多少类似的命令的话,可以打开 wp 文件看一下。

3.4 bash历史命令搜索

很多同学都知道bash下如果搜历史命令的话有一个ctrl-r键可以往回搜。但ctrl-r的一个缺点是,它在搜索的时候要求你连续打出一整段和历史命令匹配的文本才能匹配,中间打个错别字或者有几个字符太难打太难记想跳过去都是不行的。

所以我提供了一个re命令。这个re命令什么也不做,唯一做的就是帮助bash进行补齐。对,以前的bash补齐机制(打了一个命令、文件名、路径名的一部分之后按Tab键)实现比较简单,不支持太智能的补齐。现在的bash已经提供可编程补齐的机制。

我在bash下打re getprop adb persi之后按Tab补齐,它就会把 ~/.bash_history.bak 里的历史命令匹配的全都帮我列出来,如果只有一个匹配就直接帮我补齐了。否则会按使用远近排序,最近使用的排在最前让我选。选的方法是输入 .N 然后再按一次Tab,比如 .0 就是选第一个补齐:

re-for-completion.png

关于那个 ~/.bash_history.bak 文件,你可以在bash下打 hir 命令,这是我定义的一个函数,它会把bash自己记下来的历史命令 ~/.bash_history 导入到 ~/.bash_history.bak 里去。

3.5 e/ew命令

这两个命令可以用来在命令行上远程控制emacs打开某个文件。如果当前桌面下还没有打开emacs程序,它会先启动一个。注意如果emacs启动出错的话,这两个命令会进入死循环等待。

其中 e 命令会打开一个文件后直接返回。 ew 会一直等待emacs编辑完文件之后用户按 C-x # ( server-edit ) 退出编辑才返回。所以你可以把它设为你的 EDITOR 环境变量。

3.6 bash的快捷键

bash下自定义了很多快捷键。你可以用bind -p来查看都有哪些功能,你可以自己再定义几个,只要修改 .inputrc 文件就好了。

这里说一下我自己定义的最重要的一个:

M-k
把当前命令行上输入的东西放到剪贴板里去。你可以跟 C-r 或者 re 历史命令组合使用,先搜到一条历史命令,然后放到剪贴板里去。在终端上打过一条 one-liner,用这个方法可以很方便地把它写到emacs里去,成为一条以后经常使用的脚本。

4 Emacs相关

4.1 e/ew

这个已经在bash相关里提到过了。

4.2 常用快捷键

我会以学Emacs最有效的顺序来列出我认为比较有用的快捷键。

C-h ?
你需要尽快学会查看Emacs下的帮助。这里会列出所有的帮助大纲。
C-h b
列出当前模式下的所有快捷键。通过快速浏览和Emacs自带的搜索功能,你可以方便的“发现”里面有什么快捷键是你比较想要的。
C-s 和 C-r
前后搜索。按C-h k看一下这个键的帮助,非常重要!如果看过 Vim 作都写的高效编辑器使用的七种习惯的话,就会明白搜索还是一种非常重要的移动、定位方法。
M-g o
这个是我写的bhj-occur,列出在整个buffer里和你输入的pattern匹配的行,你可以用 M-g n 和 M-g p 进行来回跳转。你可以试试在看帮助文档的时候有意识地用这个键去过滤自己想找来看看的东西。
M-g n 和 M-g p
这个就是上面提到的编译出错、occur、grep等命令之后在N个匹配行之前来回跳转的快捷键。
C-M-, 和 C-M-.
跑过occur、grep等命令并跳转出去之后,可以用这两个 按键一路来回跳转到开始的地方。类似于浏览器上的前进后退按钮。
M-g r
运行beagrep。默认以当前 point 附近的单词为目标进行搜索, 你可以编辑这个pattern。也可以先选上一段文本,然后再按这个组 合键,它会以被高亮选中的文本为目标pattern运行beagrep命令。 这些pattern里的特殊字符会按grep(1)的格式被转义,比如 ^. 会被转义成 \\^\\. 。你看到两个 \ 字符进行转义是因为bash 的双引号要吃掉一个。你可以在命令行后增加一些额外的参数。

beagrep的使用帮助见 beagrep, grep 2G source code in 0.23 second

前提是对整个源代码目录已经用 for-code-reading 命令创建过索引。

M-s r
运行rgrep,Debian系统自带的,我在自己的system-config里也放 了一份,因为Ubuntu有些版本上没有该命令。有时候beagrep还是比 较慢,如果你能限定在一个比较小的目录下搜的话,可以试试直接 用rgrep。
M-.
用来查找一个函数的定义。会以grep的格式列出来,你可以用同样的 快捷键去跳转。前提是你运行过 mkgtags 。建议和beagrep的索引 数据库一起创建,用 for-code-reading 命令就可以。
M-g f
用来查找一个函数/一个pattern在哪里被调用。参考 Using Emacs as a better Source Insight 。它会调用 grep-func-call ,默 认它会在当前文件查调用;如果有 -a 参数的话它会在整个 code-reading目录底下查找。
C-x r r
用来随机切换Emacs主题。我以前浪费过很多时间在寻找“完美”的 Emacs主题上,后来醒悟过来之后,我把自己的Emacs设置成启动 时随机选择一款主题。但万一系统随机选的主题不符合我的口味 的话,我就可以按这个键再换一个,直到换到我喜欢的为止。

以上基本上都是在阅读源代码时比较有用,接下来要说的是写源代码时比较有用的快捷键。

M-/
hippie-expand,一种简单粗暴的补齐方式
M-g <return>
我写的skeleton-complete.el里按单词补齐。注意在不同的 major-mode下单词字符的定义可能不一样。参考 skeleton-complete

给定一个lisp函数名, this-useful-function-is-so-long ,你可以打 uncsolo 再按这个键来补齐它。

M-s <return>
skeleton-complete.el里定义的任意字符串补齐。有头部匹 配的限制。给定上面的函数名,你打 uncsolo 再按 M-s <return> 是无法补齐的,因为头部的 u 不能匹配一个单 词的头部。可以试试 funsolo ,看看会补什么出来。
C-M-i 或 M-tab
yasnippet补齐。在写一个bash脚本的时候你输入 Getopt 然后按这个键试试。yasnippet是一个非常有用的Emacs插件!唯一缺点是要提前准备模板。
C-c y v
问某个 yasnippet 模板。
C-c y n
新建一个 yasnippet 模板。
M-s c
进行编译,第一次要求输入编译命令,出错的话可以跳转定位。

以下为写Java代码时特别相关的快捷键。参考 Inside Ajoke 。也可以看一下源代码 ajoke.el

M-g j h
显示当前类的继承树。

其它相关的快捷键可以直接打开 ajoke.el 看一下。

the-ajoke-key-bindings.el.png

4.2.1 C++/C文件的补齐

我现在在用 ac-clang 来进行C/C++语言的补齐,见 如何在Linux + Emacs下进行MFC编程(代码补齐)

快捷键是:

C-.
ac-complete-with-helm

一般这个都是需要特别配过的。你可以参考我的 .dir-locals.el ,这个是为qt配的,把它拷到你的qt项目底下,就可以补齐了。

出错的话可以自己看一下 clang error 这个buffer里,看看有什么头文件没有找到之类的错误,然后加到 .dir-locals.el 文件里之后,记得一定要重新打开 .c/.cpp 文件。并且找开的时候一般Emacs会问你确认这些变量设置是不是安全的,选Yes就好了。