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 сделает сам.

5 комментариев:

Denis Dzyubenko комментирует...

порылся в своих конфигах, нашел много интересного, то что делал и уже забыл об этом :)
насчет поиска парной скобки:
;:*========================
;:* VI-style matching parenthesis
;: From Eric Hendrickson edh @ med.umn.edu
(defun shad-match-paren (arg)
"Go to the matching parenthesis if on parenthesis otherwise insert
%."
(interactive "p")
(cond ((looking-at "[([{]") (forward-sexp 1) (backward-char))
((looking-at "[])}]") (forward-char)
(backward-sexp 1))
(t (insert "%"))))
(global-set-key [(?%)] 'shad-match-paren)

Меня всегда напрягало длинная дефолтная комбинация клавиш для перехода на регистр, поэтому набросал вот такой код. Вставка содержимого регистра или переход на позицию регистра.
(defun my-jump-or-insert-register (register)
"Jump to REGISTER or insert value of REGISTER."
(interactive)
(let ((value (cdr (assq ?a register-alist))))
(cond
((stringp value) (insert-register register))
((markerp value) (jump-to-register register)))))

;; Переход по регистрам по C-A-буква
(let ((char ?a))
(while (<= char ?z)
(global-set-key (vector (list 'control 'meta char))
`(lambda ()
(interactive)
(my-jump-or-insert-register ,char)))
(setq char (+ char 1))))

Анонимный комментирует...

спасибо!

если найдётся ещё парочка таких мелких рецептов, то можно и в пост для блога оформить:)

Denis Dzyubenko комментирует...

фишки имеются, но в последнее время emacs'ом практически не пользуюсь (к сожалению Visual C++ 2005 + VisualAssist намного более фичастые и менее геморные в настройке), поэтому вот еще пара фич которые сразу видно из конфигов.

Давным-давно еще сделал split-dir хранение конфигов в отдельных файлах сгруппированных логически. Вот собственно код который подгружает все .el-файлы из каталога:
defun shad-load-directory (dirname)
"Load all .el files in a directory"
(let ((file-list (directory-files dirname)))
(mapc (lambda (file-name)
(when (string-match "\.el$" file-name)
(load (concat dirname "/" file-name) nil t t)))
file-list)))

(shad-load-directory (expand-file-name "~/etc/emacs/site-lisp"))

ну и с учетом того что ~/etc хранится в git-репозитории получается достаточно удобно imho.

XEmacs фишка для отображения конца буфера - в последней строчке буфера отображает картинку:
(XEmacs
(defun show-eob-pixmap ()
(let ((ext (make-extent (point-min) (point-max))))
(set-extent-property ext 'start-closed t)
(set-extent-property ext 'end-closed t)
(set-extent-property ext 'detachable nil)
(set-extent-end-glyph ext (make-glyph '([xpm :data "\
/* XPM */
static char* eye = {
\"20 11 7 2\",
\"__ c None\"
\"_` c #7f7f7f\",
\"_a c #fefefe\",
\"_b c #7f0000\",
\"_c c #fefe00\",
\"_d c #fe0000\",
\"_e c #bfbfbf\",
\"___________`_`_`___b_b_b_b_________`____\",
\"_________`_`_`___b_c_c_c_b_b____________\",
\"_____`_`_`_e___b_b_c_c_c___b___b_______`\",
\"___`_`_e_a___b_b_d___b___b___b___b______\",
\"_`_`_e_a_e___b_b_d_b___b___b___b___b____\",
\"_`_`_a_e_a___b_b_d___b___b___b___b___b__\",
\"_`_`_e_a_e___b_b_d_b___b___b___b___b_b__\",
\"___`_`_e_a___b_b_b_d_c___b___b___d_b____\",
\"_____`_`_e_e___b_b_b_d_c___b_b_d_b______\",
\"_`_____`_`_`_`___b_b_b_d_d_d_d_b________\",
\"___`_____`_`_`_`___b_b_b_b_b_b__________\",
} ;"]
[string :data "[END]"]))))
)
(add-hook 'find-file-hooks 'show-eob-pixmap))

И кстати в случае когда один и тот же конфиг используется на разных компьютерах или операционных системах может быть полезен безопасный способ подгрузки модулей:
(condition-case err
(and (require 'lazy-lock)
(setq shad-feature-lazy-lock t))
(error (setq shad-feature-lazy-lock nil)))

- данный код пытается подгрузить модуль и в устанавливает флажок в t или nil. Используется далее так:
(when shad-feature-lazy-lock
(do-some-feature-specific-thing))

Еще одна фишка вероятно для начинающих emacs users - спрашивать подтверждение перед выходом при нажатии Ctrl-X Ctrl-C
(define-key global-map [(control x) (control c)]
'(lambda () (interactive)
(cond ((y-or-n-p "Quit editor? ")
(save-buffers-kill-emacs)))))

думаю пока достаточно, тем более что все равно формиротирование сбивается и код выглядит ужасно :)

Павел Вязовой комментирует...

У меня GNU Emacs из CVS (23) - там есть совершенно нативная функция comment-or-uncomment-region. Биндим ее на хоткей и комментирует/раззкомментируем одной коммандой =)

Alex V Koval комментирует...

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

Стандартная комбинация emacs: alt j (meta-j) уже делает это