понедельник, 27 апреля 2015 г.

Emacs как IDE для Rust


rust_logo.png Многие слышали про такой язык программирования как Rust, это чрезвычайно, на мой взгляд, перспективный и интересный язык от Mozilla, про него сейчас часто пишут и говорят. Он пока еще очень молод (в данный момент доступна только beta версия), в связи с чем поддержки в модных и популярных IDE для него нет или она очень слабая, а попробовать и составить мнение о языке хочется. Как обычно, в таких случаях на помощь нам приходит emacs, в нем относительно легко можно настроить подсветку синтаксиса, компиляцию, автодополнение и т.п.



Сначало добавим подсветку синтаксиса, для этого воспользуемся пакетом rust-mode. Настройка там не мудреная:
(autoload 'rust-mode "rust-mode" nil t)
(add-to-list 'auto-mode-alist '("\\.rs\\'" . rust-mode))

Настройка отступов, если нужно, делаем стандартно - в хуке rust-mode (я не люблю выравнивание табами, поэтому отключу их в примере):
(add-hook 'rust-mode-hook
  (lambda ()
    (setq indent-tabs-mode nil)
    (setq tab-width 4)
    (setq rust-indent-offset 4)))

Что бы продвинуться дальше - нам понадобиться собственно установить сам rust, пакетный менеджер для него cargo, библиотеку для автокомплита racer и исходники rust для автодополнения по ним. Тут стоит сделать замечание, что поскольку релиза rust все еще небыло, то синтаксис языка меняется, сейчас уже не сильно, но все же. И некоторые библиотеки, в частности racer, которую я использую для автодополнения, зачастую отказываются компилироваться на не последней версии. Поэтому я, пока не вышел релиз, использую последнюю ночную сборку rust. Иногда случается обратная ситуация, когда текущая версия racer не успевает за ночной сборкой rust - в этом случае стоит посмотреть на pull requests в репозитории racer, обычно там довольно оперативно появляются те, что чинят проблему.

Все вышеперечисленное - можно без проблем поставить руками по ссылкам выше или скомпилировать самому (замечу только, что компиляция rust из исходников занимает очень приличное время). Я предпочитаю везде где можно использовать пакеты, для archlinux все можно найти в AUR. Бинарники последней ночной версии rust + cargo ставятся пакетом rust-nightly-bin, racer - пакетом racer-git. Исходники можно скачать с сайта rust:
git clone --recursive https://github.com/rust-lang/rust.git ~/.local/share/rust_src

Главное не забывать потом периодически обновлять репозиторий, для актуализации исходников.

Что бы проверить, что все установлено правильно, можно в консоли попробовать вызвать racer (первой строкой, мы указываем racer, где ему искать исходники rust):
export RUST_SRC_PATH=~/.local/share/rust_src/src
racer complete std::io::B

В ответ racer должен выдать список вариантов для автодополнения.

Далее настроим автодополнение в самом emacs. В racer оно работает через жестко зашитый пакет company, который нужно будет установить в emacs, если его раньше не стояло. Потом добавим вот такие строки конфигурации:
(setq racer-rust-src-path "~/.local/share/rust_src/src")
(setq racer-cmd "/usr/bin/racer")
;; (add-to-list 'load-path "<path-to-racer>/editors")
(add-hook 'rust-mode-hook #'racer-activate)
(eval-after-load "rust-mode" '(require 'racer))

Где закоментированная строка - указывает локальный путь к папке editors, но если racer был установлен через пакет, этот путь скорее всего уже настроен в emacs.

После перезагрузки emacs должно заработать "go to the defenition" (по умолчанию по M-.) и автодополнение (по умолчанию по Tab), выглядит это вот так:
rust_autocomplete.gif

Поиск ошибок во время редактирования кода - можно сделать либо через пакет flymake-rust, либо при помощи flycheck-rust, я пользуюсь последним, при настроенном flycheck - достаточно добавить в конфиг:
(eval-after-load 'flycheck
  '(add-hook 'flycheck-mode-hook #'flycheck-rust-setup))

Дальше работаем, как обычно с flycheck, пример отображения ошибок: rust_flycheck.gif

Следующий этап - компиляция и запуск. Я в данный момент только начинаю изучать rust, пишу небольшие консольные программы, поэтому мой обычный патерн использования - это скомпилировать, запустить и увидеть в emacs то, что вывела программа на консоль. Если кому-то нужно, то сделать себе только компиляцию без запуска, можно по аналогии.

Rust компилируется несколькими способами, если это отдельный файл, то вызываем:
rustc <path-to-rs-file> && ./<rs-file-name>

Rust скомпилирует и положит в текущую директорию бинарник с именем rs файла, следующей командой - запускаем получившийся бинарник. Если у вас есть проект (фактически, если присутствует файл Cargo.toml), то достаточно в любом месте проекта вызвать:
cargo run

В результате скопилируется и запустится "src/main.rs"

Обучим этому emacs, для этого настроим стандартную команду "compile":
(defun lcl:rust-compile-hook ()
  (require 'compile)
  (set (make-local-variable 'compile-command)
       (if (locate-dominating-file (buffer-file-name) "Cargo.toml")
           "cargo run"
         (format "rustc %s && %s" (buffer-file-name)
                 (file-name-sans-extension (buffer-file-name))))))

(setq-default compilation-read-command nil)
(add-hook 'rust-mode-hook 'lcl:rust-compile-hook)

Теперь при вызове встроенной команды "compile", если emacs найдет файл "Cargo.toml" - то скомпилирует и запустит проект через "cargo run", в противном случае через "rustc". Интересная строчка выставляющая переменную "compilation-read-command" в nil, говорит emacs не показывать команду которой будет производится компиляция, но если нужно вручную добавлять какие-то флаги, то можно ее убрать.

Скриншот вывода компилятора в emacs: rust_compile.png

Для управления проектом, я использую пакет projectile, для снипетов - пакет yasnippet.

В итоге получаем вполне юзабельную IDE для Rust, со всеми необходимыми в повседневной работе фишками.

Комментариев нет:

Отправить комментарий