Eglot でのPython開発環境
この記事は Emacs Advent Calendar 2023 の11日目の記事です。
こんにちは。 一昨年の Emacs Advent Calendar 2021 の私の記事では、Emacsで lsp-mode を用いたPython開発環境を紹介しました。
しかし、この2年で開発環境に変化がありましたので、2023年度版ということで紹介していきます。 大きな違いは lsp-mode から Eglot に変わったことと Ruff を使い始めたことです。 一昨年の記事と被る部分も多くありますが、この記事だけで Emacs の設定を完結できるように重複部分も記載しておきます。
少しでも読んだ方の参考になると嬉しいです。
Python自体の開発環境
まず、Python自体の開発環境は、rtx、pipx、poetry を用いて構築します。これらによって、プロジェクトごとに開発環境を分離しています。 特に rtx は 作業プロジェクトのみに自動的に環境変数を設定(direnvと同様の設定)ができるので、大変重宝しています。
Emacs での開発環境
では、本題の Emacs での開発環境です。 Python を Emacs で快適に書くために、以下のパッケージを導入してます。
Emacsパッケージ | 概要 |
---|---|
smartparens | 括弧等のペアの処理 |
rainbow-delimiters | 対応する括弧の強調表示 |
highlight-indent-guides | インデントの強調表示 |
whitespace-mode | 空白の可視化 |
treesit-auto | Tree-sitter を便利に使うためのパッケージ |
mwim | 行頭・行末移動の拡張 |
Tempel | テンプレートの挿入 |
Corfu | 入力補完用パッケージ |
nerd-icons | Nerd Icons を扱うためのパッケージ |
Eglot | lsp を利用するためのクライアントパッケージ |
Flymake | 構文チェッカー |
flymake-ruff | Ruff の解析結果を flymake へ受け渡し |
emacs-reformatter | カレントバッファの reformatter |
ruff-fix | 自分用に作ったRuffのカレントバッファの linter |
では、具体的に各パッケージの説明と設定を紹介します。
smartparens
smartparens は、括弧等のペアを処理するためのマイナーモードです。 以下のようにデフォルト設定を有効化すると、「モードに合った括弧の自動補完」や「選択範囲を括弧等のペアでラップ」等ができるようになります。 色々機能があるので、詳細は公式サイトをご覧ください。
(use-package smartparens
:ensure t
:delight
:hook (after-init-hook . smartparens-global-strict-mode)
:custom
(electric-pair-mode nil)
:config
(require 'smartparens-config))
私は、上記でstrictモードを有効化して、括弧等のペアが崩れないように強制しています。
例えば、strictモードを有効にすると、以下のように hoge の末尾で C-k
を押下した場合、hoge の末尾以降がすべて削除されずに )
が残り、括弧のペアを維持してくれます。便利!
(hoge huga)
↓
(hoge)
rainbow-delimiters
rainbow-delimiters は、対応する括弧を強調表示するマイナーモードです。 以下の設定をすることで、対応する括弧を色分けして表示できますので、対応関係を視認しやすくなります。
(use-package rainbow-delimiters
:ensure t
:hook ((prog-mode-hook . rainbow-delimiters-mode)))
highlight-indent-guides
highlight-indent-guides は、インデントの位置を強調表示するマイナーモードです。 どのように強調表示されるかは公式サイトのスクリーンショットをご覧ください。 特に Python は indent位置が重要になりますので、重宝しています。
(use-package highlight-indent-guides
:ensure t
:delight
:hook ((prog-mode-hook yaml-mode-hook) . highlight-indent-guides-mode)
:custom
(highlight-indent-guides-method 'character)
(highlight-indent-guides-auto-enabled t)
(highlight-indent-guides-responsive t)
(highlight-indent-guides-character ?\|))
whitespace-mode
whitespace-mode は、スペースやタブなどの空白を表示するマイナーモードです。また、不要なスペースやタブの削除も可能です。
設定は@itiut@github様のqiita記事を参考に、以下のように設定しています。
以下では、C-c W
の押下で不要なスペースやタブを明示的に除去するとともに、特定のモード(dired-mode, tar-mode, magit-mode)以外は保存時に自動的に不要なスペースやタブを除去しています。
(use-package whitespace
:ensure t
:demand t
:delight
:bind ("C-c W" . whitespace-cleanup)
:custom
(whitespace-style '(face trailing tabs spaces empty space-mark tab-mark))
(whitespace-display-mappings '((space-mark ?\u3000 [?\u25a1])
(tab-mark ?\t [?\u00BB ?\t]
[?\\ ?\t])))
(whitespace-space-regexp "\\(\u3000+\\)")
(whitespace-global-modes '(not dired-mode tar-mode magit-mode))
(global-whitespace-mode t)
(whitespace-action '(auto-cleanup))
:config
(set-face-attribute 'whitespace-trailing nil
:background "Black"
:foreground "DeepPink"
:underline t)
(set-face-attribute 'whitespace-tab nil
:background "Black"
:foreground "LightSkyBlue"
:underline t)
(set-face-attribute 'whitespace-space nil
:background "Black"
:foreground "GreenYellow"
:weight 'bold)
(set-face-attribute 'whitespace-empty nil
:background "Black"))
treesit-auto
Emacs 29から標準で Tree-sitter を利用してシンタックスハイライトができるようになりました。
しかし、Tree-sitter を有効するためには、言語に対応するパーサのインストール及び従来の python-mode
ではなく ptyhon-ts-mode
への変更が必要になります。
treesit-auto は Tree-sitter のメジャーモードを統合してくれます。具体的には、Tree-sitterが利用可能なモードの場合にパーサのインストール及びモードへの切り替えを行ってくれます。
(use-package treesit-auto
:ensure t
:custom
(treesit-font-lock-level 4)
:config
(setq treesit-auto-install 'prompt)
(global-treesit-auto-mode))
mwim
mwim は、コードの先頭・末尾への移動と行頭・行末への移動を行うコマンドを提供します。
実際の動作は公式サイトのスクリーンショットをご参照ください。
私は C-a
と C-e
に割り当てて、行頭・行末への移動を拡張しています。
(use-package mwim
:ensure t
:bind (("C-a" . mwim-beginning-of-code-or-line)
("C-e" . mwim-end-of-code-or-line)))
Tempel
Tempel は、テンプレートの挿入を提供しているパッケージです。
テンプレートは各自で設定しますが、tempel-collection というテンプレートのコレクションもあります。
例えば、私は ifm
から if __name__ == '__main__':
が展開されるようにしています。
テンプレートの候補は後述する Corfu で補完対象として表示しています。
(use-package tempel
:ensure t
:init
(defun tempel-setup-capf ()
(setq-local completion-at-point-functions
(cons #'tempel-complete
completion-at-point-functions)))
(add-hook 'prog-mode-hook 'tempel-setup-capf)
(add-hook 'text-mode-hook 'tempel-setup-capf)
(add-hook 'org-mode-hook 'tempel-setup-capf))
Corfu
Corfu は、Emacs の入力補完用のパッケージです。
Corfu 単体でも入力補完が可能ですが、私は Capeと Tempel で補完候補とテンプレートを追加しています。また、Corfu は GUI版Emacsのみで使用できるので、私はターミナル上でも利用できるように corfu-terminal も使用しています。
(use-package corfu-terminal
:ensure t
:if (not (display-graphic-p))
:config
(corfu-terminal-mode +1))
(use-package corfu
:ensure t
:custom ((corfu-auto t)
(corfu-auto-prefix 1)
(corfu-auto-delay 0)
(corfu-cycle t))
:init
(global-corfu-mode)
(corfu-popupinfo-mode))
(use-package cape
:ensure t
:init
;; Add `completion-at-point-functions', used by `completion-at-point'.
(add-to-list 'completion-at-point-functions #'cape-file)
(add-to-list 'completion-at-point-functions #'cape-dabbrev)
;; (add-to-list 'completion-at-point-functions #'cape-history)
(add-to-list 'completion-at-point-functions #'cape-keyword)
;; (add-to-list 'completion-at-point-functions #'cape-tex)
;; (add-to-list 'completion-at-point-functions #'cape-sgml)
;; (add-to-list 'completion-at-point-functions #'cape-rfc1345)
;; (add-to-list 'completion-at-point-functions #'cape-abbrev)
;; (add-to-list 'completion-at-point-functions #'cape-ispell)
;; (add-to-list 'completion-at-point-functions #'cape-dict)
;; (add-to-list 'completion-at-point-functions #'cape-symbol)
;; (add-to-list 'completion-at-point-functions #'cape-line)
)
nerd-icons
Emacs でアイコンを使う場合は、all-the-icons パッケージが有名です。しかし、GUI版Emacsでしか利用できません。
そこで、CUI版Emacsでもアイコンを使うために、Nerd Fonts のアイコンフォント(以下、nerd icons と記載)を使います。 まず、Nerd Fonts が含まれているフォント(PlemolJP や Cica)を インストール後に、Emacs でフォントを設定します。その後 nerd icons を呼び出してあげるだけです。
nerd icons を利用するためのパッケージとして、nerd-icons.el があります。GUI版でも使えますので、CUI版及びGUI版Emacsで統一的にアイコンを利用することができます。
以下の設定では、 Corfu の補完候補でも nerd icons を表示できるようにしています。
;; PlemolJP をデフォルトフォントに設定
(when (display-graphic-p)
(if (eq system-type 'darwin)
(add-to-list 'default-frame-alist '(font . "PlemolJP Console NF-18"))
(add-to-list 'default-frame-alist '(font . "PlemolJP Console NF-21"))))
;; nerd icon を扱えるように
(use-package nerd-icons :ensure t)
;; dired で nerd icon を表示
(use-package nerd-icons-dired
:ensure t
:hook (dired-mode-hook . nerd-icons-dired-mode))
;; completion で nerd icon を表示
(use-package nerd-icons-completion
:ensure t
:after marginalia
:config
(nerd-icons-completion-mode)
:hook (marginalia-mode-hook . #'nerd-icons-completion-marginalia-setup))
;; corfu で nerd icon を表示
(use-package nerd-icons-corfu
:ensure t
:after corfu
:config
(add-to-list 'corfu-margin-formatters #'nerd-icons-corfu-formatter))
Eglot
Eglot は、Emacsのlspクライアントの一つです。Eglot は Emacs 29 からビルトインされています。
Eglot とこれまで設定してきた他のパッケージを上手く統合すると、Emacs が IDE のように動作します。 以下設定では、Eglot 起動時に Tempel のテンプレートと Eglot の補完候補を Corfu で同時に表示するようにしています。
(use-package eglot
:bind (nil
:map eglot-mode-map
("C-c a" . eglot-code-actions))
:config
(defun my/eglot-capf ()
(setq-local completion-at-point-functions
(list (cape-super-capf
#'tempel-complete
#'eglot-completion-at-point)
#'cape-keyword
#'cape-dabbrev
#'cape-file)
))
(add-hook 'eglot-managed-mode-hook #'my/eglot-capf))
Flymake
Flymake は Emacs にビルトインされている構文チェッカーです。今回は Eglot での解析結果が渡されています。併せて、Flymake の拡張として、以下を導入しています。
- flymake-diagnostic-at-point: エラー等をエコーエリアではなく、カーソル位置に表示
(use-package flymake
:ensure t
:bind (nil
:map flymake-mode-map
("C-c C-p" . flymake-goto-prev-error)
("C-c C-n" . flymake-goto-next-error))
:config
(set-face-background 'flymake-errline "red4")
(set-face-background 'flymake-warnline "DarkOrange"))
(use-package flymake-diagnostic-at-point
:ensure t
:after flymake
:config
(add-hook 'flymake-mode-hook #'flymake-diagnostic-at-point-mode)
(remove-hook 'flymake-diagnostic-functions 'flymake-proc-legacy-flymake))
Ruff
Ruff は Rust で書かれた高速なPython用の linter & code formatter です。 Ruff の設定に関しては、別記事にまとめていますので、Emacs から Ruff を使う を参照いただければと思います。
上記の記事では、Ruff を Emacs で使うために、以下のパッケージを導入しています。
- flymake-ruff: Ruff の解析結果(Linter の結果)を flymake に渡す
- emacs-reformatter: code formatter を カレントバッファに適用する
- ruff-fix: Ruff の Linter の修正をカレントバッファに適用する
ここまでで、 Emacsパッケージの設定は完了です。
pyright
最後に、lsp(Language Server Protocol) を利用するための language server です。 Python向けの language server の選択肢は、有名所として以下のものがあります。
- pyright(インストールに nodejs が必要)
- python-lsp-server(Jedi が必要)
私は以前 Jedi を使用していたのですが、今は毛色が異なる pyright を利用します。
pyrightのインストール
まず、nodejs が必要となるので、nodejs をインストールしておきます。 nodejs のインストール方法は色々な記事があると思いますので、そちらを参照いただければと思います。
nodejs がインストールされていれば、以下コマンドで pyright をインストールします。
npm install -g pyright
pyright がインストールされると、 elgot で pythonファイルを編集時に自動的に pyright に接続してくれます。
Emacs での Python の設定は以下の通りにしています。
(use-package python
:custom (python-indent-guess-indent-offset-verbose . nil)
:hook (python-ts-mode-hook . eglot-ensure))
このpython開発環境でできること
以上で、必要なパッケージのインストールと各種設定が完了しました。 ここまでインストールした各パッケージには色々な機能がありますが、私がよく使う機能/コマンドを少しだけ紹介します。
-
テンプレート挿入
Tempel でテンプレートを挿入しています。
if __name__ == '__main__'
はよく忘れるので、ifm
でテンプレート挿入でき便利です。 -
入力補完 Corfu が Eglot からの補完候補を表示します。 1文字から補完を開始し、Tempel のテンプレートも補完対象としています。
-
定義ジャンプ
M-. (xref-find-definitions)
カーソル上のシンボル(クラス名や関数名等)の定義先に移動します。M-? (xref-find-references)
カーソル上のシンボルを呼び出している箇所の候補を表示して、選択後に移動します。M-, (xref-pop-marker-stack)
M-.
やM-?
で移動した先から移動前の場所に戻ります。
-
構文チェック Flymake を通して、pyright と ruff で動的に構文がチェックします。
-
リファクタリング 保存時に以下を自動で行います。
- アクティブなバッファのimport順を整理します。
- アクティブなバッファに Ruff の linter と code formatter を適用します。
- アクティブなバッファの不要なスペースやタブを除去します。
終わりに
ここまで、読んでいただき、ありがとうございます。 これで一通りの Eglot でのPython開発環境を構築できました。 今回の設定を含む私のEmacsの設定がありますので、よろしければ参考にしてください。
それでは、すべてのEmacsユーザに幸あれ!
謝辞
今回紹介させていただいたパッケージ及び紹介できなったパッケージの作者様、設定ファイルを公開してくださっている方々、いつもありがとうございます。 不都合等ありましたら、コメント等でご連絡いただけますと幸いです。