注: 本文第一次写作时没有进行全面的测试,由于 svn update 操作更新文件时会破坏 NTFS 上的硬链接而导致第一次的方法无法正常使用。现在你看到的已经是新的方法。在此为我的疏忽向大家道歉。

现在我的生活早已离不开 Vim 了,无论是在公司还是在家里,无论是在本地计算机还是远程服务器上,Vim 必定是我使用得最多的程序之一。当然了,Vim 虽好,也一定要有符合自己习惯的 .vimrc 和插件集才能发挥出更大的潜能,让我们用得更爽。也就是说,.vimrc 肯定是会被经常修改的,插件集也应该会时常添加新成员或进行版本更新。显然,要在家里和公司以及一些远程服务器之间频繁地同步这些修改是件很烦人的事。幸好,我们有 Subversion 可以让这一切变得简单。

让我们从公司的 Linux 桌面机上开始。

# 将 $HOME 里的 .vimrc 和 .vim 目录放到 vimfiles 目录里以便进行 SVN 导入操作
cd ~
mkdir vimfiles
mv .vimrc vimfiles
mv .vim vimfiles
svn import vimfiles http://svn.rainux.org/vimfiles/trunk
# 从 SVN 里 checkout 出一份 working copy 到 $HOME 里,
# 并且设置忽略掉 $HOME 里其他所有文件
svn co http://svn.rainux.org/vimfiles/trunk .
svn ps svn:ignore '*' .
svn ci -m "Let's ignore all files those not managed by Subversion in $HOME."
# 用来进行导入操作的 vimfiles 目录已经不再有任何存在的意义了
rm -rf vimfiles

好了,我们的 .vimrc 和插件集已经版本化了,下班回家。

# 先备份一下家里 Windows 上的文件,这假设我们没有使用 Cygwin
CD %HOME%
MOVE .vimrc .vimrc.backup
MOVE vimfiles vimfiles.backup
svn co http://svn.rainux.org/vimfiles/trunk .

现在我们遇到问题了,Vim 在 Windows 上会尝试从 %HOME%\vimfiles 目录加载用户脚本,而不会理会 %HOME%\.vim 目录。我的解决办法是为 .vim 目录建立符号链接 vimfiles,这需要 %HOME% 所在分区必须是 NTFS 文件系统。新的问题是 Windows 本身并没有附带创建符号链接的工具,需要用 Sysinternals 提供的命令行工具 junction.exe 或者 Windows 2000 Resource Kit 里的 linkd.exe 来创建。

CD %HOME%
junction vimfiles .vim

OK,开始享受 Subversion 为我们带来的便利吧!不仅仅可以方便的同步在公司和在家里对 .vimrc 及插件集的修改,在远程服务器上要取得这些最新的修改也变得非常容易。什么,某个服务器上还在使用古老的 Vim 6.3 ?没有关系,为 http://svn.rainux.org/vimfiles 创建一个名为 6.x 的 branch,删掉无法用于 6.x 的插件即可。

最后,如果你对我的 Vim 配置感兴趣,可以从上面提到的 URL 里 checkout 一份出来看看,是的,它是真实的 URL。:)

Update: 作为狂热的 Git 爱好者,我已经使用 Git 来管理我的 Vim 配置文件了,请访问我的 Vim 配置文件页面。

标签:, , , ,

按照《使用 Subversion 进行版本控制》 书中的建议,项目在被 import 到版本库前,最好能在项目根目录下建立 trunk、branches、tags 等目录,并将项目源代码存放在 trunk 子目录下,这将有利于工作中对相对稳定的项目做较大修改时创建分支。

但是一些历史项目,或者我们自己在对 Subversion 不够熟悉的情况下创建的项目,可能是直接把项目源代码存放在项目根目录里的,这种情况下要修改版本库布局,将所有文件移动到 trunk 子目录下就比较麻烦了。设想过使用 svn mv 命令应该可以做到,但是它会产生一个整个项目所有文件被移动的 revision,不但很不优雅,也不便于以后查看历史记录以及回溯到旧版本。

这种情况下我们可以这样做:

  1. 将整个项目的版本库导出为一个 dump 文件(它是一个可编辑的文本/二进制混合文件,其中包含了所有的 revision 记录)。
  2. 在 dump 文件中所有的路径前加上 trunk/ 前缀,使它们处于 trunk 子目录下。
  3. 在 dump 文件中 revision 1 里直接加入 trunk 等目录的创建。
  4. 删掉项目的版本库并重建新版本库,然后导入我们修改后的 dump 文件。

进行这样的操作后,项目的版本库状态就是从 revision 1 开始所有的文件就存在于 trunk 目录下了。

具体操作步骤,以在 Linux 命令行下为例:

svnadmin dump /path_to_svn_repos/your_project > your_project.svn_dump
vim -b your_project.svn_dump
# 以下为 Vim 命令
:%s/^Node-path:\s\+/\0trunk\//ge
:%s/^Node-copyfrom-path:\s\+/\0trunk\//ge
# Vim 命令结束
# 添加 trunk 等目录的创建,见后文详述
rm -rf /path_to_svn_repos/your_project
svnadmin create /path_to_svn_repos/your_project
svnadmin load /path_to_svn_repos/your_project < your_project.svn_dump

注意一定要用 -b 参数启动 Vim,这样可以避免 Vim 在没有配置好多字节文件支持的选项时对 dump 文件可能的破坏。添加 trunk 等目录的方法是在 Revsion-number: 1 那一行后的第一个 PROPS-END 行后插入以下蓝色的代码。注意那些空行,有些是空一行有些是空两行,我是严格按照已有的目录的格式来写的,在没有看到这个 dump 文件的规格文档前最好连空行也照原样复制。

...
Revision-number: 0
Prop-content-length: 56
Content-length: 56

K 8
svn:date
V 27
2007-10-11T14:15:09.781135Z
PROPS-END

Revision-number: 1
Prop-content-length: 100
Content-length: 100

K 7
svn:log
V 0

K 10
svn:author
V 6
rainux
K 8
svn:date
V 27
2007-10-11T14:15:48.344335Z
PROPS-END
Node-path: trunk
Node-kind: dir
Node-action: add
Prop-content-length: 10
Content-length: 10

PROPS-END


Node-path: branches
Node-kind: dir
Node-action: add
Prop-content-length: 10
Content-length: 10

PROPS-END


Node-path: tags
Node-kind: dir
Node-action: add
Prop-content-length: 10
Content-length: 10

PROPS-END

Node-path: trunk/README
Node-kind: file
Node-action: add
Prop-content-length: 10
Text-content-length: 8001
Text-content-md5: 2ffe7715fd6ba5509508a29022c22a17
Content-length: 8011

PROPS-END
== Welcome to Rails
...
标签:, ,

四个小时前,在上海紫金山大酒店四楼的会场见到了自由软件社区的大哥级人物 Ian Murdock。一身白色 T shirt 的他看上去比活动宣传照上更年轻。

虽然了解、使用和喜爱 Debian 已经有四年了,但对于创始人 Ian Murdock 却没有太多的了解,只知道他现在为 Sun 工作,Debian 这个词源自他当时的女友(现在的妻子)Debra 和他自己名字的组合。很浪漫的命名方式,如果有机会,我也希望能做这样的事。 :) 看到活动的介绍后,才知道 Ian 还是 Linux Foundation 的 CTO,Linux Standard Base 的 Chief。

今天活动的主要内容是 Ian 的个人演讲和跟现场的 Linux 用户交流。给我的印象是 Ian 比较健谈,对大家提出的大多数问题都聊了很多。可惜,可惜,最大的遗憾是,他说的话有 95% 我都没听懂……-_-b 平时自诩流畅阅读英文技术文档的我,听力实在是太差了。(以后一定要经常对照字幕看原版电影来练习听力!)

晚上九点左右,活动结束后,Ian 还坐在舞台的一角为大家签名,跟大家合影。我也有幸跟他合影了一张(感谢好友 AKAI 帮助拍摄!),本来想说 “I’ve loved and enjoyed Debian for several years and will continue, many thanks to your hard work!”,不过没好意思说出口。-_-b

这次活动到会的粗略估计大概有四五百人,应该是超出了报名人数不少,以致于主办方准备的简单晚餐在还有很多人排队时就已经被“洗劫一空”了。

PS: 发现到会的 Geek 中 MM 还挺多的。

Ian & Rainux

标签:, ,

一些自动执行特定任务的小脚本程序,如果希望能使程序的 stdout/stderr 输出到屏幕的同时也把他们记录到一个日志文件,可以使用 tee 命令结合 shell I/O 重定向来轻松完成:

./a_tiny_script 2>&1 | tee the_log_contain_both_stdout_and_stderr.log

这个命令的精华在于 2>&1,意为让 stderr 使用 stdout 的文件描述符,效果也就是将 stdout 和 stderr 内容合并,并且输出到 stdout 被定向的位置。在这里也就是管道中的 tee 命令的 stdin 上,然后 tee 将得到的输入同时显示在屏幕上和记录到日志文件里。爽吧?

以前为了在 PHP 脚本里实现这样的功能竟然使用了 ob 系列函数 + 自定义的 output callback 函数,并且这样也只能做到同时显示和记录 stdout,真是晕到死。

标签:, , ,

和所有的流行文本编辑器一样,Vim 可以很好的编辑各种字符编码的文件,这当然包括 UCS-2、UTF-8 等流行的 Unicode 编码方式。然而不幸的是,和很多来自 Linux 世界的软件一样,这需要你自己动手设置。

Vim 有四个跟字符编码方式有关的选项,encoding、fileencoding、fileencodings、termencoding(这些选项可能的取值请参考 Vim 在线帮助 :help encoding-names),它们的意义如下:

  • encoding: Vim 内部使用的字符编码方式,包括 Vim 的 buffer(缓冲区)、菜单文本、消息文本等。用户手册上建议只在 .vimrc 中改变它的值,事实上似乎也只有在 .vimrc 中改变它的值才有意义。
  • fileencoding: Vim 中当前编辑的文件的字符编码方式,Vim 保存文件时也会将文件保存为这种字符编码方式(不管是否新文件都如此)。
  • fileencodings: Vim 启动时会按照它所列出的字符编码方式逐一探测即将打开的文件的字符编码方式,并且将 fileencoding 设置为最终探测到的字符编码方式。因此最好将 Unicode 编码方式放到这个列表的最前面,将拉丁语系编码方式 latin1 放到最后面。
  • termencoding: Vim 所工作的终端(或者 Windows 的 Console 窗口)的字符编码方式。这个选项在 Windows 下对我们常用的 GUI 模式的 gVim 无效,而对 Console 模式的 Vim 而言就是 Windows 控制台的代码页,并且通常我们不需要改变它。

好了,解释完了这一堆容易让新手犯糊涂的参数,我们来看看 Vim 的多字符编码方式支持是如何工作的。

  1. Vim 启动,根据 .vimrc 中设置的 encoding 的值来设置 buffer、菜单文本、消息文的字符编码方式。
  2. 读取需要编辑的文件,根据 fileencodings 中列出的字符编码方式逐一探测该文件编码方式。并设置 fileencoding 为探测到的,看起来是正确的(注1)字符编码方式。
  3. 对比 fileencoding 和 encoding 的值,若不同则调用 iconv 将文件内容转换为 encoding 所描述的字符编码方式,并且把转换后的内容放到为此文件开辟的 buffer 里,此时我们就可以开始编辑这个文件了。注意,完成这一步动作需要调用外部的 iconv.dll(注2),你需要保证这个文件存在于 $VIMRUNTIME 或者其他列在 PATH 环境变量中的目录里。
  4. 编辑完成后保存文件时,再次对比 fileencoding 和 encoding 的值。若不同,再次调用 iconv 将即将保存的 buffer 中的文本转换为 fileencoding 所描述的字符编码方式,并保存到指定的文件中。同样,这需要调用 iconv.dll

由于 Unicode 能够包含几乎所有的语言的字符,而且 Unicode 的 UTF-8 编码方式又是非常具有性价比的编码方式(空间消耗比 UCS-2 小),因此建议 encoding 的值设置为 utf-8。这么做的另一个理由是 encoding 设置为 utf-8 时,Vim 自动探测文件的编码方式会更准确(或许这个理由才是主要的 ;)。我们在中文 Windows 里编辑的文件,为了兼顾与其他软件的兼容性,文件编码还是设置为 GB2312/GBK 比较合适,因此 fileencoding 建议设置为 chinese(chinese 是个别名,在 Unix 里表示 gb2312,在 Windows 里表示 cp936,也就是 GBK 的代码页)。

以下是我的 .vimrc 中关于字符编码方式设置的内容,这个设置比较有弹性,可以根据系统中的环境变量 $LANG(当然,Windows 中的写法是 %LANG%)的值来自动设置合适的字符编码方式。此时,推荐设置 %LANG% = zh_CN.UTF-8,可以通过后面的 Windows 注册表脚本文件来方便的做到。

" Multi-encoding setting, MUST BE IN THE BEGINNING OF .vimrc!

if has("multi_byte")
  " When 'fileencodings' starts with 'ucs-bom', don't do this manually
  " set bomb
  set fileencodings=ucs-bom,chinese,taiwan,japan,korea,utf-8,latin1
  " CJK environment detection and corresponding setting
  if v:lang =~ "^zh_CN"
    " Simplified Chinese, on Unix euc-cn, on MS-Windows cp936
    set encoding=chinese
    set termencoding=chinese
    if &fileencoding == ''
      set fileencoding=chinese
    endif
  elseif v:lang =~ "^zh_TW"
    " Traditional Chinese, on Unix euc-tw, on MS-Windows cp950
    set encoding=taiwan
    set termencoding=taiwan
    if &fileencoding == ''
      set fileencoding=taiwan
    endif
  elseif v:lang =~ "^ja_JP"
    " Japanese, on Unix euc-jp, on MS-Windows cp932
    set encoding=japan
    set termencoding=japan
    if &fileencoding == ''
      set fileencoding=japan
    endif
  elseif v:lang =~ "^ko"
    " Korean on Unix euc-kr, on MS-Windows cp949
    set encoding=korea
    set termencoding=korea
    if &fileencoding == ''
      set fileencoding=korea
    endif
  endif
   " Detect UTF-8 locale, and override CJK setting if needed
  if v:lang =~ "utf8$" || v:lang =~ "UTF-8$"
    set encoding=utf-8
  endif
else
  echoerr 'Sorry, this version of (g)Vim was not compiled with "multi_byte"'
endif

Windows 注册表脚本。

Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\\Environment]
"LANG"="zh_CN.UTF-8"

注1: 事实上,Vim 的探测准确度并不高,尤其是在 encoding 没有设置为 utf-8 时。因此强烈建议将 encoding 设置为 utf-8,虽然如果你想 Vim 显示中文菜单和提示消息的话这样会带来另一个小问题。参见另一篇 Win32 下 Vim 设置 enconding 为 utf-8 会在显示特定消息时崩溃。(此处提到的崩溃问题在 gVim 7.0 beta 时代就已经被解决了。)

注2: 在 GNU 的 FTP 上可以下载到 iconv 的 Win32 版,不推荐去 GnuWin32 下载 libiconv,因为那个版本旧一些,并且需要自己改名 dll 文件。

标签:, , ,
Page 2 of 3123