特性

在Linux论坛上总有人问Python用什么IDE比较好,然后总会有人回答说Emacs。最近开始学Python,也花了点时间研究怎么配置Emacs,发现没有想象中的那么麻烦。这篇文章大致上来自于Lei Chen博客文章的翻译,完成以后的Emacs具有以下特性:

  • 自动完成同一个文件内的变量、函数
  • 自动完成python库中的名称
  • 代码重构
  • 模板展开功能
  • 在线帮助系统
  • 即时语法检测

其他特性还包括自动缩进,括号匹配,语法高亮,代码折叠等等。其中最有用的莫过于自动完成了,貌似很少有python编辑器可以做到这一点。而即时语法检测让emacs下的python代码书写变得像Eclipse一样,一旦有错误立刻就会高亮标记出来。

如何安装

首先你得在home目录下有一个.emacs配置文件,并且有一个用来放插件的文件夹(比如说~/.emacs.d/)

  1. 下载auto-completion.el到.emacs.d,并且在.emacs中添加如下几行:
    (require ‘auto-complete)
    (global-auto-complete-mode t)
    
  2. 下载yasnippet到.emacs.d并且编辑.emacs:
    (require ‘yasnippet) (yas/initialize) (yas/load-directory “~/.emacs.d/snippets”)
  3. 下载python-mode.el并且放到.emacs.d中。我们会在之后的配置中用到它
  4. 设置Rope, Ropemacs 和 Pymacs

    我们需要使用最新的development版的rope和ropemacs,否则在emacs中不能找到rope-completion函数。通过如下步骤安装:

    sudo apt-get install mercurial
    mkdir /tmp/rope && cd /tmp/rope
    hg clone http://bitbucket.org/agr/rope
    hg clone http://bitbucket.org/agr/ropemacs
    hg clone http://bitbucket.org/agr/ropemode
    sudo easy_install rope
    ln -s ../ropemode/ropemode ropemacs/
    sudo easy_install ropemacs
  5. 安装pyflacks以进行自动语法检查:

    sudo apt-get install pyflakes
  6. 把所有东西放到一块儿
  7. 在你的.emacs.d中创建一个init_python.el,并且加入以下内容:

    (autoload 'python-mode "python-mode" "Python Mode." t)
    (add-to-list 'auto-mode-alist '(".py'" . python-mode))
    (add-to-list 'interpreter-mode-alist '("python" . python-mode))
    (require 'python-mode)
    (add-hook 'python-mode-hook
          (lambda ()
    	(set-variable 'py-indent-offset 4)
    	;(set-variable 'py-smart-indentation nil)
    	(set-variable 'indent-tabs-mode nil)
    	(define-key py-mode-map (kbd "RET") 'newline-and-indent)
    	;(define-key py-mode-map [tab] 'yas/expand)
    	;(setq yas/after-exit-snippet-hook 'indent-according-to-mode)
    	(smart-operator-mode-on)
    	))
    ;; pymacs
    (autoload 'pymacs-apply "pymacs")
    (autoload 'pymacs-call "pymacs")
    (autoload 'pymacs-eval "pymacs" nil t)
    (autoload 'pymacs-exec "pymacs" nil t)
    (autoload 'pymacs-load "pymacs" nil t)
    ;;(eval-after-load "pymacs"
    ;;  '(add-to-list 'pymacs-load-path YOUR-PYMACS-DIRECTORY"))
    (pymacs-load "ropemacs" "rope-")
    (setq ropemacs-enable-autoimport t)
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;;; Auto-completion
    ;;;  Integrates:
    ;;;   1) Rope
    ;;;   2) Yasnippet
    ;;;   all with AutoComplete.el
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    (defun prefix-list-elements (list prefix)
      (let (value)
        (nreverse
         (dolist (element list value)
          (setq value (cons (format "%s%s" prefix element) value))))))
    (defvar ac-source-rope
      '((candidates
         . (lambda ()
             (prefix-list-elements (rope-completions) ac-target))))
      "Source for Rope")
    (defun ac-python-find ()
      "Python `ac-find-function'."
      (require 'thingatpt)
      (let ((symbol (car-safe (bounds-of-thing-at-point 'symbol))))
        (if (null symbol)
            (if (string= "." (buffer-substring (- (point) 1) (point)))
                (point)
              nil)
          symbol)))
    (defun ac-python-candidate ()
      "Python `ac-candidates-function'"
      (let (candidates)
        (dolist (source ac-sources)
          (if (symbolp source)
              (setq source (symbol-value source)))
          (let* ((ac-limit (or (cdr-safe (assq 'limit source)) ac-limit))
                 (requires (cdr-safe (assq 'requires source)))
                 cand)
            (if (or (null requires)
                    (>= (length ac-target) requires))
                (setq cand
                      (delq nil
                            (mapcar (lambda (candidate)
                                      (propertize candidate 'source source))
                                    (funcall (cdr (assq 'candidates source)))))))
            (if (and (> ac-limit 1)
                     (> (length cand) ac-limit))
                (setcdr (nthcdr (1- ac-limit) cand) nil))
            (setq candidates (append candidates cand))))
        (delete-dups candidates)))
    (add-hook 'python-mode-hook
              (lambda ()
                     (auto-complete-mode 1)
                     (set (make-local-variable 'ac-sources)
                          (append ac-sources '(ac-source-rope) '(ac-source-yasnippet)))
                     (set (make-local-variable 'ac-find-function) 'ac-python-find)
                     (set (make-local-variable 'ac-candidate-function) 'ac-python-candidate)
                     (set (make-local-variable 'ac-auto-start) nil)))
    ;;Ryan's python specific tab completion
    (defun ryan-python-tab ()
      ; Try the following:
      ; 1) Do a yasnippet expansion
      ; 2) Do a Rope code completion
      ; 3) Do an indent
      (interactive)
      (if (eql (ac-start) 0)
          (indent-for-tab-command)))
    (defadvice ac-start (before advice-turn-on-auto-start activate)
      (set (make-local-variable 'ac-auto-start) t))
    (defadvice ac-cleanup (after advice-turn-off-auto-start activate)
      (set (make-local-variable 'ac-auto-start) nil))
    (define-key py-mode-map "t" 'ryan-python-tab)
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;;; End Auto Completion
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Auto Syntax Error Hightlight
    (when (load "flymake" t)
      (defun flymake-pyflakes-init ()
        (let* ((temp-file (flymake-init-create-temp-buffer-copy
    		       'flymake-create-temp-inplace))
    	   (local-file (file-relative-name
    			temp-file
    			(file-name-directory buffer-file-name))))
          (list "pyflakes" (list local-file))))
      (add-to-list 'flymake-allowed-file-name-masks
    	       '(".py'" flymake-pyflakes-init)))
    (add-hook 'find-file-hook 'flymake-find-file-hook)
    (provide 'init_python)
    
  8. 在你的.emacs文件中添加:(load-library “init_python”)

使用说明

  1. 代码自动展开。比如说在编辑C/C++头文件的时候键入once然后按tab,则会自动展开#ifndef __FILE_H__这样的宏。这个功能是YASnippet提供的,在emacs的菜单中可以看到它的所有宏。展开以后再按tab键可以在已展开的代码之间切换位置。
  2. 自动完成代码。函数名输入到一半按tab键会调用Rope和Ropemacs的功能自动完成库文件中的函数、变量名
  3. C-c d 显示python的doc string
  4. C-c C-c 运行当前的文件
  5. C-c ! 打开python shell

事实上init_python.el做的事情是通过使用auto_complete.el中的功能,把YASnippet和Rope的功能结合到了一块儿,实现了类似TexMate的自动完成等功能。其中YASnippet可以自定义模板,很是实用。Rope的功能还在研究中。