Начало
На хабре уже была обзорная статья по jabber.el — jabber-клиенту для emacs. Решив попробовать этот клиент после pidgin, я наткнулся на отсутствие таких привычных уже вещей, как история ввода или форматированные сообщения. К сожалению, emacs-jabber не развивается так быстро, как хотелось бы. К счастью, возможности emacs по настройке практически безграничны, поэтому добавить нужное несложно. В этой статье я расскажу, как реализовал историю ввода. Если эта тема заинтересует общественность, в дальнейшем опишу отправку форматированных сообщений (html) и некоторые другие плюшки.
История ввода
Очень удобная штука в pidgin — история ввода. По ctrl+up можно идти назад по истории отправленных сообщений, а по ctrl+down вперёд. Добавим этот функционал в emacs-jabber. Нам понадобятся три переменные: список введённых фраз, текущая позиция в этом списке и последний введённый, но ещё не отправленный текст.
(defvar my-jabber-input-history '() "Variable that holds input history") (make-variable-buffer-local 'my-jabber-input-history) (defvar my-jabber-input-history-position 0 "Current position in input history") (make-variable-buffer-local 'my-jabber-input-history-position) (defvar my-jabber-input-history-current nil "Current input value") (make-variable-buffer-local 'my-jabber-input-history-current)
При отправке сообщения добавляем его в список:
(defun my-jabber-input-history-hook (body id) (add-to-list 'my-jabber-input-history body t) (setq my-jabber-input-history-position (length my-jabber-input-history))) (add-hook 'jabber-chat-send-hooks 'my-jabber-input-history-hook)
Важно: my-jabber-input-history-position указывает не на последний элемент истории, а за него (нумерация с нуля). Это логично, ведь мы ещё не ходили по списку.
Функция для прохода назад по списку:
(defun my-jabber-previous-input () (interactive) (let (current-input (pos my-jabber-input-history-position) (len (length my-jabber-input-history))) (if (= pos 0) (message "%s" "No previous input") (setq current-input (delete-and-extract-region jabber-point-insert (point-max))) (when (= pos len) ; running first time, save current input (setq my-jabber-input-history-current current-input)) (decf my-jabber-input-history-position) (insert (nth my-jabber-input-history-position my-jabber-input-history)))))
Всё просто, единственное, на что стоит обратить внимание — сохранение текущего введённого текста. Если пользователь передумает пользоваться историей, мы сможем восстановить то, что он успел ввести.
Функция для прохода вперёд по списку:
(defun my-jabber-next-input () (interactive) (let ((pos my-jabber-input-history-position) (len (length my-jabber-input-history))) (cond ((= pos (1- len)) ; pointing at the last element, insert saved input (incf my-jabber-input-history-position) (delete-region jabber-point-insert (point-max)) (insert my-jabber-input-history-current) (setq my-jabber-input-history-current nil)) ((= pos len) ; pointing beyound last element, notify user (message "%s" "No next input")) (t ; insert next history item (incf my-jabber-input-history-position) (delete-region jabber-point-insert (point-max)) (insert (nth my-jabber-input-history-position my-jabber-input-history))))))
Здесь логика хитрее. Если мы на последнем элементе в списке (len — 1), то вставлять надо предварительно сохранённый пользовательский ввод. Но позицию по-прежнему увеличиваем, чтоб в следующий раз сработало второе условие.
Вешаем эти функции на удобные кнопкосочетания:
(define-key jabber-chat-mode-map (kbd "M-p") 'my-jabber-previous-input) (define-key jabber-chat-mode-map (kbd "M-n") 'my-jabber-next-input)
Готово. Теперь у нас есть тот же функционал, что и в pidgin + извещения о достижении начала и конца списка + история без дублирующихся сообщений (благодаря add-to-list).
Любителям ido-mode может пригодиться такая функция:
(defun my-jabber-input-history-choose () (interactive) (let ((choice (ido-completing-read "Select history item: " (reverse my-jabber-input-history)))) (delete-region jabber-point-insert (point-max)) (insert choice)))
Поскольку это ido, то работает поиск в списке по мере ввода текста (даже нечёткий, если установлена переменная ido-enable-flex-matching) и перебор вариантов по C-s/C-r.
Конец
Текст подготовлен в emacs с использованием org-mode и экспорта в docbook (С-c C-e D).
Ссылки
XSLT для преобразования докбукового XML в понятный хабру формат.
ссылка на оригинал статьи http://habrahabr.ru/post/164573/
Добавить комментарий