Emacs для начинающих: elisp

    Введение


    Сразу предупреждаю, что я не собираюсь писать ни учебник, ни
    вводный курс Lisp и не претендую на какую либо полноту описания. А
    собираюсь я дать некоторые полезные по моему мнению сведения, которые
    помогут начинающим использовать emacs настраивать его по своему
    усмотрению и писать несложные функции, которыми тоже можно будет
    пользоваться в процессе использования emacs.

    Emacs, как уже неоднократно везде упоминалось, представляет собой
    комбинацию текстового редактора и интерпретатора Lisp. Нужно только
    уметь этим воспользоваться.

    Подготовка рабочего места


    Для начала поднастроим наш emacs, чтобы нам было бы комфортно в нем
    работать.

    Вставим в наш .emacs следующие строки:

    (setq auto-mode-alist
          (append
           '(
             ( "\\.el$". lisp-mode))))
    (global-font-lock-mode 1)

    Первый набор скобок сделает так, что при открытии файла с
    расширением .el, в буфере автоматически включается режим работы с
    текстами программ Lisp. Последняя строчка включает подсветку
    синтаксиса. Раскрашивает операторы языка в разные приятные цвета. Это
    реально помогает читать текст программы. Теперь, если мы редактировали
    .emacs в emacs, перезапускаем его, чтобы он перечитал файл настроек.

    Тут опытные товарищи подсказали, что приведенные операции делать не обязательно, так как нужные режимы включены в современных версиях emacs по умолчанию.


    Постараемся все делать из емакса. Итак, нам нужно создать
    директорию для наших экспериментальных файлов. И файл.

    Предположим, мы находимся в домашнем директории (подразумеваем, что
    мы на каком нибудь UNIX-е). Нажимаем:

    | Клавиши               | Производимое действие                         |
    |-----------------------+-----------------------------------------------|
    | C-x C-f RET           | Переходим в режим dired в домашней директории |
    | + Имя директории RET  | Создаем новую директорию                      |
    | RET                   | Переходим в созданную директорию              |
    | C-x C-f myfile.el RET | Открываем файл myfile.el                      |
    


    Самые общие понятия и приемы работы


    В лиспе нужно знать два понятия, переменные и функции. Вообще то
    переменную можно рассматривать тоже как функцию, возвращающую
    значение, присвоенное этой переменной. У переменных и функций есть
    имена — последовательность символов. Если в программе заключить имя в
    круглые скобки, оно выполнится как функция. Правда, если это имя
    переменной, интерпретатор лиспа выдаст ошибку. В лиспе имена принято
    записывать, разделяя логические части имени через дефис. Например
    my-cool-function

    Теперь о том, как вызываются функции. В отличие от, например, Си,
    функции вызываются следующим образом:

    (name-of-the-function arg1 arg2 arg3 ......)
    


    Т.е. вызов функции заключен в скобки. Первое имя в скобках — имя
    функции, остальные имена это аргументы. Так же, как и в Си, в качестве
    аргументов могут выступать выражения, возвращающие значения, например
    вызовы других функций, например:

    (name-of-the-function arg1 (name-of-the-function) arg3 ......)
    


    Это все хорошо, но как с этим работать? В emacs работать с этим
    очень легко и просто. Давайте, для начала попробуем сложить 2 и
    2. Запишем в нашем файле myfile.el следующее выражение:

    (+ 2 2)
    


    Попробуем его расшифровать. Символ "+" это функция,
    складывающая два ее аргумента. следующие две двойки — аргументы
    функций. Попробуем ее выполнить. Для этого ставим курсор emacs правее
    правой скобки нашего выражения (вплотную) и нажимаем C-x e. Если все
    сделано правильно, в минибуфере появится цифра "4". Ура, мы
    выполнили наше выражение.


    Для полноценного программирования принято использовать
    переменные. Давайте попробуем это сделать. Для начала нужно присвоить
    переменной значение.


    (set 'myvar-variable 4)
    


    Что мы здесь имеем?


    | Имя            | Комментарий                                                       |
    |----------------+-------------------------------------------------------------------|
    | set            | Функция, присваивающая первому аргументу значение 2-го            |
    | myvar-variable | Имя переменной, которой нужно присвоить значение                  |
    | 4              | Присваиваемое значение                                            |
    | '              | Значок, который показывает, что имя не должно возвращать значение |
    


    Обратите внимание на заначек (одиночная кавычка), он не дает имени
    переменной вернуть значение. Без него интерпретатор лисп будет
    жаловаться на ошибку. Есть другой вариант функции присваивания, при
    котором не нужно экранировать имя переменной кавычкой, setq. Для этой
    функции запись будет выглядеть:


    (setq myvar-variable 4)
    


    Теперь, еще один удобный прием работы. Как посмотреть значение
    присвоенное переменной? Для этого нужно поставить (можно прямо в
    тексте программы) курсор правее имени переменной и нажать C-x e. В
    минибуфере будет показано значение переменной. Обратите внимание, что
    если вы попробуете это сделать с переменной, у которой стоит
    экранирующая кавычка, значение показано не будет, экранированное имя
    значение не возвращает.

    Присвоение переменной строкового значения. Очень просто. Строка
    заключается в кавычки.

    (setq myvar-str-variable "My string")

    Вывод сообщения в минибуфер.

    (message "My message")
    


    Вставка строки в буфер в текущем положении курсора:

    (insert "My string")
    


    Выполнение последовательности функций:

    (progn
      (setq my-var "Hello")
      (message my-var))

    Определение собственных функций


    Нет ничего легче, чем определить собственную функцию. Синтаксис
    определения такой:

    (defun myf-test (a b ...)
      "Строка документации"
      (выражение)
      …
      (выражение))

    В этом определении:

    | что                   | Комментарий                                    |
    |-----------------------+------------------------------------------------|
    | defun                 | Ключевое слово для определения функции         |
    | myf-test              | Имя функции                                    |
    | (a b)                 | Список параметров                              |
    | "Строка документации" | Строка документации. Выдается при C-h myf-test |
    | (выражение)           | Выражения, выполняемые в теле функции          |
    


    Примечание. Функция возвращает значение, возвращаемое ее последним выражением.

    Попробуем для примера определить собственную функцию:

    (progn
      (setq my-var "Hello")
      (message my-var))

    Проверка:

      (myf-test 1 2)
    


    Прием работы: Чтобы меньше было возни, при отладке функций, удобно пользоваться следующим приемом:


    (progn
      (defun myf-test (a b)
        "Add first argument to second. Return result"
        (+ a b))
      (myf-test 1 2)
      )

    Если помните, оператор "progn" выполняет список
    выражений в его теле. В нашем случае, выполняется сначала определение
    функции, затем вызывается на выполнение тестовый пример. Изменив что-то
    в определении, можно моментально это проверить.

    Но, есть одна заковыка, функции, определяемые таким образом, Вы не
    можете вызвать на выполнение командой M-x "имя функции". Для
    того, чтобы можно бы было это сделать, в определение функции нужно
    вставить оператор "interactive":

    (defun myf-test-1 ()
      "Add first argument to second. Return result"
      (interactive)
      (message "Hello"))

    Выполнив это определение, и подав команду M-x myf-test-1 RET, Вы
    получите в минибуфере слово Hello

    Замечание: Для имен своих функций и переменных, желательно выбрать
    и использовать свой уникальный префикс, так как в emacs глобальное
    пространство имен. Я использую eik-, по имени-отчеству-фамилии. Вам
    нужно выдумать что-то свое.

    Заключение


    Описанных сведений из Lisp, на мой взгляд достаточно, для начала
    экспериментов с кастомизацией emacs. В основном кастомизация и
    сводится к присваивании значений переменным emacs и написанию
    собственных функций.

    Литература


    1. В Ubuntu в комплект пакета emacs22 входит
      справочное пособие по Elisp. M-x info, C-s elisp
    2. Google
    3. Программирование на Emacs Lisp
    Поделиться публикацией
    Реклама помогает поддерживать и развивать наши сервисы

    Подробнее
    Реклама
    Комментарии 35
    • +7
      Хорошая статья для начинающих, хотелось бы развития темы.

      Ряд замечаний, относительно подготовки рабочего места.

      Устанавливая переменную auto-mode-alist в .emacs мы теряем её общесистемное значение — как правило, в переменной уже содержаться соответствия для различных режимов, как поставляемых с emacs, так и установленных с пакетами дистрибутива. Если это значение терять не хочется, лучше использовать функцию add-to-list.

      Так же в emacs'е существует специальный режим для редактирования elisp — emacs-lisp-mode, возможно имеет смысл использовать именно его. В итоге, вместо (setq auto-mode-alist ...) можно написать нечто вроде:

      (add-to-list 'auto-mode-alist '("\\.el$". emacs-lisp-mode))

      Наконец, весьма вероятно, что emacs и без дополнительной настройки открывает .el файлы в нужном режиме — в этом случае вообще ничего писать не нужно.

      На счёт global-font-lock-mode — аналогично, не исключено, что она включена по умолчанию.
      • НЛО прилетело и опубликовало эту надпись здесь
    • 0
      Спасибо за замечания, исправлю.

      Про развитие, может и напишу небольшой цикл статеечек для начинающих, так, чтобы хотя бы поверхностно были охвачены базовые и расширенные возможности Emacs и те места, которые вызывают трудности у новичков. Целей вижу две, привлечение новых емаксоводов и понижение порога вохождения в Emacs.
      • НЛО прилетело и опубликовало эту надпись здесь
        • 0
          Я его знаю. И все-таки, считаю, что есть место и для таких статей. Начинающим не всегда легко бывает найти нужную информацию в такой объемистой документации. Тем более, что они часто не знают, что собственно искать. Такие короткие статейки, в которых описана какая-то частная оласть/задача и ее решение, но более связанно, с работающими примерами и объяснениями и которую можно прочитать и попробовать ее примеры за двадцать минут, думаю они уместны и полезны. Интересны также и приемы работы. Конечно, это все ИМХО.
          • НЛО прилетело и опубликовало эту надпись здесь
            • НЛО прилетело и опубликовало эту надпись здесь
            • 0
              Кстати, я поторопился, учебник я до этого не видел, вставил на него ссылку.
            • 0
              Спасибо за полезную ссылку.
              • 0
                Может кому поможет избежать потери времени:
                emacs lisp не поддерживает оптимизацию хвостовой рекурсии. Т.е если писать работу со списками в функциональном стиле то скрипт будет вываливаться с чем-то вроде maximum recursion depth…
                • 0
                  Насколько я помню, в eval по дефолту забинден на «C-x C-e», а не на «C-x e». Возможно стоить проверить…
                  • 0
                    После «Попробуем для примера определить собственную функцию:» надо заменить кусок с (progn ...) на кусок с (defun ...).

                    PS: Нынче стало модно отделять префикс через "/" — «oxyum/my-cool-fun».
                    • 0
                      Спасибо, все исправил.

                      Насчет префикса — как-то стремно такой символ в имя функции пихать, хотя с другой сторны, дело привычки.
                      • 0
                        Да мне тоже было непривычно, а потом втянулся — сразу и наверняка видно, что это именно префикс.

                        А вообще я предпочитаю языки, в которых есть понятие «namespace» (C++, Python, etc.).
                  • 0
                    Куда статья про emacs делась? Только решил проглядеть, а тут история Windows и Unix. И то только наброски.
                    • 0
                      Пардон, статью вернул, приношу извинения.
                    • 0
                      > C-x C-f RET | Переходим в режим dired в домашней директории

                      А не «С-x D RET»?
                      • 0
                        Работает и так и так, я просто всегда жму, C-x C-f RET просто чтобы не запоминать лишние клавиши, их и так много.
                        • 0
                          Странно. У меня «C-x C-f RET» не переходит в dired режим, а просто обновляет текущий файл. XEmacs 21.4.17
                          • 0
                            Неправильно выразился. Я имею ввиду, что Емакс перечитывает текущий файл заново.
                            • 0
                              Не уверен в чем дело, у меня по C-x C-f при открытом файле, в минибуфере появляется путь к текущему директорию.
                              • 0
                                Ну да, у меня тоже. «C-x C-f» — появляется путь к текущей директории. «RET» — текущий файл перечитывается.
                                • 0
                                  А у меня после «RET» открывается директорий. Попробуйте сделать:
                                  C-h k C-x C-f
                                  У меня вот что:
                                  C-x C-f runs the command find-file, which is an interactive compiled
                                  Lisp function in `files.el'.
                                  • 0
                                    C-x C-f runs 'find-file'
                                    'find-file' is an interactive compiled Lisp function loaded from "/some_path/xemacs-21.4.17/lisp/files.elc"
                                    • 0
                                      Может быть дело в версиях? у меня GNU Emacs 23.1.1 (i686-pc-linux-gnu, GTK+ Version 2.16.1)
                                      А так: функция та же. Вообще, перегружает текущий файл специальная функция: M-x revert-buffer
                                      Теперь осталось сделать M-x find-file
                                      У меня там написано среди прочего:

                                      «Interactively, the default if you just type RET is the current directory»

                                      А у Вас?
                                      • 0
                                        Пардон: M-h f find-file
                                        • 0
                                          Я понял =)
                                          У меня касательно действия после RET ничего не сказано.
                                          Ладно, будем считать что дело в разных версиях Емакса. Да и ОС — Солярис.
                                          • 0
                                            ОК, ставьте 23, он очень вкусный.
                        • –1
                          Сделал все как в инструкции, не хочет выполнять выражения на C-x e. Пишет 'No kbd macro has been defined'. А в главном меню Emacs-а, в пункте SLIME->Evaluation-> все функции «серенькие», на которые нельзя нажать.
                          Вот ~/.emacs:
                          (custom-set-variables
                          ;; custom-set-variables was added by Custom.
                          ;; If you edit it by hand, you could mess it up, so be careful.
                          ;; Your init file should contain only one such instance.
                          ;; If there is more than one, they won't work right.
                          )
                          (custom-set-faces
                          ;; custom-set-faces was added by Custom.
                          ;; If you edit it by hand, you could mess it up, so be careful.
                          ;; Your init file should contain only one such instance.
                          ;; If there is more than one, they won't work right.
                          )
                          (setq auto-mode-alist
                          (append
                          '(
                          ( "\\.el$". lisp-mode))))
                          (global-font-lock-mode 1)

                          (setq inferior-lisp-program "sbcl")


                          Подскажите, в каком месте проблема?
                          • 0
                            C-x C-e тоже не работает. Пишет 'Not connected'. Курсор во время нажатия этой комбинации стоит в начале следующей строки.
                            • 0
                              Ах, все заработало. Нужно было M-x slime
                              • 0
                                Ну вот и ладушки. M-x 'function-name'
                                это команда выполнить интерактивную функцию 'function-name'
                                Все так, как и должно быть.
                              • 0
                                'C-x C-e' Это команда выполнить выражение. При этом курсор должен стоять справа рядом с сзакрывающей скобкой выражения.
                              • 0
                                'C-x e' это выполнить клавиатурный макрос, который к этому моменту должен быть определен. Вам emacs говорит, что вы хотите выполнить макрос, а никакой макрос не определен.

                              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.