IPython 和 Emacs
IPython 真个是好东西,方便的“帮助模式”,以及 tab 补全。让我这种只会在 terminal 里输入 python 然后开打的人打开眼界!不过 IPython 虽好,用 Emacs 的人总喜欢尽可能地把所有的事情移到 Emacs 下去做。想想看,也是啊,Emacs 里的括弧对齐,方便的输入方式,在 ipython 里打了一会儿,就怀念起来了。你猜对了,接下来说的肯定是 IPython 提供的 py-shell。
py-shell 是在 ipython.el 里提供的一个命令,让我们能使用在 Emacs 底下用上 ipython。先介绍一下 py-shell:
py-shell 的 major-mode 是 Comint 模式(即 command interpreter 模式),在这个模式下用户的输入被 Emacs 收下,喂给指定的 command interpreter(本例中就是 ipython 了),而 interpreter 的输出则被打印到当前的 buffer 中。当然,实际的 Comint 比这个复杂得多,Comint 会过滤输入输出,加入自己的操作比如定义一些 key-map,让自动补全更 Emacs 化。把自动补全显示到专门的 *IPython Completions* buffer 中。
我们都知道 Python 用缩进来控制程序的结构,如果缩进有问题的话,就无法写很多 Python 程序了。而 py-shell 的缩进却是有问题的。
In [11]: def wc(file): ....: count = 0 ....: for line in file: ....: count += 1 ....: return count
本来应该这样的:
In [11]: def wc(file): ....: count = 0 ....: for line in file: ....: count += 1 ....: return count ....:
为了解决缩进的问题,我和 ipython.el 斗争了一个晚上。首先求助于 google 大神,没找到有意义资料。接着在水木上发帖求助,好在有朋友也遇到了这个问题。而且有了补救的方法。他的办法就是在开启另外一个辅助的 python-mode buffer *IPython Indentation Calculation*,在那里面插入和 *Python* buffer 里相同的输入语句,让 python-mode 帮助我们计算缩进的字符串,然后再把这个字符串记下,待 comint 要输出的时候,再把缩进字符串加到输出的提示符后面。这个方法虽然有些绕弯,但是一下子也找不出什么更好的替代方案了。但是补救方法只是在 Windows 的 NTEmacs 上可行,在 Debian 的 Emacs 下却会不正常(第二版的设置根本就无效)。具体的修改:
- 只是加入了一个 “RET” 的 key map—— ipython-newline-and-indent()
- 负责更新 *IPython Indentation Calculation*
- 以及抓取缩进字符串
- 负责检查 ipython 的提示符
- 并插入正确的缩进字符串
- 清空缩进字符串
Liu Jin 的办法是在 ipython-newline-and-indent() 抓取缩进字符串,这个办法可能会有 race condition 的问题。不知道是 ipython-newline-and-indent 先执行完毕,还是 ipython-indentation-hook 先执行。测试下来,ipython-indentation-hook 从没有等到过抓好的字符串。因此,我把抓取字符串的工作从 ipython-newline-and-indent() 移动到了 ipython-indentation-hook(),并作了一些小改动。看起来没问题了,但是用了一阵子,碰到了新的问题。照 Liu Jin 的提示,我在 py-python-command-args 中又加了 -noautoindent。现在看上去没问题了。先将就着使吧。
