Emacs 的其他编辑技巧

数字增减和循环改变文字
智能标记
align-regexp
C-w 的绑定

数字增减和循环改变文字

;; 下面的几个函数可以实现自动增加数字,和循环改变文本的功能。定义方法是
;; 1. 一个 (regexp . (lambda () ....) 的方式。 下面的第一个定义就提供了自动增加
;; 和减少数字的功能。
;; 2. 一个含有字符串的 list , 那么就会在这些字符串中循环选择。
;; M-x wcy-rotate-text 可以接受 C-u 的参数,负数表示减少数字或者反向循环。
;; 参数的大小可以指定增加或者减少多少,或者循环的步长。

(defvar wcy-rotate-text-definations
  '(("-?[0-9]+" . (lambda ()
                    (format "%d" (+ rotate-arg (string-to-number (match-string 0))))))
    ("zero" "one" "two" "three" "four" "five" "six" "seven" "eight" "nine")
    ("Sunday"  "Monday"   "Tuesday"   "Wednesday"   "Thursday"   "Friday"
     "Saturday")
    )
  "
a list of ROT text defination. each element is a defination.
element can be a list of string.
element can be a cons. (REGEXP . func)
if REGEXP matched, func is called with no args, return value is the next value.
")

(defun wcy-rotate-text-aux ()
  (catch 'break
    (mapc
     #'(lambda (def)
         (let ((regexp (if (functionp (cdr def))
                           (car def)
                         (mapconcat 'regexp-quote def "\\|")))
               (func (if (functionp (cdr def))
                         (cdr def)
                       #'(lambda ()
                           (let* ((l (length def))
                                  (r (length (member (match-string 0) def)))
                                  (i (% (+ rotate-arg (- l r)) l)))
                             (format "%s" (nth i def)))))))
           (if (re-search-forward regexp (line-end-position) t nil)
               (throw 'break (funcall func)))))
     wcy-rotate-text-definations)
    nil))
(defun wcy-rotate-text(rotate-arg)
  (interactive "p")
  (let ((x (wcy-rotate-text-aux)))
    (when x
      (replace-match x)
      (goto-char (match-beginning 0)))))

智能标记

;;这个功能绑定在 C-3 上。这个功能就是根据光标的所在位置,智能的选择一块区域,也就
;;是设置成为当前的 point 和 mark。这样就可以方便的拷贝或者剪切,或者交换他们的位
;;置。

;;如果当前光标在一个单词上,那么区域就是这个单词的开始和结尾分别。
;;如果当前光标在一个连字符上,那么就选择包含连字符的一个标识符。

;;这个两个的是有区别的,而且根据不同的 mode 的语法定义,连字符和单词的定义也不一样。
;;例如 C mode 下, abc_def_xxx , 如果光标停在 abc 上,那么就会选择 abc 这个单词。 如果
;;停在下划线上,那么就会选择 abc_def_xxx 。

;;如果当前光标在一个双引号,单引号,一个花括号,方括号,圆括号,小于号,或者大于号,
;;等等,那么就会选择他们对应的另一个括号之间的区域。 引号中的 escape 字符也是可以
;;自动识别的。嵌套关系也是可以识别的。这一点可以和 VIM 中的 % 的功能类比。

(defun wcy-mark-some-thing-at-point()
  (interactive)
  (let* ((from (point))
         (a (mouse-start-end from from 1))
         (start (car a))
         (end (cadr a))
         (goto-point (if (= from start )
                            end
                       start)))
    (if (eq last-command 'wcy-mark-some-thing-at-point)
        (progn
          ;; exchange mark and point
          (goto-char (mark-marker))
          (set-marker (mark-marker) from))
      (push-mark (if (= goto-point start) end start) nil t)
      (when (and (interactive-p) (null transient-mark-mode))
        (goto-char (mark-marker))
        (sit-for 0 500 nil))
      (goto-char goto-point))))
(define-key global-map (kbd "C-3") 'wcy-mark-some-thing-at-point)
(define-key global-map (kbd "M-C-SPC") 'wcy-mark-some-thing-at-point)

align-regexp

M-x align-regexp 可以方便的对齐一些文字。 例如

    Fred (123) 456-7890
    Alice (123) 456-7890
    Mary-Anne (123) 456-7890
    Joe (123) 456-7890

选择这段文字之后, M-x align-regexp ,然后根据提示输入, ``('' 这样就可以得到下 面的结果:

    Fred      (123) 456-7890
    Alice     (123) 456-7890
    Mary-Anne (123) 456-7890
    Joe       (123) 456-7890

C-w 的绑定

我把 C-w 绑定 backward-kill-word, 这样就和 bash 的 input-line 是一致的了。我试 了试,还挺好用。但是原来的 C-w 是和 kill-region 绑定的。改变习惯还是很难的。以前 我不喜欢 transient-mark-mode ,但是现在发现她可以派上用场了。可以在激活选择区域 的时候,C-w 和 kill-region 绑定,否则和 backward-kill-word 绑定,感觉不错。

(defmacro wcy-define-2bind-transient-mode (funname cmd-mark-active
                                                   cmd-mark-no-active)
  `(defun ,funname ()
     (interactive)
     (if mark-active
         (call-interactively ,cmd-mark-active)
       (call-interactively ,cmd-mark-no-active))))
;; 和 bash 中的类似的快键,不用再按 backspace 了。
(global-set-key "\C-w"     'wcy-backward-kill-word-or-kill-region)
(wcy-define-2bind-transient-mode
 wcy-backward-kill-word-or-kill-region
 'kill-region
 'backward-kill-word)

我定义了一个 macro , 可以方便的定义这种双重绑定,也就是,在 mark-active 时运行 一个函数,否则运行另一个函数。