8 февр. 2008 г.

О переселении душ или о переназначении клавиш

Многие пользователи Emacs используют CapsLock в качестве левого Ctrl. Это довольно удобно. Так почему же на клавишу Return не назначить правый Ctrl? Это еще больше добавляет удобства, да и симметричности с левым Ctrl, который на месте клавиши CapsLock.

Небольшое отступление: некоторые пользователи нажимают комбинации C-a, C-e, C-d, используя левый Ctrl. Делать это не только неудобно, но и довольно неграмотно (скорее даже преступно :)). Если одна клавиша на левой стороне клавиатуры, а другая на правой, то пожалуйста, используйте обе руки (будь-то С-f, M-/ или C-M-s (здесь Ctrl и Alt для правой руки, а 's' для левой)). Стремитесь к эргономичности.

Вернемся к теме. Возникает вопрос: куда же деть Return? А его вполне можно "повесить" на место правого Ctrl или на место Menu, если таковое имеется (между правым Alt и правым Ctrl). На некоторых ноутбуках фирмы Apple вообще нет правого Ctrl, так что данная замена будет очень кстати.

В итоге мы имеем Control_L на месте клавиши CapsLock, Control_R на месте клавиши Return и Return на месте Menu (или правого Ctrl).

Запускаем xev. Нажимаем клавишу "Return" (или "Enter"), вылавливаем keycode:

  
state ..., keycode 36 (keysym ..., Return), same_screen ...,
  
  
xmodmap -e "keycode 36 = Control_R"
xmodmap -e "add Control = Control_R"
  

Получаем Control_R на месте клавиши Return. Для CapsLock и левого Ctrl:

  
xmodmap -e "keycode 66 = Control_L"
xmodmap -e "add Control = Control_L"
  

Теперь назначаем Return на Menu, к примеру.

  
xmodmap -e "keycode 117 = Return"
  

Не забудьте использовать xev для определения keycode.

Итак, у нас высвободились две клавиши. Правый Ctrl и левый. Некоторые "вешают" цикличное переключение раскладки клавиатуры на левый Ctrl. Думаю, что это слишком "жирно". Более грамотно было бы настроить переключение по Ctrl+1 (english), Ctrl+2 (russian) или Alt+1, Alt+2, или Fn+j, Fn+k, или каким-либо другим комбинациям. Возможно помощь в этом сможет оказать статья "Emacs, X Window и единое переключение раскладки клавиатуры".

Как же использовать высвободившиеся левый и правый Ctrl? Для меня было удобно сделать так. При нажатии правого Ctrl получать С-H в Emacs (Ctrl + Hyper), левого Ctrl -- C-s (где 's' не 's', а Super). После переназначения с помощью xmodmap получаем такую штуку. При нажатии правого Ctrl + 'k' получаем С-H-k, Ctrl + Shift + k -- C-S-H-k, Ctrl + Alt + k -- C-M-H-k. С левым Ctrl по аналогии. То есть открывается простор для назначения новых биндингов, которые вполне легко использовать.

Теперь к практической части. Пускаем xev, находим keycode для левого и правого Ctrl. Берем, например, какие-нибудь braille_dot_* и назначаем:

  
xmodmap -e "keycode 37 = braille_dot_5 NoSymbol Control_L"
xmodmap -e "keycode 109 = braille_dot_6 NoSymbol Control_R NoSymbol NoSymbol NoSymbol NoSymbol Hyper_R"

xmodmap -e "add Mod4 = braille_dot_5"
xmodmap -e "add Mod5 = braille_dot_6"
  

Для меня это сработало. :)

Теперь добавляем все, что мы проделали в ~/.xmodmaprc

  
keycode 117 = Return

keycode 66 = Control_L
add Control = Control_L
keycode 36 = Control_R
add Control = Control_R

keycode 37 = braille_dot_5 NoSymbol Control_L
keycode 109 = braille_dot_6 NoSymbol Control_R NoSymbol NoSymbol NoSymbol NoSymbol Hyper_R

add Mod4 = braille_dot_5
add Mod5 = braille_dot_6
  

И прописываем в ~/.xinitrc

  
xmodmap ~/.xmodmaprc
  

Возможно будут полезны приложения xkeycaps и xbindkeys, как более легкие инструменты для достижения результата.

Для платформы Windows стоит обратить внимание на приложение xkeymacs.

Кому-то покажется все это неудобно, особенно нажимать Menu для получения Return. Могу заверить, что через 2 дня от неудобства не останется и следа. Привыкнуть довольно легко. Так что найдите время, чтобы "наточить топор", господа. В качестве переходного этапа можно для начала обойтись лишь переназначением Control_L на CapsLock, Control_R -- Return, Menu -- Return и отключением левого и правого Ctrl.

Все, теперь остается лишь выучить раскладку клавиатуры Дворака и благодать обязательно снизойдет.

Данная статья -- лишь одна из идей по оптимизации использования клавиатуры. Хотелось бы в комментариях услышать другие подходы в данной области.

Материалы к ознакомлению:

man xev
man xmodmap
/usr/include/X11/keysymdef.h

28 янв. 2008 г.

Emacs, X Window и единое переключение раскладки клавиатуры

Aim

Цель: Сделать переключение раскладки X Window и внутренней раскладки Emacs по одним и тем же комбинациям клавиш: Fn+j (английский), Fn+k (русский), Fn+l (итальянский).


X Window

Добавляем Option "XkbLayout" "us,ru(winkeys),it" в секцию "Input Device" в файл xorg.conf


emxkb

Смотрим http://akshaal.livejournal.com/58473.html, модифицируем код, получаем emxkb.c . Компилируем:

  
    gcc -L/usr/X11R6/lib -lX11 -o emxkb emxkb.c
  
При исполнении emxkb 0 раскладка переключается на "us", emxkb 1 -- "ru(winkeys)", emxkb 2 -- "it". А если значение WM_CLASS окна равно строке "emacs", то emxkb шлет нажатие клавиш F31, F32 или F33 (в зависимости от параметра) и устанавливает раскладку для X Window на "us".


emxkb.c:

  
/* Thanks to Evgeny Chukreev (C) 2005, GNU GPL */
/* See http://akshaal.livejournal.com/58473.html */

/* Modified a little by Bzek .) */

/* Compilation: gcc -L/usr/X11R6/lib -lX11 -o emxkb emxkb.c */

/* Usage:
 *      emxkb 0  # For first group
 *      emxkb 1  # For second group 
 *      emxkb 2  # For third group
 */

#include <X11/Xlib.h>
#include <X11/XKBlib.h>
#include <X11/keysym.h>
#include <X11/Xutil.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* For locking a group */
int lock_group (int window_id, int group);

/* For sending a key to Emacs */
int send_key_to_emacs (Display *display, int window_id, int group);


/* Main function */
int
main (int argc, char *argv[]) {

    Display *display;
    XClassHint class_hint;
    Window focus;
    int revert, group;

    /* Check arguments */
    if (argc < 2) {
        fprintf (stderr, "Usage: %s <group>\n", argv[0]);
        return -1;
    }

    /* Parse arguments */
    group = strtol (argv[1], NULL, 0);

    /* Open display */
    display = XOpenDisplay (NULL);

    if (!display) {
        fprintf (stderr, "%s: Can't open display\n", argv[0]);
        return -2;
    }

    /* Get window id */
    if (!XGetInputFocus (display, &focus, &revert)) {
        fprintf (stderr, "%s: Can't get focus\n", argv[0]);
        return -3;
    }

    /* Get WM_CLASS */
    XGetClassHint (display, focus, &class_hint);
/*     printf ("WM_CLASS: %s\n", class_hint.res_name); */

    if (class_hint.res_name != NULL
        && !strncmp (class_hint.res_name, "emacs", strlen("emacs"))) {
        /* Yeah, Emacs! Send a key. */
        if (!send_key_to_emacs (display, focus, group)) {
            fprintf (stderr, "%s: Failed during sending a key to Emacs\n", argv[0]);
            return -4;
        }

        /* Change group to 0 (it should be "us") for Emacs */
        group = 0;
    }

    if (!lock_group (focus, group)) {
        fprintf (stderr, "%s: Failed during locking group\n", argv[0]);
        return -5;
    }

    /* Close display */
    XCloseDisplay (display);

    /* That is all */
    return 0;
}


int
send_key_to_emacs (Display *display, int window_id, int group) {

    XKeyEvent event;

    /* Init event */
    memset (&event, 0, sizeof (event));
    event.window = window_id;
    event.display = display;
    event.root = RootWindow (display, DefaultScreen (display));
    event.state = 0;

    switch (group) {
    case 0:
        event.keycode
            = XKeysymToKeycode (display, XStringToKeysym ("F31"));
        break;
    case 1:
        event.keycode
            = XKeysymToKeycode (display, XStringToKeysym ("F32"));
        break;
    case 2:
        event.keycode
            = XKeysymToKeycode (display, XStringToKeysym ("F33"));
        break;
    default:
        event.keycode
            = XKeysymToKeycode (display, XStringToKeysym ("F31"));
        break;
    }

    /* Send KeyPress event */
    event.type = KeyPress;

    if (!XSendEvent (display, window_id, False, 0, (XEvent *) &event)) {
        fprintf (stderr, "send_key_to_emacs(): Can't send KeyPress event\n");
        return -1;
    }

    /* Send KeyRelease event */
    event.type = KeyRelease;

    if (!XSendEvent (display, window_id, False, 0, (XEvent *) &event)) {
        fprintf (stderr, "send_key_to_emacs(): Can't send KeyRelease event\n");
        return -2;
    }

    XSync (display, False);

    return 1;
}


int
lock_group (int window_id, int group) {

    Display *xkb_display;
    int res;

    /* Open xkb display */
    xkb_display = XkbOpenDisplay (NULL, NULL, NULL, NULL, NULL, NULL);

    if (!xkb_display) {
        fprintf (stderr, "lock_group(): Can't open display\n");
        return -1;
    }

    /* Init XKB */
    res = XkbQueryExtension (xkb_display, NULL, NULL, NULL, NULL, NULL);
    if (!res) {
        fprintf (stderr, "lock_group(): Can't init XKB\n");
        return -2;
    }

    /* Set Focus */
    if (window_id > 0) {
        XSetInputFocus (xkb_display, window_id, RevertToParent, CurrentTime);
        XSync (xkb_display, False);
    }

    /* Lock Group */
    res = XkbLockGroup (xkb_display, XkbUseCoreKbd, abs (group % 4));
    if (!res) {
        fprintf (stderr, "lock_group(): Can't lock group\n");
        return -3;
    }

    XSync (xkb_display, False);
            
    /* Close xkb display */
    XCloseDisplay (xkb_display);

    return 1;
}
  

Window Manager

Запускаем xev, жмем Fn+j, Fn+k, Fn+l, получаем что-то типа:

  
    state ..., keycode ... (keysym ..., KP_End), ...
    state ..., keycode ... (keysym ..., KP_Down), ...
    state ..., keycode ... (keysym ..., KP_Next), ...
  
То есть, для Fn+j (вероятно в вашем случае будет не KP_End) -- это KP_End, Fn+k -- KP_Down, Fn+l -- KP_Next Теперь прописываем в window manager, чтобы по KP_End запускалось emxkb 0, по KP_Down -- emxkb 1 и по KP_Next -- emxkb 2 .



xmodmap

Определеям keycode для F31, F32, F33:

  
xmodmap -e "keycode 241 F31"
xmodmap -e "keycode 242 F32"
xmodmap -e "keycode 243 F33"
  
На будущее добавляем в файл ~/.xmodmaprc строки:
  
keycode 241 F31
keycode 242 F32
keycode 243 F33
  
В ~/.xinitrc добавляем:
  
    xmodmap ~/.xmodmaprc
    

Emacs

Добавляем в .emacs (или init.el) строки:

  
(defun reset-flyspell-with-new-dict (dict)
  "Set new dictionary and restart flyspell"

  (unless (equal dict ispell-local-dictionary)
    (setq ispell-local-dictionary dict)
    (when flyspell-mode
      (flyspell-mode)
      (flyspell-mode)))

  (when flyspell-mode
    (save-excursion
      (flyspell-region (window-start) (window-end))))

  (message nil))

(global-set-key [(f31)]
                (lambda ()
                  (interactive)
                  ;; (reset-flyspell-with-new-dict "american")
                  (inactivate-input-method)))

(global-set-key [(f32)]
                (lambda ()
                  (interactive)
                  ;; (reset-flyspell-with-new-dict "russian")
                  (set-input-method 'russian-computer)))

(global-set-key [(f33)]
                (lambda ()
                  (interactive)
                  ;; (reset-flyspell-with-new-dict "italian")
                  (set-input-method 'italian-keyboard)))


(defun toggle-specified-isearch-input-method (new-input-method)
  "Toggle specified input method in interactive search."
  (interactive)
  (let ((overriding-terminal-local-map nil)))

  (if (eq new-input-method 'default-method) 
      (inactivate-input-method)
    (set-input-method new-input-method))
    
  (setq isearch-input-method-function input-method-function
        isearch-input-method-local-p t)
  (setq input-method-function nil)
  (isearch-update))


(add-hook 'isearch-mode-hook
          (lambda ()
            (define-key isearch-mode-map (kbd "<f31>") 
              (lambda ()
                (interactive)
                (toggle-specified-isearch-input-method 'default-method)))

            (define-key isearch-mode-map (kbd "<f32>") 
              (lambda () 
                (interactive) 
                (toggle-specified-isearch-input-method 'russian-computer)))

            (define-key isearch-mode-map (kbd "<f33>") 
              (lambda () 
                (interactive) 
                (toggle-specified-isearch-input-method 'italian-keyboard)))))
  
Для необходимости можно раскомментировать строки с вызовом (reset-flyspell-with-new-dict).



xxkb

Если есть желание использовать xxkb, то вот конфиг, с которым был протестирован весь этот "костыль":

  
XXkb.group.base: 1
XXkb.group.alt: 2

XXkb.mainwindow.type: normal
! possible values - normal, top, tray, wmaker

XXkb*label.text.1: En
XXkb*label.text.2: Ru
XXkb*label.text.3: It

XXkb.mainwindow.label.enable: yes
XXkb.mainwindow.enable: yes
XXkb.mainwindow.appicon: no
XXkb.mainwindow.geometry: 15x15-0+0
XXkb.mainwindow.label.background: yellow
XXkb.mainwindow.label.foreground: blue4
XXkb.mainwindow.label.font: -misc-*-r-*-13-*

XXkb.button.enable: no

XXkb.controls.add_when_start: yes
XXkb.controls.add_when_create: yes
XXkb.controls.add_when_change: no
XXkb.controls.two_state: no
XXkb.controls.button_delete: yes
XXkb.controls.button_delete_and_forget: yes
XXkb.controls.mainwindow_delete: yes
XXkb.ignore.reverse: no

XXkb.app_list.wm_class_class.alt_group1: emacs Emacs
  

Последняя строчка впрочем даже и не нужна.

Порой (у меня это случалось только с одним приложением и довольно редко) xxkb начинает капризничать и менять обратно раскладку, тогда помогает клик по значку xxkb (чудесатое решение :)).

В xmonad и некоторых других wm, по свидетельствам очевидцев, xxkb вообще не хочет работать с этим "костылем", не давая переключать раскладку с помощью emxkb. Если для вас это так, тогда стоит посмотреть в сторону другого индикатора раскладки клавитуры (например в сторону xneur).



Тестировалось под X.Org 6.7, xxkb (1.10 и 1.11), icewm, fluxbox, ion3, awesome.

При замечаниях и более элегантных решениях просьба оставить комментарий.

Спасибо Павлу Вязовому за помощь.

13 окт. 2007 г.

Несколько прибамбасов для более удобной работы с текстом.

Захват всей строки.

Этот прибамбас я подсмотрел в Textmate. Заключается он в том, чтобы замаркировать всю строку и переместить курсор в начало следуюшей строки. При этом совершенно неважно, в каком месте строки находился курсор до этого.

 
(defun my-mark-line ()
  (interactive)
  (beginning-of-line)
  (cua-set-mark)
  (end-of-line)
  (next-line)
  (beginning-of-line))

(global-set-key [(alt k)] 'my-mark-line)
 

Дублирование строки одной командой.

Ну тут, помоему, и объяснять много не надо: обыкновенное дублирование строки по alt-d

 
(defun my-copy-line ()
  (interactive)
  (kill-ring-save (line-beginning-position) (line-end-position))
  (end-of-line)
  (newline)
  (cua-paste nil))

(global-set-key [(alt d)] 'my-copy-line)
 

Новая строка.

Создаём новую строку с отступом.

 
(defun my-new-line ()
  (interactive)
  (end-of-line)
  (newline-and-indent))

(global-set-key [(alt o)] 'my-new-line)
 

Комментарии.

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

 
(defun my-comment-or-uncomment-region (arg)
  (interactive "*P")
  (comment-normalize-vars)
  (if (and (not mark-active) (save-excursion (beginning-of-line) (not (looking-at "\\s-*$"))))
  (comment-or-uncomment-region (line-beginning-position) (line-end-position))
  (comment-dwim arg)))

(global-set-key (kbd "A-/") 'my-comment-or-uncomment-region)
 

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

 
(setq comment-style 'indent)
 

Поиск парной скобки.

Мне дико нравился в своё время поиск парной скобки в Vim по нажатию %. Поэтому решил сделать подобное и в Emacs. Вот что получилось:

 
(defun my-match-paren (arg)
  (interactive "p")
  (cond ((looking-at "\\s\(")
  (forward-list 1) (backward-char 1))
  ((looking-at "\\s\)")
  (forward-char 1) (backward-list 1))
  (t (self-insert-command (or arg1)))))

(global-set-key (kbd "A-%") 'my-match-paren)
 

Ну и напоследок.

Этот прибамбас облегчает на порядок написание SGML/HTML/XML тегов.

 
(defun html-surround-region-with-tag (tag-name beg end)
  (interactive "sTag name: \nr")
  (insert "<" tag-name ">")
  (insert "")
  (goto-char (+ end 2 (length tag-name)))
  )

(global-set-key [(control <)] 'html-surround-region-with-tag)
 

Жмём control-< и даём название тега без знаков '<' и '>'. Всё осталное Emacs сделает сам.

30 июл. 2007 г.

Сокращения/snippets и лучший редактор этой вселенной

Что я подразумеваю под сокращениями (abbrevs)? Возможно, вы уже видели это в TextMate для MacOS X или в какой-нибудь интегрированной среде разработки. В общем случае выглядит это так: вы набираете в редакторе for, а он (редактор) сразу после набора этого слова заменяет его на соответствующий ему шаблон, например такой:


for (_;_;_) {
    _
}

Причем курсор появляется в местах, помеченных как "_" (я буду называть их "точками перехода"). Между такими местами можно переключаться с помощью какой-нибудь клавиши (обычно это Tab). Демонстрацию работы такой функции можно посмотреть здесь.

По умолчанию в Emacs (по крайней мере в последних версиях) есть так называемые skeleton'ы, но с ними не очень удобно работать, поскольку точка перехода может быть только одна. В таких условиях после каждого банального if'а вам придется орудовать стрелками, чтобы перейти в тело цикла. Как по мне, так проще и быстрее код пишется без таких вот сокращений. Кроме того, при использовании skeleton'ов текст вставляетя без нормального форматирования отступов. Приходится либо делать indent вручную, либо дописывать костыли.

Что касается сторонних скриптов (в которых проблема с единственной точкой перехода решена), то их вполне достаточно; самые популярные - snippet.el и smart-snippet. Второй является надстройкой над первым. Однако ни тот, ни другой, мне настроить так и не удалось. Да, для С/С++ все замечательно (кроме форматирования отступов, к которому эти скрипты относятся прямо скажем очень своеобразно), но к ruby-mode приделать их так и не получилось. Поэтому я расскажу о другом, не столь популярном скрипте - msf-abbrev.el, который гораздо проще в настройке (как мне показалось).

У меня в домашнем каталоге есть директория, куда я складываю все сторонние скрипты для Emacs (у меня это ~/emacs). Если у вас еще нет такой, рекомендую ее создать и добавить в ваш ~/.emacs следующую строку:

(add-to-list 'load-path "~/emacs")

После этого чтобы загрузить какой-нибудь сторонний скрипт (foobar.el), вам нужно будет поместить его в этот каталог и дописать в конфиг что-нибудь вроде (require 'foobar) или (load "foobar"). Я рассчитываю на то, что вы скачали msf-abbrev.el и поместили его в свой аналог ~/emacs. На сайте автора есть архив с его сокращениями, но мне они показались не очень удобными. Там же есть ссылка на архив сокращений для всех функций glibc.

Что ж, приступим к настройке собственно скрипта. Открывайте ~/.emacs и добавляйте туда такие строки:


(require 'msf-abbrev)
(setq-default abbrev-mode t)
(setq save-abbrevs nil)
(setq msf-abbrev-root "~/emacs/abb")
(global-set-key (kbd "C-c a") 'msf-abbrev-define-new-abbrev-this-mode)
(add-hook 'ruby-mode-hook 'msf-abbrev-load)

В первой строке подгружается сам скрипт (если он еще не был загружен раньше), после чего все его функции становятся доступными. Во второй строке мы говорим, чтобы Emacs по умолчанию включал подрежим abbrev (сокращения будут работать в этом режиме). Если деятельность скрипта начнет вам мешать, выполните M-x abbrev-mode. В третьей строке мы говорим, чтобы Emacs не записывал наши сокращения в ~/.abbrevs. По умолчанию эта функция включена, но при использвании msf-abbrevs в ней нет необходимости. Далее мы определяем каталог, где будут храниться наши сокращения (создайте свой и вставьте вместо "~/emacs/abb").
После этого мы задаем клавиатурное сочетание "C-c a", которая будет создавать для нас новое сокращение для текущего режима. В последней строке добавляем новый хук к ruby-mode (я буду показывать все на примере Ruby). Вообще можно обойтись и без хука, вставив вместо этого строку (msf-abbrev-load), но я люблю, чтобы скрипт загружался только в нужных режимах. Если вы пишете на других языках, то вместо ruby-mode-hook вставьте хук для своего языка (c-mode-hook, java-mode-hook, python-mode-hook).

Все, больше никакой правки .emacs не потребуется. Теперь будем обучать редактор нашим сокращениям. Загружайте по-новой Emacs, переходите в нужный режим (тот, для которого будете задавать сокращения и для которого настроили загрузку скрипта через хук: M-x ruby-mode). Теперь жмите "C-c a". В минибуфере появится сообщение о том, что директория ~/emacs/abb/ххх-mode не найдена и тут же вам предложат ее создать. Соглашайтесь. Дальше вас спросят об имени сокращения. Имя сокращения соответствует его вызову. То есть если вы дадите ему имя for, то и вызываться оно будет после набора в редакторе слова "for" (разумеется, только в том режиме, для которого оно определено). После ввода имени сокращения (пусть для определенности это будет тот же for), откроется новый буфер. Вставьте в него что-то вроде этого (напомню, что примеры у меня для Ruby):


for <field "name"> in <field "exp"> do
    <endpoint>
end

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


for name in exp do

end

То, что я выделил наклонным шрифтом, скорее всего будет выделено в самом редакторе каким-нибудь цветом (у меня это серый). Это точки перехода. В между ними можно перемещаться по клавишам Tab и Shift-Tab (вперед и назад, соответственно). После нажатия Tab в последней точке перехода, курсор переместится в то место, где мы указали endpoint. Думаю, в целом смысл понятен. Теперь давайте заглянем в ~/emacs/abb/ruby-mode/ и посмотрим, что же там появилось. А появился там обычный текстовый файл с именем for, содержащий наш шаблон.

Кроме field и endpoint скрипт принимает еще несколько ключевых слов: cursor, varlookup, elisp, query, choose и comment. Из них отмечу query, который вместо создания точки перехода просто спрашивает вас в минибуфере, что вставить в этом месте и choose, с помощью которого можно организовать комбо-бокс с несколькими вариантами выбора. Про остальные можете почитать на странице проекта.

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

20 июл. 2007 г.

Настройка Emacs для отправки почты через Gmail

Вчера приступил к настройке давно задуманной вещи, которая так и не завелась у меня в Emacs под Windows - скрещиванию Gnus и Gmail, чтобы можно было читать рассылки в удобном емаксовом интерфейсе. Вчера удалась только одна часть - настроил отправку почты через Gmail, а вот скачивание почты через pop3 так и не заработало - сегодня буду пробовать еще раз, и может быть настрою fetchmail, для автоматического вытягивания почты (что не хочется, ибо он будет вытягивать почту и тогда, когда меня нет у компа и имею доступ только через web интерфейс). Настройка отправки почты через Gmail описана в нескольких блогах, но они все имели одну и ту же ошибку - не указывали один пакет (starttls), что не позволило сразу отправку. В общем, для отправки почты нужно сделать следующее:
  1. поставить gnutls для того, чтобы smtpmail мог выполнить команду STARTTLS
  2. В .gnus написать следующее:

    (setq user-mail-address "my-email@gmail.com")
    (setq send-mail-function 'smtpmail-send-it
    message-send-mail-function 'smtpmail-send-it
    smtpmail-starttls-credentials '(("smtp.gmail.com" 587 nil nil))
    smtpmail-auth-credentials '(("smtp.gmail.com" 587 "my-email@gmail.com" nil))
    smtpmail-default-smtp-server "smtp.gmail.com"
    smtpmail-smtp-server "smtp.gmail.com"
    smtpmail-smtp-service 587
    smtpmail-debug-info t)
    (require 'starttls)
    (require 'smtpmail)
  3. протестировать отправку, при отправке письма, smtpmail спросит пароль, и отправит письмо. Поскольку в данном конфиге включена отладка, то вся SMTP сессия будет выводиться в буфер с именем *trace of SMTP ...*
Что означает каждая строка в приведенном конфиге?:
  • первая строка задает адрес пользователя;
  • вторая и третья строка заставляют отправлять почту через SMTP, а не через локальный почтовый сервер;
  • четвертая и пятая строки задают для какого сервера надо использовать STARTTLS, и какие данные пользователя будут указанны для данного сервера. Если не боитесь, то можете указать пароль сразу в данном конфиге, или сохранить его в файле ~/.authinfo и тогда для smtpmail-auth-credentials можно записать (expand-file-name "~/.authinfo") вместо того, что там сейчас написано;
  • 6,7 и 8 строки задают имя и порт сервера, через который будет производиться отправка писем;
  • 9-я строка включает отладку, что приводит к выводу SMTP сессии в; отдельный буфер. Если все будет работать нормально, то позже можно эту строку удалить
  • 10-я и 11-я строки загружают нужные пакеты.
Вот и все :-) Оригинал статьи - тут.

6 июн. 2007 г.

Tip #3. Emacs'овые биндинги в программах под MS Windows

Давно уже обнаружил и даже немного попользовал замечательную программу XKeymacs, которая реализует поддержку сочетаний клавиш a-la Emacs для многих программ Windows. Я до этого уже делал такое в виде переназначений многих клавиш в MS Word, в котором приходилось много писать одно время, но не было поддержки сочетаний из нескольких клавиш, например, C-x h, к которым руки уже привыкли. Программа позволяет выбирать какие сочетания клавиш будут доступны программе, ну и конечно можно выбрать для каких программ поддержка будет предоставляться. Тем кто уже совсем подсел на Emacs, очень советую эту программу. По себе знаю - очень часто пальцы срабатывают раньше чем ты осознаешь что ты работаешь не в Emacs ;-) Кросспост из моего журнала

23 мая 2007 г.

Tip #2. Быстрое переключение между буферами

Обычно в Emacs'e переключение между буферами производится с помощью сочетания клавиш C-x b, или путем выбора нужного буфера в меню. Однако, при работе с большим количеством файлов, эти методы не совсем удобны. Поэтому, были разработаны пакеты для более удобного переключения между буферами в Emacs'e. Один из таких пакетов - iswitchb, который показывает список буферов, которые соответствуют тому тексту, который вы набираете. Список буферов меняется по мере набора слова или его части, к тому же вы можете набирать любую часть слова, что особенно полезно, если вы имеете много файлов начинающихся с одного префикса. В остальном, iswitchb полностью заменяет стандартные механизмы Emacs. Данный пакет идет в поставке Emacs 22 (текущий CVS), а для предыдуших версий, его можно скачать с emacs-wiki. Настройка пакета тоже проста - надо лишь поместить следующие строки в файл инициализации:
(require 'iswitchb)
(iswitchb-mode 1)
Для того, чтобы не отображались некоторые буфера, их имена можно поместить в список игнорирования, который хранится в переменной iswitchb-buffer-ignore. Вот, например, минимальный список таких буферов:
(add-to-list 'iswitchb-buffer-ignore "*Messages*")
(add-to-list 'iswitchb-buffer-ignore "*Backtrace")
(add-to-list 'iswitchb-buffer-ignore "*Quail Com")
(add-to-list 'iswitchb-buffer-ignore "*Buffer")
(add-to-list 'iswitchb-buffer-ignore "*fsm-debug")
(add-to-list 'iswitchb-buffer-ignore "*Completions")
(add-to-list 'iswitchb-buffer-ignore "^[tT][aA][gG][sS]$")
Для того, чтобы обеспечить кэширование информации, можно использовать пакет filecache, который умеет интегрироваться с iswitchb. Этот пакет также идет в составе Emacs 22. Для его использования поместите в .emacs следующие строки:
(require 'filecache)
(load "iswitchb-fc")
Про другие пакеты, обеспечивающие подобную функциональность, вы можете почитать на Emacs WiKi - в разделе про iswitchb, есть ссылки на них

18 мая 2007 г.

Tip #1

Преамбула

Иногда, находясъ в какой-нибудь функции, требуется быстро перейти на предыдущую или последующую объявленную функцию в коде. Использовать для этого способ, описанный в Tip #0, мне показалось, немного накладно: для этого нужно вызвать команду my-show-functions-list, перейти в буфер *Occur* и выбрать нужную функцию. Гораздо удобнее было бы "скакать" по объявлениям функций, используя определённые клавишные комбинации, оставаясь при этом в текущем буфере.

Задача

Удобное и быстрое перемещение между функциями в текущем буфере, без использования буфера *Occur*.

Решение

Для решения задачи нам потребуются стандартные команды Emacs search-forward-regexp и search-backward-regexp. Как можно догадаться из названий, эти две команды позволяют осуществлять поиск по регулярному выражению в текущем буфере. В качестве аргумента для поиска, мы будем использовать регулярное выражение из Tip #0. Нам также потребуется создать две новые функции с названием my-jump-to-function-forward и my-jump-to-function-backward.

Функции my-jump-to-function-forward и my-jump-to-function-backward

Взяв за основу функцию my-show-functions-list из Tip #0, получаем следуюший Emacs lisp код:


(defun my-jump-to-function-forward()
  (interactive)
  (search-forward-regexp
   "^\t+\\(function\\|public function\\|protected function\\|private function\\|public static\\|protected static\\|private static\\|def\\)"
   ))

(defun my-jump-to-function-backward()
  (interactive)
  (search-backward-regexp
   "^\t+\\(function\\|public function\\|protected function\\|private function\\|public static\\|protected static\\|private static\\|def\\)"
   ))

Теперь осталось назначить клавишные комбинации. Для себя я выбрал ^N и ^P.


(global-set-key [(control n)] 'my-jump-to-function-forward)
(global-set-key [(control p)] 'my-jump-to-function-backward)

Всё. Можно наслаждаться быстрыми "прыжками" между функциями, оставаясь при этом в текущем буфере.

17 мая 2007 г.

Tip #0

Задача

Удобное и быстрое перемещение между функциями в текущем буфере.

Решение

В Emacs есть дико полезная команда list-matching-lines. Эта команда принимает, в качестве аргумента, регулярное выражение и возвращает обратно найденые совпадения, в виде списка в отдельный буфер *Occur*. Вот её-то мы и будем использовать для решения задачи.

Подбираем регулярное выражение

Так как я в основом работаю с PHP и Python, то регулярное выражение будет составлено с учётом только этих двух языков.


^\t+\\(function\\|public function\\|protected function\\|private function\\|public static\\|protected static\\|private static\\|def\\)

Конечно, вся эта бодяга выглядет немного коряво, можно сделать гораздо изящнее. Но это было первое, что пришло мне в голову и оно работает:)

Функция my-show-functions-list

Создав и проверив регулярное выражение, можно заняться созданием специальной функции с последующим размещением её в .emacs (конфигурационный файл редактора). Функцию я обозвал my-show-functions-list. Если вы создаёте новую функцию для Еmacs, советую придумать какой-нибудь префикс (у меня это "my-") и всегда использовать его в начале имени вашей новой функции. Это позволит в дальнейшем удобно отделять ваши собственные команды от стандартных команд Еmacs.


(defun my-show-functions-list()
  (interactive)
  (list-matching-lines "^\t+\\(function\\|public function\\|protected function\\|private function\\|public static\\|protected static\\|private static\\|def\\)"))

Теперь осталось прописать комбинацию клавиш для быстрого вызова нашей новой команды. Я это дело повесил на ^F11 (Control + F11).


(global-set-key [C-f11] 'my-show-functions-list)

Вот собственно и всё. Теперь нужно перегрузить Emacs и открыть какой-нибудь *.php или *.py файл с некоторым кол-вом функций для проверки того, что у нас получилось. При нажатии ^F11 будет открыто новое окно с буфером *Occur*, в котором приведён список всех объявленных в файле функций. Перейдя в буффер *Occur* и выбрав из списка, посредством клавиши Return нужную функцию, вы, тем самым, переместите курсор на строку с объявлением той самой функции в вашем файле.