1. ホーム
  2. emacs

[解決済み] ClojureのためのEmacs/Swank/Pareditのやさしいチュートリアル

2023-04-13 08:52:23

質問

私はEmacsに移行して Clojure /Lispに取り組むためにEmacsに移行します。 Emacsで以下のことができるようにするために必要な情報は何でしょうか?

  1. 対応する閉じ括弧の自動マッチング/生成
  2. C++/Javaスタイルではなく、Lisp/Clojureスタイルの自動インデント
  3. シンタックスハイライト
  4. 起動 REPL
  5. ファイルからREPLにコードの一部をロードし、評価できるようにする。

Emacsで設定した後、これらを取得するためのコマンド一覧も頂けるとありがたいです。

どのように解決するのですか?

[非著者からの編集: これは2010年のもので、2011年5月以降、プロセスは大幅に簡素化されました。2012年2月現在の私の設定メモをこの回答に追加します]。

いくつかの部品をまとめる必要があります。Emacs、SLIME (Clojureと完璧に動作します -- swank-clojureを参照)、swank-clojure (SLIMEのサーバー対応部分のClojure実装)、clojure-mode、Paredit、そしてもちろんClojure jar、それからおそらくLeiningenが最も顕著であるいくつかの特別なもの、です。 一度それをすべてセットアップすると、Emacsの中で、あなたが質問で言及したすべてのワークフロー/編集機能を持つことになります。

基本的な設定です。

以下は、これらすべての設定方法を説明した素晴らしいチュートリアルです。Web には他にもありますが、他のいくつかはかなり古く、今のところこの 2 つで大丈夫なようです。

  1. には、clojureのオーサーシップに関するトリックがあります。 Philはswank-clojureとclojure-mode、そしてEmacs Starter Kitと呼ばれるパッケージを管理しており、Emacsの世界に入ったばかりの人は見ておくとよいでしょう。これらの手順は、インフラストラクチャへの最近の変更に伴って更新されているようです。疑わしい場合は、ClojureのGoogleグループで追加情報を探してください。

  2. Clojure、Incanter、Emacs、Slime、Swank、Pareditのセットアップ Incanterプロジェクトのブログへの投稿です。Incanterは、Clojureに組み込まれた統計計算のためのRライクなDSLを提供する、魅力的なパッケージです。この投稿は、Incanterを使用する予定がなくても、あるいはインストールする予定がなくても、役に立つことでしょう。

すべてを実行に移す。

これらのものをすべてセットアップしたら、すぐに使い始めてみることもできますが、次のことを行うことを強くお勧めします。

  1. SLIME のマニュアルを見てください -- それはソースに含まれていて、実際にとても読みやすいです。また、あなたが を読む必要はありません。 どのような機能が利用できるかを見るために見て回るだけです。

    注意してください。 最新の上流ソースにあるようなSLIMEのautodoc機能はswank-clojureと互換性がありません。 -- Phil Hagelbergの推奨するELPAバージョンを使うか(説明については彼の前述のブログポストを参照)、単にautodocをオフにする(これがデフォルトの状態です)ことに従えば、この問題は生じないでしょう。後者のオプションには、Common Lisp で最新の SLIME を使用できるという魅力もあります。

  2. pareditのドキュメントを見てください。これには2つの方法があります。(1) ソースを見る -- ファイルの先頭に膨大な量のコメントがあり、あなたが必要とするであろうすべての情報が含まれています。 C-h m バッファに現在のメジャーモードの情報が表示され、その後にすべてのアクティブなマイナーモード(pareditはそのうちの1つ)の情報が表示されます。

    更新しました。 私はちょうど見つけた このクールなノートのセット を見つけました。これはテキストファイルへのリンクで、この情報を含む素晴らしいスライドのセットをどこかで見た記憶があるのですが、今は見つけられそうにありません。とにかく、どのように機能するのかがよくまとめられています。私は今、Pareditなしでは生きていけませんし、このファイルを見れば、とても簡単に使い始めることができると信じています。)

  3. 実際には C-h m の組み合わせは、clojureモードのSLIME REPLで有効な全てのキーバインドについて教えてくれます。 C-c C-k コンパイルのために現在のバッファを送るためにを覚えておくとよいでしょう)、そして実際にどのEmacsバッファでもです。

ファイルからコードをロードし、REPLでそれを実験するために、前述の C-c C-k の組み合わせで現在のバッファをコンパイルし、次に use または require という名前空間をREPLで指定します。次に、実験してみましょう。

最後のメモです。

すべてがうまくいくまで、しばらくの間、いろいろと調整する必要があることを覚悟してください。多くのツールが関与しており、それらの相互作用はほとんどかなりスムーズですが、最初に何らかの調整をする必要がないと考えても大丈夫なほどではありません。

最後に、私が保存しているコードの一部を紹介します。 .emacs に置いているコードで、他では見かけないものです (Phil Hagelberg のクールな関数に基づいていますが)。私は、この素敵なインスタンスを lein swank (Leiningen のクールな機能の 1 つ) を使うか、あるいは clojure-project 関数を使用してEmacsの中から全体を起動します。私は、後者が lein swank . ああ、もしあなたがただEmacsの中でREPLを使いたいだけなら、正しいセットアップをすれば M-x スライム を直接使うことができます。

(setq clojure-project-extra-classpaths
      '(
        ; "deps/"
        "src/"
        "classes/"
        "test/"
        ))

(setq clojure-project-jar-classpaths
      '(
        ; "deps/"
        "lib/"
        ))

(defun find-clojure-project-jars (path)
  (apply #'append
         (mapcar (lambda (d)
                   (loop for jar in (remove-if (lambda (f) (member f '("." "..")))
                                               (directory-files d t))
                         collect jar into jars
                         finally return jars))
                 (remove-if-not #'file-exists-p
                                clojure-project-jar-classpaths))))

(defun find-clojure-jar (jars)
  (let ((candidates
         (remove-if-not
          (lambda (jar)
            (string-match-p "clojure\\([0-9.-]+\\(SNAPSHOT|MASTER\\)?\\)?\\.jar$" jar))
          jars)))
    (if candidates
        (car candidates)
      (expand-file-name "~/.clojure/clojure.jar"))))

(defun find-clojure-contrib-jar (jars)
  (let ((candidates
         (remove-if-not
          (lambda (jar)
            (string-match-p "clojure-contrib\\([0-9.-]+\\(SNAPSHOT|MASTER\\)?\\)?\\.jar$" jar))
          jars)))
    (if candidates
        (car candidates)
      (expand-file-name "~/.clojure/clojure-contrib.jar"))))

;;; original due to Phil Hagelberg
;;; (see `Best practices for Slime with Clojure' thread on Clojure Google Group)
(defun clojure-project (path)
  "Sets up classpaths for a clojure project and starts a new SLIME session.

   Kills existing SLIME session, if any."
  (interactive (list (ido-read-directory-name
                      "Project root:"
                      (locate-dominating-file default-directory "pom.xml"))))
  (when (get-buffer "*inferior-lisp*")
    (kill-buffer "*inferior-lisp*"))
  (cd path)
  ;; I'm not sure if I want to mkdir; doing that would be a problem
  ;; if I wanted to open e.g. clojure or clojure-contrib as a project
  ;; (both lack "deps/")
                                        ; (mapcar (lambda (d) (mkdir d t)) '("deps" "src" "classes" "test"))
  (let* ((jars (find-clojure-project-jars path))
         (clojure-jar (find-clojure-jar jars))
         (clojure-contrib-jar (find-clojure-contrib-jar jars)))
    (setq swank-clojure-binary nil
          ;; swank-clojure-jar-path (expand-file-name "~/.clojure/clojure.jar")
          swank-clojure-jar-path clojure-jar
          swank-clojure-extra-classpaths
          (cons clojure-contrib-jar
                (append (mapcar (lambda (d) (expand-file-name d path))
                                clojure-project-extra-classpaths)
                        (find-clojure-project-jars path)))
          swank-clojure-extra-vm-args
          (list (format "-Dclojure.compile.path=%s"
                        (expand-file-name "classes/" path)))
          slime-lisp-implementations
          (cons `(clojure ,(swank-clojure-cmd) :init swank-clojure-init)
                (remove-if #'(lambda (x) (eq (car x) 'clojure))
                           slime-lisp-implementations))))
  (slime))