Friday, February 26, 2010

Настройка clojure-mode. Черновик.

В этом посте я хочу описать, как я настроил у себя среду разработки для Clojure с использованием emacs и Java.
Я использую Ubuntu в качестве ОС, но похожее решение должно работать и для
других ОС. Если вас интересует только clojure, возможно вы захотите пойти по простому пути, но он имеет свои недостатки, которые автор и описал.
1. Установка clojure
Что нам понадобится?
1) Java JDK. Вы можете установить ее средствами системы, например через пакетный менеджер или скачав инсталятор с сайта Оракла. Важно, что бы в результате в PATH были команды java и javac. Текущая версия clojure работает и с .Net/Mono, как ее запускать читайте на сайте clojure. Но этот вариант я не проверял.
2) Git - это система контроля версий, которая понадобится нам для получения нужных частей рещения.
3) Clojure. Лучше брать с сайта . На данный момент в реппозитории Ubuntu версия 1.0, а на сайте 1.1, в которой добавлено много интересных возможностей.
4) clojure-contrib - официальная библиотека для расширения языка.
5) Сложить все *.jar файлы где вы считаете нужным. Лично я создал отдельную директорию /opt/clojure, в которой должно лежать все, связанное с clojure. Теперь можно запускать clojure командой:
java -cp /opt/clojure/clojure.jar clojure.main
Но, нам потребуется сценарий, который я назвал clj-cmd и поместил в PATH:

Пояснение. Вызвав этот скрипт из консоли мы получим clojure, запущенный с поддержкой jline.ConsoleRunner или опций командной строки, а для запуска из emacs используется переменная среды CLJ_CMD, которую мы сгенерируем в emac
Теперь делаем этот скрипт исполняемым:
chmod a+x clj-cmd
Теперь проверяем:
./clj-cmd
Clojure 1.1.0
user=> (+ 1 1)
2
Для желающих собрать из исходников можно сделать это, так как описано ниже:
для сборки нам потребуются системы для сборки java-проектов Ant и Maven. Также не имеет значения, как вы их поставите,
важно, что бы команда ant была в PATH.
Сначала собираем clojure:
cd /opt/experimental/
git clone git://github.com/richhickey/clojure.git
cd clojure
ant
После чего на выходе получим clojure.jar - это и есть реализация языка.
Собираем clojure-contrib - официальная библиотека для расширения языка.
cd ..
git clone git://github.com/richhickey/clojure-contrib.git
cd clojure-contrib
mvn package -Dclojure.jar=/opt/experimental/clojure/clojure.jar
В каталоге target получим clojure-contrib-1.2.0-SNAPSHOT.jar, который и подкинем в каталог с clojure.
cp ./target/clojure-contrib-1.2.0-SNAPSHOT.jar ../clojure/clojure-contrib.jar

2. Теперь у нас есть рабочая clojure и наша задача подружить Clojure и emacs.
Нам потребуются:
1) clojure-mode.el - режим emacs для clojure. Его можно взять тут . Я сложил полученные файлы в ~/elisp/mode/clojure.
далее в конфигурационном файле прописать:

string-join - эта функция объединяет строки, разделяя их разделителем joiner
Эти действия устанавливают переменную окружения CLJ_CMD, которую мы передадим скрипту, запускающему clojure. Она представляет собой строку, типа этой:
java -server -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8888 -cp /opt/experimental/clojure/clojure.jar:clojure.main:./:~/MY_Projects/java clojure.main
которая запустит сессию clojure.

2) SLIME - это мощная среда разработки Emacs для различных диалектов Lisp. Её можно скачать здесь. После распаковки прописываем в конфигурационном файле:


3) swank-clojure. Это часть, которая позволяет запустить clojure, как SLIME-процесс. Берем его из репозитория
cd /opt/clojure
git clone git://github.com/jochu/swank-clojure.git
Подбрасываем swank-clojure.el в ~/elisp/mode/clojure
cd swank-clojure/
cp swank-clojure.el ~/elisp/mode/clojure/
Далее:
cd ..
mv swank-clojure/src/swank/ ./
rm -r swank-clojure/
и в конфигурационном файле прописываем следующее:

Вот и все. Мы получили работающую среду для clojure. Проверяем:
Создайте где-нибудь файл test.clj и пишем в нем простую функцию:
(defn hello [] "Hello World!")
Emacs подсветит код. Далее
M-x slime
Дождитесь приглашения :
; SLIME 2010-02-20
user>
Возвратитесь к функции hello и нажмите C-c C-c для компиляции. Потом вернитесь в REPL и наберите
(hello)
Вы должны увидеть следующее:
"Hello World!"
Еще примеры:
Наберите :
(System/getProperty "java.class.path")
и нажмите C-c C-e . В результате вы увидите CLASSPATH, который видит clojure
Наберите :
(defn blank? [s] (every? #(Character/isWhitespace %) s))
и скомпилируйте это. Потом наберите (b , нажмите C-c TAB и slime предложит вам выбрать подходящий вариант. Далее введите"
(blank? "some text")
C-c C-e
false
(blank? " ")
C-c C-e
true
(blank? "")
C-c C-e
true.

Ниже я приведу некоторые вещи, которые вы, возможно, найдете удобными для себя.
Настройки slime. Сразу, после (slime-setup) пропишите следующее

Это позволит вам запускать slime по F5 и сделает красивое автодополнение.
Настройки clojure-mode

Покажет детали класса. Наберите (new java.util.Random) и после слова Random M-x slime-java-describe покажет вам методы класса.


Покажет документацию по классу. Например, наберите (new java.util.Random) и после слова Random M-x slime-javadoc.
Некоторые настройки, взятые у Алексея Отта:


После всех манипуляций имеем следующую конфигурацию:

Полезные ссылки:
Блог Телмана Юсупова.
Конфигурация Алексея Отта
Bill Climenson blog.

17 comments:

  1. Вроде все правильно.
    Только если используется только кложура, то можно просто поставить все из ELPA с помощью package.el и сразу получить рабочую конфигурацию. Я использую кастомную конфигурацию, поскольку у меня еще и sbcl используется иногда, и я работаю с CVS-версией SLIME

    ReplyDelete
  2. Я знаю о ELPA, но мне не нравится этот вариант по причине того, что уже есть один менеджер пакетов остальные (ELPA, питоновские яйца и пр.) явно лишние. Кроме того я тоже планирую прикрутить схему к SLIME.

    ReplyDelete
  3. Дошёл до:
    "Вот и все. Мы получили работающую среду для clojure. Проверяем:"
    Но на
    M-x slime
    емакс отвечает:
    Searching for program: no such file or directory, lisp

    ReplyDelete
  4. Я немного напутал с путями. У меня в одном месте /opt/clojure, а в другом /opt/experimental/clojure. Эо связано с тем, что у меня два clojure.
    Кроме того, проверьте, чтобы у вас :
    1) java была в PATH (выполнялась без указания пути) и что бы она была сановская
    2) clj-cmd тоже был в PATH
    3) Каталог swank из swank-clojure/src/ был в каталоге с clojure.jar
    Попробуйте запустить конфигурацию, описанную в самом низу статьи

    В любом случае напишите про результат.

    ReplyDelete
  5. Кстати почему конфигурация в самом низу отличается от комбинации конфигураций приведённых выше ?

    ReplyDelete
  6. 1) Потому, что статья пишется и проверяется не за один час, а в разные дни и на разных машинах. Потому и расхождения в путях. А конфигурация особо не отличается, кроме путей и внешнего скрипта. На всякий случай вот моя конфигурация емакса и кложуры.
    2) У вас как, получилось? Если да, то в чем была проблема?

    ReplyDelete
  7. Ночью буду делать :)
    Как попробую отпишусь

    ReplyDelete
  8. This comment has been removed by the author.

    ReplyDelete
  9. This comment has been removed by the author.

    ReplyDelete
  10. This comment has been removed by the author.

    ReplyDelete
  11. Заработало.
    Во первых если идти по шагам, то не хватает этого:
    (setq slime-net-coding-system 'utf-8-unix)
    (setq slime-lisp-implementations '((clojure ("clj-cmd") :init swank-clojure-init)))
    в конфиге слайма.

    Во вторых, если используется стандартный слайм, а по вашей инструкции это он и есть, то надо отключить автодок:
    (setq slime-use-autodoc-mode nil)

    Спасибо Alex Ott'у.

    ReplyDelete
  12. This comment has been removed by a blog administrator.

    ReplyDelete
  13. Спасибо, я это учту и на этой неделе внесу исправления.

    ReplyDelete
  14. Надо сказать, что все ваши замечания были в конечном варианте, но мой баг, что я не внес в пошаговую инструкцию.

    ReplyDelete
  15. В последнем удаленном сообщении было:
    я бы в (defun slime-javadoc
    добавил
    "(use 'clojure.contrib.repl-utils)"
    если вызвать её перед, например, slime-java-describe, то будет исключение

    ReplyDelete
  16. Можно добавить

    ;;показывает source
    (defun slime-clojure-source (symbol-name)
    "Get clojure source at point."
    (interactive (list (slime-read-symbol-name "Source: ")))
    (when (not symbol-name)
    (error "No symbol given"))
    (save-excursion
    (set-buffer (slime-output-buffer))
    (unless (eq (current-buffer) (window-buffer))
    (pop-to-buffer (current-buffer) t))
    (goto-char (point-max))
    (insert (concat "(use 'clojure.contrib.repl-utils)" "(clojure.contrib.repl-utils/source " symbol-name ")"))
    (when symbol-name
    (slime-repl-return)
    (other-window 1))))

    ;;показывает doc
    (defun slime-clojure-doc (symbol-name)
    "Get clojure doc at point."
    (interactive (list (slime-read-symbol-name "Doc: ")))
    (when (not symbol-name)
    (error "No symbol given"))
    (save-excursion
    (set-buffer (slime-output-buffer))
    (unless (eq (current-buffer) (window-buffer))
    (pop-to-buffer (current-buffer) t))
    (goto-char (point-max))
    (insert (concat "(doc " symbol-name ")"))
    (when symbol-name
    (slime-repl-return)
    (other-window 1))))

    и в клавиши
    (define-key slime-mode-map (kbd "C-c S") 'slime-clojure-source)
    (define-key slime-repl-mode-map (kbd "C-c S") 'slime-clojure-source)

    (define-key slime-mode-map (kbd "C-c s") 'slime-clojure-doc)
    (define-key slime-repl-mode-map (kbd "C-c s") 'slime-clojure-doc)

    ReplyDelete
  17. invis, большое спасибо. Обязательтено включу.

    ReplyDelete