📝Clojure 開発環境 with Emacs

📝Clojure 開発環境 with Emacs

Clojure開発環境(IDE)としてのEmacs設定まとめ.

Emacs CIDER #

EmacsでClojure開発をするときのデファクトスタンダード.

Quick References #

よくつかうもの.

  • C-c l ' cider-jack-in REPL起動 & 接続
  • C-c C-zで REPL - Editor間を移動.
  • C-c C-c で現在の定義を評価.
  • C-c C-e でフォームの末尾の手前から評価.
  • C-c M-p で現在の定義をREPLに送信.
  • M-. 定義に移動.
  • C-c C-d C-d documentをみる.
  • jack-inしている状態で2charくらい打ち込んで C-iで補完候補がでる.
  • C-c M-i で cider-inspectorを起動, defの中身が別バッファに表示される.
  • C-c SPC: clojure-align, alignを自動整形.
  • Evaluation
    • M-x cider-pprint-last-eval-to-comment
      • 式の評価結果がコメントとして書かれる.
      • Design Journalとしては便利な機能かも.
      • C-u C-x C-e でも可能.
    • M-x cider-pprint-defun-to-comment
      • これはフォームの先頭で評価すると次の行に結果表示.
  • cider-repl-set-ns: namespaceをreplに設定.

cf. clojure-lsp #

CIDER同様のツールでclojure-lspというEmacsからClojureのLSPを使うためのEmacs Packageもある. 同じことはCIDERでもclojure-lspでもできるがclojure-lspのほうがCPU使用率が高いとか.

tips: cider-jack-inでカスタムの依存を設定 #

一応cider-jack-inをすると依存関係をよろしく解決してくれるが, productionに含めないdevelopmentの依存関係は自動で解決されない.

.dir-locals.elに cider-clojure-cli-global-optionsや cider-clojure-cli-aliasesに追加の設定を書く.

例えば, deps.ednのaliasに :devのような定義があれば,

((clojure-mode . ((cider-clojure-cli-aliases . "dev"))))

ref: Practicalli: CIDER jack-in to Clojure CLI projects from Spacemacs

tips: REPLの履歴をつかう(cider-repl-history) #

REPLに入力したフォームはM-pで遡ることができる.

また C-c M-p(cider-repl-history)で過去の履歴をリスト表示できる.

tips: 変数定義の中身をみる(cider-inspect) #

C-c C-eでフォームを評価して中身をみるのもいいが, ciderには cider-inspectという機能がある.

これを調べたい変数の上で実行(C-c M-i)すると, 別バッファに中身が表示される.

tips: 関数の定義を参照する(Find References) #

関数を呼び出してる参照元を一覧表示して移動する.

  • cider-xref-fn-refs (C-c C-? r)
  • cider-xref-fn-refs-select (C-c C-? C-r)

LSPのように静的解析ではないので若干時間かかる. C-?はボタン押しにくいかも, Ctrl+Shiftが必要.

似たような機能で以下もある. ソースを参照せずにdocのみ見たい場合にrefよりも高速に検索が終わる.

  • cider-xref-fn-deps (C-c C-? d)
  • cider-xref-fn-deps-select (C-c C-? C-d)

ref. CIDER Docs


ソースコードの規模によるかもしれないが, projectile + ripgrepのほうが検索が速いかも.

M-x cljr-find-usageがciderのxrefよりも高速で動作する. こっちがいい.このreferenceに関してはciderはおそすぎる. LSPとの併用がいいかも. しかしそもそも利用しているPCがボロいことが原因かも. お金溜まったら新しいPC買ってLSPも導入したい. ソレまで我慢.

tips: cider-clojuredocsの活用 #

cider-clojuredocsをすると別バッファで clojuredocs 内の関数定義を参照できる.

Clojureの初学ではライブラリをGoogleで検索することが多い. cider-clojuredocsをつかう習慣を心がけることで, マージン時間の削減につながる.

tips: cider-connectでのport固定 #

固定ポート自体はnREPLのオプションから指定.

:main-opts ["-m" "nrepl.cmdline"
            "-b" "0.0.0.0"
            "-p" "12345"
            "--middleware" "[cider.nrepl/cider-middleware,refactor-nrepl.middleware/wrap-refactor]"]

cider-connectの接続先の候補に固定したportを表示する(ref).

(setq cider-known-endpoints '(("localhost" "0.0.0.0" "12345")))

tips: REPLでたくさん出力してEmacsフリーズを防ぐ #

(setq cider-print-quota 1024)

ref. Pretty-printing :: CIDER Docs

Emacs smartparens #

https://github.com/Fuco1/smartparens

EmacsでS式を操作する.

pareditよりもsmartparensのほうが最近登場したようなのでこちらをつかう.

doom emacsの default設定

  • (, [, {などで自動で閉じカッコが挿入される.
  • block movement
    • ()の中で)を入力すると,現在の)の末尾に飛ぶ.
    • []の中で]を入力すると,現在の]の末尾に飛ぶ.
  • Navigation
    • C-M-a: sp-beggining-of-sexp 現在のS式の先頭へ移動.
    • C-M-e: sp-end-of-sexp現在のS式の末尾へ移動.
    • C-M-f: sp-forward-sexp 次のS式に移動
    • C-M-b: sp-backward-sexp 前のS式に移動
    • C-M-n: sp-next-sexp
    • C-M-p: sp-previous-sexp
    • C-M-u: sp-up-sexp 現在のS式のひとつ外側のS式の末尾へ移動.
    • C-M-d: sp-donw-sexp 現在のS式のひとつ内側のS式の先頭へ移動.
    • C-M-k: sp-kill-sexp 現在のS式の内側を削除.
    • C-M-t: sp-transpose-sexp
  • wrapping/unwrapping
    • C-M-Spaceで現在の部分からwordの末尾までをマーク.
      • (とか[でマークした部分を囲む.
    • C-M-: sp-splice-sexp
      • 現在の部分の前のS式もろとも削除.

この5つを覚えるだけで、作業効率が上がりおすすめされている.

  • Slurp (隣の括弧を吸い込む)
  • Barf (括弧を追い出す)
  • カット (括弧単位でのカット)
  • コピー (括弧単位でのコピー)
  • 削除 (括弧を丸ごと消す)

ref: いまどきのClojureのはじめかた - 紙箱

refs:

Doom Emacs Clojure Module #

hlissner/doom-emacs · GitHub

以下の3つのパッケージこ梱包されている.

  • cider
  • clj-refactor
  • flycheck-clj-kondo

Clojure: 文芸的プログラミング with org-babel #

org-modeのノート上からREPLにjack-inしてコードを評価. すなわち, Design Journal を org-modeから実施する (aka. Literature Programming).

header options #

  • begin_src clojureを指定してorg-babelにclojureを設定.
  • :results ppをすることで結果をpretty print
    • valueという評価結果を表示する指定はdefaultのため省略されている.
  • :ns fooを宣言すると, 起動時のnamespaceを設定できる.
    • resultは指定した nsにbindされる.
#+begin_src clojure :results pp
(require '[lib.twitter.guest :as guest])
(guest/get-user "richhickey")
#+end_src

org-babel実行 #

  • まず事前にREPLを立ち上げておく.
  • C-c C-c を実行することでコードを評価.
    • cider-jack-in or cider-connectの選択を求められる.
    • 事前に立ち上げておいたREPLにcider-connect

tips: org-modeでclojureコードを評価 #

通常は M-x org-edit-src-codeでコード編集だが, org-modeから編集するTips.

org-babel で 実行したい言語としてclojureをenable. デフォルトでは emacs-lisp だけ.

  (org-babel-do-load-languages
   'org-babel-load-languages
   '((lisp . t)
     (shell . t)
     (clojure . t)))

これで code blockに関わらずclojureがかける. 評価はorg-modeではC-x C-eがemacs-lispの評価に取られているので, 別のkeybindを設定する.

(org-defkey org-mode-map "\C-u\C-x\C-e" 'cider-eval-last-sexp)

References #