iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 8
0
Software Development

Emacs 來寫程式系列 第 8

[Emacs-8] 程式自動補全套件 : Company-mode

關於程式補全 (Code Complete)

  • 程式補全在編輯程式時是相當重要的功能之一,它可以提醒目前可以使用的變數或函數的名稱,避免寫錯名稱造成的臭蟲,更可以在使用長的變數時不怕打錯,節省打鍵盤時間
  • 一個聰明的程式補全能夠讓軟體工程師的事半功倍,例如在 javascript 裡,打完 this.,可以帶出目前可用的物件變數及方法 (method), js
  • 也可以帶出系統內建的方法 (method),如果有太多的選項,可以打前面的字來選擇需要的函數,例如 doc
  • 在 Emacs 的環境裡有一些程式補全套件次模式,例如內建的 auto-complete company... 等等,這裏我們介紹 company 這個套件

Company: Complete Anything

  • company-mode 是一個可以擴充前端,後端的套件,前端負責使用者介面的部分,後端管理可以選用的字串
  • 內建一些後端,例如 elisp, Clang, CMake, files, keyword, capf... 等等,很多的第三方後端可以選擇,例如 c/c++ 使用 irony, rtagsPython 使用 Python 使用 Jedijavascript 使用 微軟的 tsserver,也可以使用 lsp 等等,可以說比起一般常用的 VS Code, Atom, Sublime Text 一點都不遜色

安裝

(use-package company
  :ensure t
  :config
  (global-company-mode t)
  (setq company-idle-delay 0)
  (setq company-minimum-prefix-length 3)
  (setq company-backends
        '((company-files
           company-keywords
           company-capf
           company-yasnippet
           )
          (company-abbrev company-dabbrev))))
  • 設定為全區使用的次模式,設定 company-idel-delay0,如果怕太吃 CPU,可以設定例如 0.3,設定 company-minimum-prefix-length3,至少打完三個字才啟動,預設的 company-backends(company-files company-keywords company-capf company-yasnippet)(company-abbrev company-dabbrev)
  • 可以使用多個後端,後端可以設群組,像上面就是設定兩個群組,啟動後會向第一個群組詢問,全部都會問到,如果有搜尋的的字串,會全部都返回前端顯示
  • company-backends 可以在不同的主模式下設定不同的值,例如
(add-hook 'emacs-lisp-mode-hook (lambda () 
            (add-to-list (make-local-variable 'company-backends) 
            '(company-elisp))))
  • 會在 emacs-lisp 模式下加入 company-elisp,可以使用 Ctrl-h v company-backends 顯示目前的設定值 elisp
  • 上面的設定,可以在 Emacs-Lisp 下完成自動補全,例如 company
  • 而因為使用 add-to-list,原先的預設會設為第二順序跟第三順序,例如要載入檔案,會使用到 company-files 後端 company-files
  • 要查看目前使用的後端,可以用 M-x company diag來看,例如剛剛的例子 backend
  • 它會顯示目前所有後端 ((company-elisp)
    (company-files company-keywords company-capf company-yasnippet)
    (company-abbrev company-dabbrev))
  • 使用到的後端 (company-files company-keywords company-capf company-yasnippet) 以及根據目前的前面的字帶出來的字串
  • 如果你只要某個後端在某個主模式下運作,可以如下面這樣設定,這個例子這樣就只會有 company-elisp 作用,不過你就沒法使用像前面的 company-files
(add-hook 'emacs-lisp-mode-hook (lambda () 
            (set (make-local-variable 'company-backends) 
            '(company-elisp))))

選擇字

  • 在跳出來的選單上挑選字串時,預設會使用 Meta-nMeta-p 來移動游標,但這跟我們平常使用的習慣有點不同,我們可以來改一下設定
(with-eval-after-load 'company
  (define-key company-active-map (kbd "\C-n") #'company-select-next)
  (define-key company-active-map (kbd "\C-p") #'company-select-previous)
  (define-key company-active-map (kbd "M-n") nil)
  (define-key company-active-map (kbd "M-p") nil))
  • 使用 Ctrl-nCtrl-p 就像我們在主緩衝區使用的游標移動方式一樣

Company 跟 Yasnippet 的 [tab]鍵衝突

  • company-mode 使用 tab 鍵來做跳出來清單的補全,例如當你打入 compa 時,company-mode會建議補全的字用紅色顯示,這時用 tab 鍵就會自動補入 company,例如 compa
  • 但這會跟 yasnippet 衝突,因為 yasnippet 也是用 tab 鍵來展開程式片段
  • 假設定義了一個 yasnippet 的關鍵字(例如 comp),但因為 company-mode 啟動,無法使用 yasnipeet,例如 candy
  • 這時可以如此定義,這樣就可以使用 yasnippet 來展開 comp 的程式
(advice-add 'company-complete-common :before (lambda () 
                                (setq my-company-point (point))))
(advice-add 'company-complete-common :after (lambda () 
                                (when (equal my-company-point (point)) (yas-expand))))

相關影片請看 Yes

相關連結,請看我的部落格

相關程式,請看 Github,你可以直接下載 init.el 放在 ~/.emacs.d/ 下,啟動 Emacs 時會安裝這些套件跟設定


上一篇
[Emacs-7] 管理程式碼片段 (Snippet) 的 yasnippet 套件
下一篇
[Emacs-9] 程式語法檢查套件 : Flycheck
系列文
Emacs 來寫程式30

尚未有邦友留言

立即登入留言