この記事はEmacs Advent Calendar 2023の11日目の記事です。
こんにちは。 一昨年のEmacs Advent Calendar 2021の私の記事では、Emacsでlsp-modeを用いたPython開発環境を記載しました。
しかし、この2年で開発環境に変化がありましたので、2023年度版ということで記載します。 大きな違いはlsp-modeからEglotに変わったこととRuffを使い始めたことです。 一昨年の記事と被る部分も多くありますが、この記事だけでEmacsの設定を完結できるように重複部分も記載しておきます。
Python自体の開発環境 #
まず、Python自体の開発環境は、mise、pipx、poetryを用いて構築します。これらによって、プロジェクトごとに開発環境を分離しています。 特にmiseは作業プロジェクトのみに自動的に環境変数を設定(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がインストールされると、Eglotで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ユーザに幸あれ!
謝辞 #
今回紹介させていただいたパッケージ及び紹介できなったパッケージの作者様、設定ファイルを公開してくださっている方々、いつもありがとうございます。 不都合等ありましたら、コメント等でご連絡いただけますと幸いです。