Emacs: как написать defun, который действует на регион, но действует на месте, если нет региона? - PullRequest
5 голосов
/ 12 сентября 2011

Я пишу простой 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)

Вот и все!Должно работать во всех режимах.

Edit2 :

@ 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))))

Ответы [ 3 ]

8 голосов
/ 12 сентября 2011

Несколько замечаний о вашем решении ...

  1. Рекомендуется избегать ненужных глобальных областей действия setq s. Вместо этого используйте (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))))
6 голосов
/ 12 сентября 2011

use-region-p должен возвращать t, если ваша функция должна воздействовать на регион, а не на точку.

2 голосов
/ 12 сентября 2011

Вы можете использовать функцию region-or-word-at-point, определенную в thingatpt + .el

...