2020年4月19日日曜日

Emacsで入力補完 その2

はじめに


先日の記事ではEmacsのcompany-modeの設定をしましたが、 CまたはC++を使う場合のプロジェクト内のヘッダファイルを検索対象にするために、ひと手間必要でした。

ここではそれを自動化するための設定をしてみます。

設定


プロジェクトルートを見つけるため、最初にProjectileをインストールします。
M-x package-install [Enter] projectile [Enter]
次に、~/.emacs.d/init.elに以下の内容を記載します。
(require 'company)
(global-company-mode t)
(define-key global-map (kbd "C-f") 'company-complete)
(setq company-backends '((company-clang company-dabbrev-code company-gtags)))

(require 'projectile)
(define-key projectile-mode-map (kbd "C-c p") 'projectile-command-map)
(projectile-mode +1)

;; Return a project root if it is found else a current directory                                                                                                  
(defun pproot () (let ((d (projectile-project-root))) (unless d (setq d ".")) d))

;; Find all include paths and set them to clang include path                                                                                                    
(defun set-company-clang-include-path ()
  (interactive)
  (setq company-clang-arguments
        (mapcar (lambda (x) (concat "-I" x)) ;; Make clang options to set include path                                                                          
                (seq-uniq (mapcar (lambda (x) (replace-regexp-in-string "/[^\/]*$" "" x)) ;; Extract directories                                                
                                  (directory-files-recursively (pproot) ".*\.\\(h\\|hpp\\)$")))))) ;; Find all header files
(defun set-company-clang-include-path-if-empty ()
  (unless company-clang-arguments (set-company-clang-include-path)))
(add-hook 'c++-mode-hook 'set-company-clang-include-path-if-empty)
(add-hook 'c-mode-hook 'set-company-clang-include-path-if-empty)
プロジェクトルート以下の.h/.hppをすべて検索するため、大きめのプロジェクトでは、 c-modeまたはc++-modeでファイルを開くと最初は時間がかかるかもしれません。

company-clang-argumentsを更新する場合は、M-x set-company-clang-include-pathを実行します。

2020年4月12日日曜日

Emacsで入力補完

はじめに


EmacsにIntellisenseっぽいものを導入してみます。

準備


Packageを使う準備ができていない場合は、
https://melpa.org/#/getting-started
に従って準備します。

設定ができたらemacsを立ち上げて、 M-x package-list-packages を実行します。

パッケージの一覧が表示されますので、companyの行へ移動します。なければ r を押してください。リストが更新されます。

companyの行へ移動できたら i を押します。すると、その行に I が表示され、インストール準備が完了した状態になります。

最後に x を押すとインストールしてよいかの確認の後、インストールされます。

使い方


emacsを立ち上げて、 M-x global-company-mode を実行すれば有効になります。

C++のファイルを開いているときにcompany-modeを有効にしようとして、もし、

Company backend ’company-clang’ could not be initialized:
Company found no clang executable
というエラーがでた場合は、clangがインストールされていないということなので、aptなどでclangをインストールします。

この状態でも使えるのですが、emacsを起動するたびにglobal-company-modeを有効にしなければならないので、 ~/.emacs.d/init.el に次の内容を追加しておきます。

(global-company-mode t)
(global-set-key (kbd "C-f") 'company-complete)
このようにすると、Ctrl+f で自動補完が動作するようになります。 カーソル移動にCtrl+fを使う人は別のキーに割り当てましょう。

C++のプロジェクト内で定義した関数等の補完


C++では、global-company-modeを有効にしただけでは標準の関数等に対してしか補完は行われません。 今まさに作っている最中のプロジェクト内のファイルに対する補完が効かないということです。これは、補完のために呼び出されるclangが読み込むべきファイルのパスを知らないためです。

そこで、プロジェクトのルートに次のような内容を記載した .dir-locals.el という名前のファイルを作成します。

((nil . ((company-clang-arguments . ("-I/path/to/include/"
                                     "-I/path/to/2nd/include/")))))
これで、指定したパスのファイル内で定義されている関数等は補完の対象になります。サブディレクトリを再帰的に見てくれるわけではないので注意が必要です。

なお、このファイルを作成すると、emacs起動時に

The local variables list in /path/to/include/ contains values that may not be safe (*).
と聞かれるようになってしまいます。設定値に文字列が入っていると聞いてくるようです。許可すればいいだけですが、ちょっと手間ですね。

まとめ


使えることは使えるのですが、プロジェクトごとにファイルを準備しないといけないため、 常用するにはもうひと工夫必要になりそうです。

参考


company の説明
http://company-mode.github.io/
http://emacs.rubikitch.com/company/
https://qiita.com/syohex/items/8d21d7422f14e9b53b17

emacs設定いろいろ
http://tuhdo.github.io/c-ide.html

clangが見つからないと言われたら
https://emacs.stackexchange.com/questions/19306/how-do-i-get-company-mode-to-recognize-clang

.dir-locals.el の説明
https://www.emacswiki.org/emacs/DirectoryVariables

bashのキーボード・ショートカット一覧
https://ss64.com/bash/syntax-keyboard.html