Emacs:如何编写一个对区域起作用的defun,但如果没有区域则作用于point?

Ado*_*obe 5 emacs elisp

我为一个区域写了一个简单的defun,即使没有区域我想要应用它 - 也就是说它根本没有选择.我以为我可以做以下事情:

(defun region-study (strt end)
  (interactive "r")
  (if (= strt end)
    (progn ....) ;; then
    (progn ....))) ;; else
Run Code Online (Sandbox Code Playgroud)

但它不起作用.事实证明,当您(interactive "r")在没有区域的情况下进行呼叫时,它不仅仅将边界设置为相等.试试这个:

(defun region-study (strt end)
  (interactive "r")
  (message "strt=%d; end=%d" strt end))
Run Code Online (Sandbox Code Playgroud)

所以我的问题是:"如何编写一个对区域起作用的defun,但如果没有区域则会对点进行操作?"

编辑:

所以我想把选择放在括号中或只是插入括号和(backward-char 1).这是一个解决方案:

(defun put-in-lft-rit (lft rit)
  (interactive "k")
  (if (use-region-p) ;; act on region
    (progn 
      (setq pP (point)) 

      (setq strt (region-beginning))
      (setq end (region-end))

      (setq meat (buffer-substring-no-properties strt end))
      (setq news (concat lft meat rit))
      (delete-region strt end)
      (goto-char strt)
      (insert news)

      (if (= pP strt)
      (goto-char strt) ; then
      (goto-char (+ end 1))))  ; else
    (progn ;; act on point
      (insert lft rit)
      (backward-char 1))))

(defun bk-put-in-braces ()
  (interactive)
  (put-in-lft-rit "(" ")"))

(defun bk-put-in-curly-braces ()
  (interactive)
  (put-in-lft-rit "{" "}"))

(defun bk-put-in-quotes ()
  (interactive)
  (put-in-lft-rit "'" "'"))

(defun bk-put-in-double-quotes ()
  (interactive)
  (put-in-lft-rit "\"" "\""))

(defun bk-put-in-square-brackes ()
  (interactive)
  (put-in-lft-rit "[" "]"))
Run Code Online (Sandbox Code Playgroud)

然后你绑定.emacs:

(global-set-key (kbd "C-<f9>") 'bk-put-in-square-brackes)
(global-set-key (kbd "<f9>") 'bk-put-in-curly-braces)
(global-set-key (kbd "S-<f7>") 'bk-put-in-quotes)
(global-set-key (kbd "S-<f8>") 'bk-put-in-double-quotes)
(global-set-key (kbd "S-<f9>") 'bk-put-in-braces)
Run Code Online (Sandbox Code Playgroud)

而已!应该在所有模式下工作.

编辑2:

@phils谢谢.你是完全正确的.但有一点 - 我的代码还有一个额外的功能,即将点留在区域的开头或结尾 - 取决于它在选择中的位置.这是您添加此功能的代码:

(defun put-in-lft-rit (lft rit)
  (interactive "k")
  (if (use-region-p) ;; act on region
      (let ((strt (region-beginning))
            (end (region-end))
            (pP (point)))

        (save-excursion
          (goto-char end)
          (insert rit)
          (goto-char strt)
          (insert lft))

        (if (= pP strt)
          (goto-char strt) ; then
          (goto-char (+ end 1))))  ; else

    (progn ;; act on point
      (insert lft rit)
      (backward-char 1))))
Run Code Online (Sandbox Code Playgroud)

phi*_*ils 8

关于您的解决方案的几点说明......

  1. 避免不必要的全局范围setq是一种很好的做法.(let)而是使用它来定义变量的临时范围.

  2. 你做的工作比要求多得多.而不是复制区域,将该副本和分隔符连接成"新闻"变量,删除区域,然后插入"新闻",您需要做的就是在区域的开头和结尾插入分隔符字符.

    (一般情况下,如果你尝试elisp的写入操作时"认为像编辑",并专注于操作的缓冲区,而不是变量,你通常会风与更高效的代码.)

  3. save-excursion是非常有用的(以及其他几个save-with-形式).

 

(defun put-in-lft-rit (lft rit)
  (interactive "k")
  (if (use-region-p) ;; act on region
      (let ((strt (region-beginning))
            (end (region-end)))
        (save-excursion
          (goto-char end)
          (insert rit)
          (goto-char strt)
          (insert lft)))
    (progn ;; act on point
      (insert lft rit)
      (backward-char 1))))
Run Code Online (Sandbox Code Playgroud)


Woo*_*ble 6

use-region-pt如果你的函数应该作用于该区域而不是某个点,则应返回.