Última vez editado
Modificado:
< * AutoPairs to insert parentheses, braces, quotes, etc. in matching pairs.
a
> * AutoPairs to insert parentheses, braces, quotes, etc. in matching pairs, with pair deletion etc. to boot.
According to the Autotype manual.
‘skeleton-pair-insert-maybe’ instead of ‘self-insert-command’. The “maybe” comes from the fact that this at-first surprising behavior is initially turned off. To enable it, you must set ‘skeleton-pair’ to some non-‘nil’ value.Here follows an enhanced variant of skeleton-pair-insert-maybe, that overcomes some of its limitations.
skeleton-pair-insert-maybe and how this enhaced version overcomes it.)(setq skeleton-end-hook nil) ; do not insert newline after skeleton insertation
(defvar myskeleton-pairs
'((?\" . (?\" ?\" ?\" _ ?\"))
(?\( . (?\( ?\) ?\( _ ?\)))
(?\[ . (?\[ ?\] ?\[ _ ?\]))
(?\{ . (?\{ ?\} ?\{ _ ?\}))
(?\' . (?\' ?\' ?\' _ ?\'))
(?\` . (?\` ?\' ?\` _ ?\')))
"Table of skeletons pairs. Maybe local to buffer.") (defun myskeleton-pair-insert (arg)
"Inserts pairs."
(interactive "*P") (let* ((chr (event-key last-command-event))
(pair (assoc chr myskeleton-pairs)))
(if (null pair)
(message "Character %s is not in `myskeleton-pairs'.")
(cond ((and (listp arg) (not (null arg)))
;; Surraund current word with
(save-excursion
(when (not (looking-at "\\<"))
(backward-word 1))
(when (looking-at "\\sw")
(let ((pl 0)
(r (prefix-numeric-value arg)))
(while (> r 1)
(setq r (/ r 4))
(setq pl (1+ pl))) (insert (make-string pl (nth 0 (cdr pair))))
(forward-word 1)
(insert (make-string pl (nth 1 (cdr pair))))))))
(t (mapcar (lambda (not-used)
(skeleton-insert
(cons nil (cdddr pair))))
(make-list (prefix-numeric-value arg) 'not-used))))))) (define-key global-map (kbd "C-M-{") 'backward-paragraph)
(define-key global-map (kbd "C-M-}") 'forward-paragraph)
(define-key global-map (kbd "C-M-'") 'abbrev-prefix-mark) (define-key global-map (kbd "M-\"") 'myskeleton-pair-insert)
(define-key global-map (kbd "M-`") 'myskeleton-pair-insert)
(define-key global-map (kbd "M-'") 'myskeleton-pair-insert)
(define-key global-map (kbd "M-{") 'myskeleton-pair-insert)
(define-key global-map (kbd "M-(") 'myskeleton-pair-insert)
(define-key global-map (kbd "M-[") 'myskeleton-pair-insert) ;; pairing for C-mode
(defun my-skelpair-cmode ()
(make-local-variable 'myskeleton-pairs)
(setq myskeleton-pairs (copy-alist myskeleton-pairs))
(remassoc ?\{ myskeleton-pairs)
(add-to-list 'myskeleton-pairs '(?{ . (?{ ?} ?{ '(progn (indent-according-to-mode) nil) \n _ \n ?} '(progn (indent-according-to-mode) nil)))))(add-hook 'c-mode-hook 'my-skelpair-cmode)
myskeleton-pair-insert recognizes two types of prefix, one is sereveral universal arguments (C-u) and the other numeric prefix argument. In the first case it will surround the current word N times (N is how much you press C-u), or just insert pair N times (N is numeric prefix argument).
To delete empty pairs like ‘()’ with a single keypress, we can advice delete-backward-char with the following code (borrowed from textmate.el):
(defvar skeletons-alist
'((?\( . ?\))
(?\' . ?\')
(?\" . ?\")
(?[ . ?])
(?{ . ?})
(?$ . ?$))) (defadvice delete-backward-char (before delete-empty-pair activate)
(if (eq (cdr (assq (char-before) skeletons-alist)) (char-after))
(and (char-after) (delete-char 1))))If the cursor is between ‘(’ and ‘)’, pressing <backspace> now deletes both characters. The variable skeletons-alist is easily extended with more pairs, represented as single characters.
However, we can also remove pairs that are not empty:
(defadvice backward-kill-word (around delete-pair activate)
(if (eq (char-syntax (char-before)) ?\()
(progn
(backward-char 1)
(save-excursion
(forward-sexp 1)
(delete-char -1))
(forward-char 1)
(append-next-kill)
(kill-backward-chars 1))
ad-do-it))This modifies the behavior of backward-kill-word, normally bound to <C-backspace>. For example, if the cursor is at the ‘w’ in ‘((word))’, <C-backspace> gives ‘(word)’. It only works for pairs listed in the syntax table, however.
The code above only deletes single-character pairs. To remove skeletons that consist of more characters, we can use regular expressions:
(defvar regexp-pairs-alist
'(("\\[i\]" . "\\[/i\\]")
("\\[b\]" . "\\[/b\\]")
("\\[u\]" . "\\[/u\\]")
("\\[font[^]]*\]" . "\\[/font\\]")
("\\[url[^]]*\]" . "\\[/url\\]")
("\\[list\\]" . "[\n ]*\\[/list\\]")
("\\[\\*\\]" . "")
("\\[img\\]" . "\\[/img\\]")
("\\[indent\\]" . "\\[/indent\\]")
("\\[youtube\\]" . "\\[/youtube\\]"))) (defadvice delete-backward-char (around delete-empty-regexp activate)
(unless (catch 'loop
(let (regexps start end)
(dolist (regexps regexp-pairs-alist)
(and (looking-at (setq end (cdr regexps)))
(looking-back (setq start (car regexps)))
(progn (replace-match "")
(looking-at end)
(replace-match "")
(throw 'loop t))))))
ad-do-it))I use this code for BbCode tags in forum posts. With skeletons, I can wrap the point or region in ‘[i][/i]’ with a single keystroke, and delete empty pairs with another – <backspace>.
But there’s more! Remember when deleting nonempty pairs above, the pair had to be listed in the syntax table? Not with regular expressions:
(defadvice backward-kill-word (around delete-regexp activate)
(unless (catch 'loop
(let (regexps start end (level 1))
(dolist (regexps regexp-pairs-alist)
(when (looking-back (setq start (car regexps)))
(replace-match "")
(setq end (cdr regexps))
(save-excursion
(while (re-search-forward
(concat "\\(" start
"\\)\\|\\("
end "\\)") nil t)
(if (looking-back start)
(setq level (1+ level))
(when (= 0 (setq level (1- level)))
(replace-match "")
(throw 'loop t)))))
(throw 'loop t)))))
ad-do-it))Now, if the cursor is at the ‘t’ in ‘[i]text[/i]’, <C-backspace> gives ‘text’. The advice recognizes nested tags.
See also: