Показаны сообщения с ярлыком emacs. Показать все сообщения
Показаны сообщения с ярлыком emacs. Показать все сообщения

четверг, 14 октября 2010 г.

SLIME на службе автоматизации

В предыдущем посте я рассказал как можно ускорить компиляцию шаблонов cl-closure-template и тем самым упростить процесс разработки. Кроме того, мне также досаждает другая проблема. Для перекомпиляции этих шаблонов я обычно переключаюсь в файл, в котором расположен код компилирующий шаблоны, ставлю курсов на этот код и нажимаю M-C-x. Другой вариант - оформить это в виде функции и вызывать через REPL. Оба способа достаточно не удобны и могут вызывать некоторое раздражение при активной правке шаблонов. Поэтому, для упрощения этой задачи я использую следующий приём (который можно использовать и для других подобных задач):

в конфигурационный файл Emacs (~/.emacs, ~/.emacs.d/init.el или т.п.) я добавляю такой код:
(global-set-key "\C-c\C-p" 
(lambda ()
(interactive)
(slime-eval-async '(mypackage:compile-all-templates)
(lambda (obj) (message "Compilation templates finished")))))
Теперь при нажатии в Emacs сочетания C-c C-p будет вызвана функция mypackage:compile-all-templates, которая вызывает перекомпиляцию шаблонов (или что либо другое, что нужно именно вам).

вторник, 17 августа 2010 г.

Выравнивание в closure-template-html-mode

Благодаря помощи cvb удалось реализовать мою мечту - прикрутить выравнивание кода в closure-template-html-mode.el (из состава cl-closure-template). Осталось ещё несколько тонких моментов, которые не учитываются реализованным механизмом, но такие ситуации встречаются довольно редко. Теперь править код шаблонов стало намного, намного приятней. Ну и заодно немного разобрался как это всё реализуется в Emacs.

четверг, 12 августа 2010 г.

Chrome: Edit with Emacs

Давно хотел заполучить для Chromium (Chrome) аналог It's All Text! и вот, наконец, с подсказки dmitry_vk нашёл Edit with Emacs. Данный пост написан с помощью этого расширения. Жизнь, однако, налаживается...

воскресенье, 14 марта 2010 г.

Расширение возможностей SLIME 2

Продолжаю экспериментировать над расширением возможностей SLIME. В прошлый раз, я указывал, что можно переопределить поведение стандартного инспектора объектов для собственных классов с помощью специальной реализации generic-функции swank:emacs-inspect . Использую эту возможность я создал достаточно интересные инспекторы модулей и виртуальных хостов (что получается расскажу в следующий раз). Но мне не нравился один момент. В инспекторе модуля я показываю список маршрутов (routes), предоставляемых модулем. В RESTAS маршруты определяются через макрос define-routes, который просто создаёт символ и настраивает его свойства. Таким образом, маршрут это фактически просто символ. Что бы в инспекторе объектов он отображался именно как маршрут (а для символов swank:emacs-inspect уже определена) я создал отдельную структуру-обёртку %restas-route. Всё бы хорошо, но стандартная функция инспектора slime-inspector-show-source (вызывается по нажатию ".") показывает на маршруте именно определение этой структуры, а я хотел бы, что бы эта команда открывала соответствующее определение define-rotue - было бы чрезвычайно удобно. При чём, технически такая возможность безусловно есть, ибо define-route также создаёт одноимённую функцию (которая является обработчиком маршрута) и таким образом компилятор (ну если он вообще поддерживает такую возможность) знает место определения. Очень быстро я определил, что соответствующее поведение обеспечивается функцией swank-backend:find-source-location, которая принимает объект, а возвращает (ну если реализация это позволяет) его местоположение в исходном коде. Но это простая функция, при чем, по разному реализуемая в разных бэкэндах и изменить её поведение несколько затруднительно. Поэтому я ввёл новую generic-функцию swank:object-source-location, которая по-умолчанию, просто вызывает find-source-location, но поведение которой можно изменить для своих объектов, и заменил в swank.lisp вызовы find-source-location (благо, таких мест оказалось целых два) на вызовы этой новой функции. Теперь реализация нужного поведения оказалась тривиальной:
(defstruct %restas-route
symbol)

(defmethod swank:object-source-location ((route %restas-route))
(swank:object-source-location (symbol-function (%restas-route-symbol route))))

пятница, 12 марта 2010 г.

Расширение возможностей SLIME

Сразу скажу, что вчера после коротких сомнений форкнул SLIME. Без этого программирование тех возможностей, которые мне нужны порой слишком сильно напоминает хак, чего я не люблю. Моя первоочередная цель - упрощение расширения возможностей SLIME сторонними модулями. Если ли у вас также есть какой-либо интерес в этой области (может быть он появиться после этой заметки ;)) - пишите, обсудим (либо сразу делайте форк средствами github). Но сразу предупреждаю, что возможность включения моих изменений в оригинальный SLIME весьма сомнительна.

Итак, вчера я реализовал следующую возможность: если в систему загружен RESTAS, то можно в Emacs выполнить команду M-x restas-inspect-module, ввести имя модуля (в терминологии RESTAS), например, restas.wiki, и получить стандартный инспектор, в котором показывается имя модуля и список маршрутов (routes), который предоставляет этот модуль. Пока всё, но для первой пробы пойдёт, тем более, что реализация совершенно тривиальна:

Common Lisp код
(defpackage #:restas.swank
(:use #:cl #:iter)
(:export #:inspect-module))

(in-package #:restas.swank)

(defstruct %restas-module
package)

(defmethod swank:emacs-inspect ((module %restas-module))
(let ((package (find-package (%restas-module-package module))))
`("" "Name: " (:value ,(package-name package))
(:newline)
(:newline)
"Routes: "
(:newline)
,@(iter (for route in-package (symbol-value (find-symbol restas::+routes-symbol+ package)))
(collect (list :value
(find-symbol (symbol-name route)
package)))
(collect '(:newline))))))

(swank:defslimefun inspect-module (package)
(swank:inspect-object (make-%restas-module :package package)))
elisp код
(defun restas-inspect-module (module)
"Inspect module."
(interactive (list (slime-read-package-name "Module: ")))
(when (not module)
(error "No module given"))
(slime-eval-async `(restas.swank:inspect-module ,module) 'slime-open-inspector))
Большая часть расширений SLIME может быть выполнена совершенно тривиальным образом. На стороне CL-кода необходимо объявить функцию, которая делает основную работу и возвращает результат в виде s-выражения. Для этого предусмотрен специальный макрос defslimefun, который согласно комментариям создаёт функции, которые могут использоваться из elisp-кода. Технически это не совсем верно, ибо он пока всего лишь объявляет функцию и экспортирует её из пакета. Но я думаю, что это хорошая практика использовать для объявления подобных функций специальный макрос, тем более что я собираюсь его несколько изменить, что бы он выполнял больше полезной работы (например, его можно использовать для реализации автоматической генерации описания протокола). Теперь, вызывать эту функцию на стороне elisp можно либо с помощью slime-eval (синхронный вариант), либо с помощью slime-eval-async (асинхронный вызов, требуется также указать callback-функцию для обработки результата). Это настолько просто, что может даже сложиться впечатление, что код функции restas.swank:inspect-module (см. код выше) вообще объявлен на стороне elisp (я подумывают на тем, что бы использовать defslimefun для автоматической генерации elisp-кода, так что подобные вызовы можно будет делать совершенно прозрачным образом). Теперь, полученное s-выражение можно как-либо обработать и например что-нибудь показать пользователю.

В коде выше я также использую возможность переопределения работы стандартного инспектора с помощью определения специализированного метода emacs-inspect. Это вообще является самым простым способом расширения функционала SLIME: просто определите emacs-inspect для ваших классов (или даже отдельных объектов, используя eql-спецификатор)!

В общем, это настолько просто, что приходиться только удивляться, почему это не используется повсеместно для расширения функционала SLIME для работы с разными системами. Впрочем, я думаю, это обусловлено позицией разработчиков SLIME, которые не афишируют этих возможностей и не делают их более удобными в использовании.

Причём, SLIME может использоваться для создания elisp-приложений, которые не имеют непосредственного отношения к Common Lisp, но которые трудно реализовать только на elisp (например, человеческий интерфейс к базам данных). Как известно, для elisp нет FFI, но SLIME предоставляет мощный интерфейс для взаимодействия с Common Lisp кодом (а также с кодом на Scheme и Clojure), что гораздо круче ;)

понедельник, 8 февраля 2010 г.

paredit

Попробовал использовать paredit, который все так хвалят, для редактирования лисп-кода: это ужасно - оно насильно поддерживает правильный баланс скобок, что полностью сбивает меня с толку. Я использую незакрытые s-выражения для выражения того, что мысль не закончена. Я ставлю последнюю скобку когда считаю, что выражение готово.

Наверное я просто недостаточно люблю скобочки (что правда, я их принял, но никогда не был в восторге от s-выражений) и поэтому идея "структурного редактирования" впечатления на меня не производит: предпочитаю иметь дело с текстом.

P.S. У меня есть схожая проблема с js2-mode, но там хоть можно спокойно удалять автоматически подставленные символы.

четверг, 25 декабря 2008 г.

sbcl-slime, clisp-slime and etc

Хотелось бы поделиться двумя советами, которые представляются мне довольно важными при использовании Slime (а если вы работаете с Common Lisp, то почти наверняка используете именно его).

Как известно, какая именно реализация CL будет запущена при запуске Slime определяется переменной inferior-lisp-program. Однако глобальное определение этой переменной и использование команды slime довольно неудобно, поскольку не позволяет легко запускать различные реализации CL. Я же часто запускаю как sbcl, так и clisp, а в планах поработать и с другими реализациями. Не переопределять же эту переменную каждый раз, когда хочешь поработать с другой реализацией? Поэтому, в свой конфиг Emacs я добавил следующее:
(defmacro lisp-slime (lisp path &optional coding)
(let ((funname (intern (format "%s-slime" lisp))))
`(defun ,funname ()
(interactive)
(let ((inferior-lisp-program ,path)
(slime-net-coding-system (or ,coding 'utf-8-unix)))
(slime)))))

(lisp-slime sbcl "/usr/bin/sbcl")
(lisp-slime clisp "/usr/bin/clisp")
Теперь у меня доступны команды sbcl-slime и clisp-slime, которые позволяют легко запустить sbcl или clisp соответственно. Ну а макрос lisp-slime может быть использован для лёгкого добавления других реализаций.

Второй совет связан с использование hyperspec. Функция hyperspec-lookup отрывает документацию по символу в браузере и очень удобно, если это emacs-w3m. Для того, что бы так и происходило (в моей системе по умолчанию запускается Firefox), можно просто переопределить функцию browse-url-default-browser таким образом, что бы она вызывала w3m-browser-url. Однако, в таком случае функция browser-url всегда будет открывать указанный url в emacs-w3m, чего бы мне хотелось избежать (w3m хорош для работы с hyperspec, но для других задач я предпочитаю использовать Firefox). Добиться того, что бы hyperspec открывался в emacs-w3m (в том числе, при использовании slime-hyperspec-lookup), а другие url в браузере по умолчанию (в моём случае в Firefox) можно следующим образом:
(require 'hyperspec)

(defun hyperspec-lookup (&optional symbol-name)
(interactive)
(let ((browse-url-browser-function 'w3m-browse-url))
(if symbol-name
(common-lisp-hyperspec symbol-name)
(call-interactively 'common-lisp-hyperspec))))
Примечание: хотя в моей системе hyperspec загружается автоматически, мне всё же пришлось добавить (require 'hyperspec) до определения hyperspec-lookup, что бы гаранитровать правильный порядок инициализации.

среда, 3 декабря 2008 г.

вспоминая postgres

Сегодня с утра надо было сделать небольшую базу данных. Давненько ничего подобного не делал... Запустил pgadmin3, потылкался минут 20 - не могу, раздражает, какие-то окошечки, выпадающие списки и прочие "рюшечки". А ведь вроде когда-то под виндой юзал более-менее нормально. Ладно, плюнул, M-x sql-postgres и уже через пять минут почувствовал себя человеком :-) Ну а psql оказалась очень даже вменяемой утилитой. Теперь думаю только так и работать.