среда, 16 ноября 2005 г.

Настраеваем emacs/gnus

Надеюсь кому-то пригодятся те изменения которые я вчера вечером проделал со своим gnus'ом. Жду коментарии :)

В обычном своем виде, почтовый клиент gnus похож на текстовый редактор. Глядя на список почтовых папок (групп) кажется, что нажми ты кнопку backspace на клавиатуре, как незамедлительно будет удалена часть названия папки, как это происходит при редактировании документов. Мигающий курсор сбивает с толку. Поэтому мы его убираем первым же делом:
;; Прячем курсор в режиме групп и списка сообщений
(add-hook 'gnus-group-mode-hook
(lambda ()
(setq cursor-type nil)
))

(add-hook 'gnus-summary-mode-hook
(lambda ()
(setq cursor-type nil)
))

А для того, чтобы видеть какую строку (с названием почтовой папки или описанием письма из папки) мы в данный момент выбираем, включаем режим подсветки текущей строки буфера. Включаем это дело глобально ибо вещь полезная не только в гнусе:
;; Включаем подсветку текущей строки
(highlight-current-line-on t)

Настроить режим подсветки (задать фон, подчеркивание, особо крупный размер и тд)
можно нажав: M-x customize-face <enter> highlight-current-line-face <enter>

Теперь выбор папки и письма похожи на выбор каталога в Norton Comander'е или почтовых клиентах tin/mutt.

Чтобы приблизить gnus к tin'у и mutt'у изменим поведение кнопок в режимах просмотра списков папок и писем:

up - переход к предыдущей строке буфера как и раньше, но спрятанный курсор перемещается в начало строки, а не остается в той же колонке.

down - переход к следующей строке буфера (по прежнему ничего необычного), но как и для кнопки 'up', переходим в начало строки, к тому же не даем курсору попасть в позицию 'end-of-buffer', предотвращая случай, когда ни одна группа не выбрана (не даем курсору уйти за пределы списка).

pgdown - аналогично изменениям с кнопкой 'down', но перемещение происходит на страницу, а не строку, логично.

home - переход к началу списка, а не в начало строки.

end - переход к концу списка, а не в конец строки.

right - более сложные изменения, но по прежнему весьма интуитивные (разгружаем
лобную долю и нагружаем мозжечок, занимая голову более полезной работой чем
обдумывание нажатий).
В режиме просмотра списка папок, нажатие на эту клавишу,
открывает папку для просмотра ее содержимого
(в mc мы входим таким же образом в каталог). В режиме просмотра списка
писем нажатие на эту клавишу открывает выбранное письмо для просмотра.
Если письмо уже открыто на просмотр, то нажатие на right скроллирует письмо
на страницу вперед (на страницу минус две строки). При достижении конца письма,
дальнейшие нажатия игнорируются. Фактиски мы переносим ф-ии клавишь
space и enter, на клавишу right.

left - самая сложная функция. В режиме просмотра списка папок (групп) осуществляет
выход из gnus'а (функция кнопки q). В контексте просмотра списка сообщений,
когда не открыто ни одного сообщения (то есть когда на экране только список
сообщений папки), производит выход в режим просмотра списка папок,
но без перехода к следующей папке, как это происходит по кнопке q.
Если же имеется открытое письмо и первая его строка на экране не видна
(письмо отображается не с начала), то скроллирует письмо на страницу назад,
также как и кнопка 'backspace'. Если письмо отображается с самого начала, то
нажатие на left приводит к удалению его с экрана подобно нажатию на C-x 1.

Таким образом типичный цикл чтения почты осуществляется всего 4мя основными клавишами left, right, up, down, и выглядит следующим образом: в списке папок клавишами up/down выбираем нужную и нажимаем right, видим список писем в папке, выбираем заинтересовавшее нас письмо с помощью клавишь up/down и нажимаем кнопку right, нажимаем ее периодически до тех пор, пока не прочтем до конца, после чего либо выбираем следующее письмо кнопками up/down и нажимает right, либо с помощью кнопки left возвращаемся к началу письма и еще одним нажатием этой же кнопки разворачиваем список писем на весь экран для лучшего его обзора. Полистав список писем и не найдя ничего хорошего нажимаем left и оказавшись в режиме просмотра папок повторяем все операции сначала, или еще одним нажатием
left выходим из gnus'a.

Реализация этих изменений:

;; - - - - - - -- - -- - - - - - - - - - - - - - - - - - - - - - - - -
;; Кнопки в режиме просмотра групп - - - - - - - - - - - - - - - - - - -

;; Переопределяем Down на переход к началу слудющей строки
(define-key gnus-group-mode-map (kbd "<down>")
'my-next-line-nomark)

;; Переопределяем Up на переход к началу предыдущей строки
(define-key gnus-group-mode-map (kbd "<up>")
'my-previous-line-nomark)

;; Переопределяем PgDn на переход через страницу
(define-key gnus-group-mode-map (kbd "<next>")
'my-scroll-up-nomark)

;; Переопределяем End для перехода к конец списка
(define-key gnus-group-mode-map (kbd "<end>")
'my-goto-last-line)

;; Переопределяем Home для перехода в начало списка
(define-key gnus-group-mode-map (kbd "<home>")
'my-goto-first-line)

;; Переопределяем Right для входа в группу
(define-key gnus-group-mode-map (kbd "<right>")
'gnus-group-select-group)

;; Переопределяем Left для выхода из gnus'а
(define-key gnus-group-mode-map (kbd "<left>")
'gnus-group-exit)

;; - - - - - - -- - -- - - - - - - - - - - - - - - - - - - - - - - - -
;; Кнопки в режиме просмотра группы - - - - - - - - - - - - - - - - - -

;; Переопределяем Down на переход к началу слудющей строки
(define-key gnus-summary-mode-map (kbd "<down>")
'my-next-line-nomark)

;; Переопределяем Up на переход к началу предыдущей строки
(define-key gnus-summary-mode-map (kbd "<up>")
'my-previous-line-nomark)

;; Переопределяем PgDn на переход через страницу
(define-key gnus-summary-mode-map (kbd "<next>")
'my-scroll-up-nomark)

;; Переопределяем End
(define-key gnus-summary-mode-map (kbd "<end>")
'my-goto-last-line)

;; Переопределяем Home
(define-key gnus-summary-mode-map (kbd "<home>")
'my-goto-first-line)

;; Переопределяем Right на скроллинг сообщения
(define-key gnus-summary-mode-map (kbd "<right>")
'my-summary-right)

;; Переопределяем Left на:
;; , если плказывается не начало письма, то скролим назад на страницу
;; , если показывается начала письма, то прячем письмо и показываем полный список сообщений
;; , если показан полный список сообщений, то выходим в режим групп
(define-key gnus-summary-mode-map (kbd "<left>")
'my-summary-left)

;; Переход на последнюю строку
(defun my-goto-last-line ()
"Goto last line"

(interactive)
(goto-char (- (point-max) 1))
(beginning-of-line)
)

;; Переход на первую строку
(defun my-goto-first-line ()
"Goto last line"

(interactive)
(goto-char 0)
)

;; Переход к началу следующей строки, и если мы достигли конца буфера, то переход
;; к началу последней строки.
(defun my-next-line-nomark ()
"Goto beginning of next line preventing end-of-buffer position"

(interactive)
(next-line-nomark 1)
(when (eobp)
(goto-char (- (point) 1)))
(beginning-of-line)
)

;; Переход к началу следующей части буфера, и если мы достигли конца буфера, то переход
;; к началу последней строки.
(defun my-scroll-up-nomark ()
"Goto beginning of next page preventing end-of-buffer position"

(interactive)
(scroll-up-nomark nil)
(when (eobp)
(goto-char (- (point) 1)))
(beginning-of-line)
)

;; Переход к началу предыдущей строки
(defun my-previous-line-nomark ()
"Goto beginning of previous line"

(interactive)
(previous-line-nomark 1)
(beginning-of-line)
)

;; Функция для кнопки влево в режиме просмотра списка сообщений
(defun my-summary-left ()
"Multifunctional left button handler in summary mode"

(interactive)

;; Если буфер сообщения существует
(if (buffer-live-p (get-buffer gnus-article-buffer))
;; Буфер открытого сообщения существует,
;; получаем окно для этого буфера
(let ((article-window (get-buffer-window gnus-article-buffer t)))
;; Если окно nil, тоесть у буфера нет окна, то выходим из группы
(if (null article-window)
(my-summary-exit)

;; Окно с сообщение показано на экране, определяем начало ли показано или нет
;; Если показано начало, то значит убираем буфер сообщения с экрана,
;; иначе скролируем кусок страницы сообщения назад
(if (pos-visible-in-window-p 1 article-window)
;; Убираем буфер сообщения с экрана
(delete-other-windows)

;; Скролируем назад
(gnus-summary-prev-page)
)
)
)

;; Буфер сообщения не существует - выходим из группы
(my-summary-exit)
)
)

;; Выходим из группы.
;; Из-за того, что gnus перекидывает курсор к следующей группе
;; мы сохраняем позицию курсора в буфере групп перед выходом из группы
;; и восстанавливаем ее после выхода из группы
(defun my-summary-exit ()
"Exit summary preserving selected group"

(let ((old-group-point (gnus-eval-in-buffer-window gnus-group-buffer (point))))
(gnus-summary-exit)
(goto-char old-group-point)
)
)

;; Функция для кнопки вправо в режиме просмотра списка сообщений
(defun my-summary-right ()
"Scroll article buffer without jumping to new article at the end"

(interactive)
(gnus-summary-next-page nil nil t)
)

В дополнение ко всему, письма прочитанные более 15 дней назад, автоматически кладем в одноименные папки, добавив к ним (к именам папок) префикс "archive." и суффикс являющийся годом написания устаревшего письма. Например письмо из папки в mail.private написанное в 2004 году уйдет через 15 дней после прочтения в папку archive.mail.private.2004.

;; По умолчанию сообщения в группах не устаревают
(setq gnus-auto-expirable-newsgroups nil)

;; Время хранения почты после прочтения прежде чем она устреет
(setq nnmail-expiry-wait 15)

;; Настройка свойств групп - - - - - - - - - - - - - - - - - - - - - --
(setq gnus-parameters
'(("^nnml:mail\\.\\(.*\\)$"
(auto-expire . t)
(gcc-self . t))

("^nnml:list\\.\\(.*\\)$"
(auto-expire . t))

("^nnml:archive\\.mail\\.\\(.*\\)$"
(gcc-self . "nnml:mail.\\1"))
))

;; Устаревание производится через нашу ф-ию
(setq nnmail-expiry-target 'my-fancy-expiry-target)

;; Возвращает название группы куда складывать устаревшие письма для данной
(defun my-fancy-expiry-target (group)
"Returns a target expiry group with year included."
(let ((date (date-to-time
(or (message-fetch-field "date") (current-time-string))
)
)
)
(concat "nnml:archive." group "." (format-time-string "%Y" date))
)
)

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

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