在 Emacs 里整合 Ipython

处理 Emacs 和 Ipython 整合时的 Bug 并优化

Created on 2017-09-19 00:58

Emacs Ipython 输出错误

在Emacs 运行 run-python 的时候,报错了,如下

[?12l[?25h2+2
[J[?7h[?12l[?25h[?2004l[?7hOut[1]: 4

因为我的版本时Ipython5,查阅文档 ipython.readthedocs 之后,发现 Ipython5 有了新的 terminal 接口,和 Emacs 继承的 Shell 不兼容,所以 会出现上述的错误,只要给Ipython 加上运行参数就能解决了,所以只要在 .emacs 或者对应的初始化文件加上下面语句

(setq python-shell-interpreter "ipython"
python-shell-interpreter-args "--simple-prompt -i")

Update 2017-3-15

在添加了 --simple-promp -i 参数以后,虽说乱码的问题解决了,但是新的问题又出现了 在Ipython 里面是没法无法输入多行内容的,即使是一个简单的循环,详情查看这条issue. 现在Ipython 开发社区还没有解决这个 问题,所以现在的权宜之计就是使用 Ipython4,等到社区解决了这个问题在升级为 Ipython5

pip install --force-reinstall ipython==4.2.1

Update 2017-5-25

社区似乎已经解决这个问题了,社区有人将原来的 readline interface 接口抽离出来做 成 rlipython,以供用户自己选择。安装方法:

pip install rlipython
python -c "import rlipython as r; r.install()"

不过这个解决方案还有一点限制, rlipython 现在只支持 Ipython 6.0 (Python 3), 以及 Ipython 5.4(Python 2) 以后的版本

Emacs Ipython 的使用优化

python-pop

因为我之前使用Emacs的时候,是使用Spacemacs的配置的,但是后来觉得还是自己的配置用 的更舒服,所以又切换回自己的配置,但是我还是很想念Spacemacs的一些绑定例如shell在 底下弹出,或者是关闭,然后找到 了Shell-pop 这个package,就可以用回 Spacemacs的 Shell使用习惯。然后我觉得,Ipython Shell 应该也可以这样配置,只不过我没有 发现类似的 package,又因为 Emacs Lisp的强大,所以我自己写了一段小函数实现 shell-pop 的功能

(defun samray/python-pop ()
  "Run python and switch to the python buffer.
similar to shell-pop"
  (interactive)
  (if (get-buffer "*Python*")
      (if (string= (buffer-name) "*Python*")
	  (if (not (one-window-p))
	      (progn (bury-buffer)
		     (delete-window))
	    )
	(progn (switch-to-buffer-other-window "*Python*")
	       (end-of-buffer)
	       (evil-insert-state)))
    (progn
      (run-python)
      (switch-to-buffer-other-window "*Python*")
      (end-of-buffer)
      (evil-insert-state))))

如果没有使用Evil,可以把 (evil-insert-state)去掉

Ipython History

我在普通的 Shell使用 Ipython的时候,很自然地使用上下方向键翻到上一条/下一条 执行的命令,因为 Shell的使用习惯就是这样滴,但是在 Emacs里面使用 Ipython, 上下 方向键是去到上一行/下一行,就好像 Vim 的 j k,如果要翻到上一条命令,快捷键 是 M-p,实在很不习惯,所以在查了一下 Emacs manual 后,我改了一下按键绑定就实现了 我想要的效果

(define-key comint-mode-map (kbd "<up>") 'comint-previous-input)
(define-key comint-mode-map (kbd "<down>") 'comint-next-input)

Enjoy Emacs :)