![[Home]](https://www.emacswiki.org/images/logo218x38.png)
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. [new] 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>. [new] 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: