【Emacs】Pythonを書く設定2024下半期

Pythonを書くためのEmacsの設定は常にアップデートしている.

reformatter および ruff-format をインストールする. これ以外にもtempelの設定もしてある.tempelについては以下の記事にて.

当然,入力補完にはcorfuを使っている.

補完候補のフィルタリングにはhotfuzzを使っている.

dabbrev系にはhippie-expandも欠かせない.

ちなみにシンタックスハイライトをいい感じにするためにtree-sitterを導入している(python-ts-mode). M-x treesit-install-language-grammar から "python" と入力し,あとはenter連打(デフォルト設定)でOKだと思われる.

eglotの動作をさらに高速にするために,lsp-boostereglot-boosterを取り入れている.

カッコの挙動をいい感じに扱うための smartparens はお好みで.

Eglotでは:hoverProviderをオフにしない限り、カーソル下のシンボルやメソッドなどに対してエコーエリアに何かしらの補助情報が表示されるのでありがたいが、表示が複数行に渡りうるのでとてもうっとうしい(ウィンドウ下部を侵食する)。そこで普段はこれをエコーエリア1行表示に抑制し、詳細が見たくなったらeldocコマンドでチラ見する。shackle-mode によりポップアップウィンドウの挙動を制御するのが良い("eldoc"バッファ)。

いずれにせよ、eglotによるカーソル下のシンボルハイライトは必要なかったので、サーバーレスポンス軽量化のためにも :documentHighlightProvider はオフにした。ちなみにbasedpyrightは型ヒントのインライン表示もやってくれるが、不要なときは :inlayHintProvider をオフにすればOK。

上記の記事以外の設定はこんな感じに落ち着いた.python用のlanguage-serverはpyrightを使っている.

(setq gc-cons-threshold 16777216)
(setq read-process-output-max (* 1024 1024))
(add-to-list 'major-mode-remap-alist '(python-mode . python-ts-mode))
(add-hook 'python-ts-mode-hook #'eglot-ensure)

;; 保存時にruffでformatするマイナーモード
(add-hook 'python-ts-mode-hook 'ruff-format-on-save-mode)

(reformatter-define ruff-sort-imports
  :program "ruff"
  :args (list "check" "--fix" "--select" "I001" "--stdin-filename"
              (or (buffer-file-name) input-file))
  :group 'python)
;; 保存時にruffでimport順をソートするマイナーモード
(add-hook 'python-ts-mode-hook #'ruff-sort-imports-on-save-mode)

;; ruffによってfixをかけるコマンドやマイナーモードを導入
(reformatter-define ruff-fix
  :program "ruff"
  :args  (list "check" "--fix" "--stdin-filename"
               (or (buffer-file-name) input-file))
  :group 'python)

;; for eglot
(add-hook 'eglot-managed-mode-hook
          #'(lambda ()
              (flymake-ruff-load) ;; ruffのlint結果をflymakeで拾うためのパッケージ
              (require 'eglot-booster)
              (eglot-booster-mode t)))

(add-hook 'emacs-startup-hook
          #'(lambda ()
              (setq jsonrpc-default-request-timeout 3000)
              (fset #'jsonrpc--log-event #'ignore)))

(with-eval-after-load "eglot"
  (setq eglot-ignored-server-capabilities ;; eglotで無効にする機能を追加
        '(:documentHighlightProvider ;; カーソル下のシンボルハイライト
          :inlayHintProvider ;; インラインのヒント表示 (basedpyright)
          )))

;; エコーエリアの使用を強制的に1行にする
(setq eldoc-echo-area-use-multiline-p nil)

;; chileframeを使ってhover内容をカーソル位置に表示する(=VSCodeの挙動に近くなる) お好みで
;; (add-hook 'eglot-managed-mode-hook
;;           #'(lambda ()
;;               (eldoc-box-hover-at-point-mode)
;;               (setq eldoc-box-lighter "")
;;               (setq eldoc-box-max-pixel-height 300)
;;               (setq eldoc-box-max-pixel-width 500)
;;               (setq eldoc-box-only-multi-line t)))

;; for consult
(with-eval-after-load 'consult-imenu
  (add-to-list 'consult-imenu-config
               '(python-ts-mode
                 :toplevel "Function"
                 :types
                 ((?f "Function" font-lock-function-name-face)
                  (?m "Method" font-lock-function-name-face)
                  (?c "Class" font-lock-type-face)
                  (?v "Variable" font-lock-variable-name-face)))))
(with-eval-after-load 'consult-eglot
  (consult-eglot-embark-mode))

;; for smartparens
(add-hook 'emacs-startup-hook
          #'(lambda ()
              (smartparens-global-mode +1)
              (electric-pair-mode -1)
              (require 'smartparens-config)))

;; インデントをハイライトするパッケージ お好みで
;; (add-hook 'python-ts-mode-hook #'(lambda ()
;;                                    (highlight-indentation-mode +1)))