Saturday, November 24, 2007

Friday, November 16, 2007

[Emacs Tips] 注释

M-x comment-dwim (Do What I Mean) 是最聪明的一种注释方式。如果已经选定了区域,那么就是注释或者反注释;如果没有选定区域,那么就是在这行末尾添加注释。

默认的键绑定是 M-;

注释还可以选择不同的模式,不同注释符号,在不同的编程语言模式下都不同。

控制注释符号的是变量 comment-start 和 comment-end,用 C-h v 查看,用例如 (setq comment-start "//") 修改。

变量 comment-style 控制注释的样式。可以用例如 (setq comment-style 'box) 修改。
以下是各种注释风格的示例。

int main()
{
/* this is a comment line. */
/* comment style 'plain */

/* this is a comment line. */
/* comment style 'indent */

/* this is a comment line. */
/* comment style 'aligned */

/* this is a comment line.
* comment style 'multi-line */

/*
* this is a comment line.
* comment style 'extra-line
*/

/***************************/
/* this is a comment line. */
/* comment style 'box */
/***************************/

/****************************
* this is a comment line. *
* comment style 'box-multi *
****************************/
}
再提供一个直接注释一行的函数。有时候比 comment-dwim 更有效。有选中区域的话就是注释或反注释这个区域;反之注释或者反注释光标所在的行。
(defun huangq-comment-dwim (&optional n)
"Comment do-what-i-mean"
(interactive "p")
(apply 'comment-or-uncomment-region
(if (and mark-active transient-mark-mode)
(list (region-beginning) (region-end))
(if (> n 0)
(list (line-beginning-position) (line-end-position n))
(list (line-beginning-position n) (line-end-position))))))

[Emacs Tips] 插入相邻一行的字符

类似于 VIM 插入状态下的 C-y 和 C-e,也就是插入光标所在上一行或者下一行的字符。
例如: VIM 插入状态下的 C-y 和 C-e,也就是插入光标所在上一行或者下一行的字符。

写程序的时候还是挺有用的
;;;###autoload
(defun my-insert-char-next-line (arg)
"insert char below the cursor"
(interactive "p")
(let ((col (current-column))
char)
(setq char
(save-excursion
(forward-line arg)
(move-to-column col)
(if (= (current-column) col)
(char-after))))
(if char
(insert-char char 1)
(message (concat "Can't get charactor in "
(if (< arg 0)
"previous"
"next")
(progn (setq arg (abs arg))
(if (= arg 1) ""
(concat " " (number-to-string arg))))
" line.")))))

;;;###autoload
(defun my-insert-char-prev-line (arg)
"insert char above the cursor"
(interactive "p")
(my-insert-char-next-line (- arg)))
用的键绑定是 C-x (C-x )
(global-set-key (kbd "C-)") 'my-insert-char-next-line)
(global-set-key (kbd "C-(") 'my-insert-char-prev-line)

Wednesday, November 14, 2007

[Emacs Tips] isearch 查找 (2)

注:有些函数非原创,因为年代长久,很难找到出处,就不一一注明了。

一些加快查找速度的函数。

1. 查找选定区域的内容。Emacs 有无数用来选定 (mark) 的函数,所以选定容易,但是没有直接查找选定内容的函数。下面这个函数提供此功能,按 F3 就是 isearch 当前选定的词,继续按 C-s 就可以查找了。

(defvar my-isearch-string nil)
(setq my-isearch-string "")

(defun my-isearch-region-forward ()
"isearch region if mark is acktive"
(interactive)
(if mark-active
(let ((beg (region-beginning))
(end (region-end)))
(setq my-isearch-string (filter-buffer-substring beg end nil))
(deactivate-mark)
(if (> (length my-isearch-string) 0)
(progn
(goto-char beg)
(isearch-update-ring my-isearch-string)
(add-hook 'isearch-mode-end-hook 'my-isearch-end-hook)
(isearch-mode t) ;hack isearch-forward
(isearch-repeat 'forward)
(message "%s" isearch-string)))) ;print debug msg
(if (> (length my-isearch-string) 0)
(progn
(isearch-repeat 'forward))
(message "no region selected")
)))

(global-set-key (kbd "<f3>") 'my-isearch-region-forward)

(defun my-isearch-end-hook ()
(remove-hook 'isearch-mode-end-hook 'my-isearch-end-hook)
(setq my-isearch-string ""))


2. 查找当前词,类似于 VIM 的 *,这里用的键绑定是 C-* .

(defvar my-isearch-word "")

(defun my-isearch-word ()
  (interactive)
  (when (not mark-active)
    (let (word-beg word-end)
      (unless (looking-at "\\<")
        (if (eq (char-syntax (char-after)) ?w)
            (backward-word)
          (and (forward-word) (backward-word)))
        )
      (setq word-beg (point))
      (forward-word)
      (setq word-end (point))
      (setq my-isearch-word (filter-buffer-substring word-beg word-end nil t))
      (backward-word)
      )
    (when (> (length my-isearch-word) 0)
      (setq my-isearch-word (concat "\\<" my-isearch-word "\\>"))
      (isearch-update-ring my-isearch-word t)
      (add-hook 'isearch-mode-end-hook 'my-isearch-word-end-hook)
      (isearch-mode t t)
      (isearch-repeat 'forward)
      (message "%s" isearch-string))))

(global-set-key (kbd "C-*") 'my-isearch-word)

(defun my-isearch-word-end-hook ()
  (remove-hook 'isearch-mode-end-hook 'my-isearch-word-end-hook)
  (setq my-isearch-word ""))

Tuesday, November 13, 2007

[Emacs Tips] isearch 查找 (1)

isearch (C-s) 是 Emacs 里最常用的查找方式,也是目前为止我在各种软件里,编辑器里用过最舒服的查找方式。

首先这是 incremental search,也就是递增方式的搜索,一边输入一边就开始查找了;
其次有 lazy highlight 功能,低亮显示 buffer 里所有找到的词。
这个功能是由 isearch-lazy-highlight 这个变量控制的,用 C-h v isearch-lazy-highlight 查看这个变量目前是不是真 t。



isearch-mode 也有很多键绑定,用 C-h f isearch-mode 查看。
具体就不详细写了。最常用的 C-w ,查找当前的词。(明天再给出一个更快更方便的查找方式)

建议可以试试相关的 Elisp 插件 color-moccor.el
用了这个以后可以在 isearch 里敲 M-o,列出文件里的搜索结果; 或者 M-O (大写o) 列出所有 buffer 里的对应结果。

[Emacs Tips] 复制一行

从今天开始打算每天用中文介绍一个 Emacs 小技巧。都是很小的技巧而已。

首先是快速复制一行。基本思想是,光标在哪一行就复制哪一行,不用选定区域。如果区域已经选定了,那么就复制区域。类似于 VIM 的yy。

仍旧使用 M-w 的键绑定,和原先的习惯差不多。使用前提是启用了 transient-mark-mode,即高亮选定区域。实际使用中发现每行开头的空格一点用都没有,而且很碍事,所以今天改了一下,一般从第一个非空格的字符开始复制。

这里提供几个函数。
huangq-save-one-line 是复制一行;如果有参数,则从第一个不是空格的字符开始复制。
huangq-kill-ring-save 如果选定了区域,则复制区域;否则复制行。
huangq-save-line-dwim 如果选定了区域,复制区域;否则从第一个不是空格的字符开始复制。

最后是键绑定:
(global-set-key (kbd "M-w") 'huangq-save-line-dwim)

函数的实现:
;;;###autoload
(defun huangq-save-one-line (&optional arg)
"save one line. If ARG, save one line from first non-white."
(interactive "P")
(save-excursion
(if arg
(progn
(back-to-indentation)
(kill-ring-save (point) (line-end-position)))
(kill-ring-save (line-beginning-position) (line-end-position)))))

;;;###autoload
(defun huangq-kill-ring-save (&optional n)
"If region is active, copy region. Otherwise, copy line."
(interactive "p")
(if (and mark-active transient-mark-mode)
(kill-ring-save (region-beginning) (region-end))
(if (> n 0)
(kill-ring-save (line-beginning-position) (line-end-position n))
(kill-ring-save (line-beginning-position n) (line-end-position)))))

;;;###autoload
(defun huangq-save-line-dwim (&optional arg)
"If region is active, copy region.
If ARG is nil, copy line from first non-white.
If ARG is numeric, copy ARG lines.
If ARG is non-numeric, copy line from beginning of the current line."
(interactive "P")
(if (and mark-active transient-mark-mode)
;; mark-active, save region
(kill-ring-save (region-beginning) (region-end))
(if arg
(if (numberp arg)
;; numeric arg, save ARG lines
(huangq-kill-ring-save arg)
;; other ARG, save current line
(huangq-save-one-line))
;; no ARG, save current line from first non-white
(huangq-save-one-line t))))

Friday, November 02, 2007

flymake mode

How can I miss this wonderful feature until now?

Flymake is amazing. See the screenshot:


What you need is only a Makefile with an extra target "check-syntax":
check-syntax:
    gcc -o nul -Wall -Wextra -fsyntax-only $(CHK_SOURCES)

And of course type "M-x flymake-mode" when needed.

You can also customize the error and warning face in .emacs like:
(require 'flymake nil t)
(when (featurep 'flymake)
(set-face-background 'flymake-errline "LightPink")
(set-face-foreground 'flymake-errline "DarkRed")
(set-face-bold-p 'flymake-errline t)
(set-face-background 'flymake-warnline "LightBlue2")
(set-face-foreground 'flymake-warnline "DarkBlue")
(set-face-bold-p 'flymake-warnline t))

Search word at point in Emacs

查找光标上的单词

The default i-search command in Emacs is C-s, and then type the word you want to search. If your cursor is current on the beginning of the word, then you can type C-s C-w. This is case insensitive.

If you want to look for the exact word, then you can use the following code. Type C-* and search the word at the point. It works just like the Star * in VIM.

(defvar my-isearch-word "")

(defun my-isearch-word ()
(interactive)
(when (not mark-active)
(let (word-beg word-end)
(unless (looking-at "\\<")
(if (eq (char-syntax (char-after)) ?w)
(backward-word)
(and (forward-word) (backward-word)))
)
(setq word-beg (point))
(forward-word)
(setq word-end (point))
(setq my-isearch-word (filter-buffer-substring word-beg word-end nil t))
(backward-word)
)
(when (> (length my-isearch-word) 0)
(setq my-isearch-word (concat "\\<" my-isearch-word "\\>"))
(isearch-update-ring my-isearch-word t)
(add-hook 'isearch-mode-end-hook 'my-isearch-word-end-hook)
(isearch-mode t t)
(isearch-repeat 'forward)
(message "%s" isearch-string))))

(global-set-key (kbd "C-*") 'my-isearch-word)