【问题标题】:Emacs: how to write a defun which acts on region, but acts on point if there's no region?Emacs:如何编写一个作用于区域的defun,但如果没有区域则作用于点?
【发布时间】:2011-09-12 11:24:35
【问题描述】:

我为一个区域编写了一个简单的 defun,即使没有区域,我也想应用它——即完全没有选择地调用它。我认为我可以执行以下操作:

(defun region-study (strt end)
  (interactive "r")
  (if (= strt end)
    (progn ....) ;; then
    (progn ....))) ;; else

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

(defun region-study (strt end)
  (interactive "r")
  (message "strt=%d; end=%d" strt end))

所以我的问题是:“如何编写一个作用于区域的 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 "[" "]"))

然后你在 .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)

就是这样!应该在所有模式下工作。

编辑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))))

【问题讨论】:

  • 有一个自动配对 - 但它在文本模式下不起作用。

标签: emacs elisp


【解决方案1】:

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

  1. 避免不必要的全局范围setqs 是一种很好的做法。请改用(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))))

【讨论】:

    【解决方案2】:

    use-region-p 应该返回 t,如果您的函数应该作用于区域而不是某个点。

    【讨论】:

      【解决方案3】:

      你可能喜欢使用thingatpt+.el中定义的函数region-or-word-at-point

      【讨论】:

        猜你喜欢
        • 2017-11-29
        • 1970-01-01
        • 1970-01-01
        • 2022-10-13
        • 1970-01-01
        • 2010-10-22
        • 1970-01-01
        • 2021-06-21
        • 2023-03-05
        相关资源
        最近更新 更多