Skip to content

Commit

Permalink
Major overhaul of the way pairs are inserted. This is more heavily ba…
Browse files Browse the repository at this point in the history
…sed on the autopair-insert from emacs wiki. It's been modified to automatically add bindings.
  • Loading branch information
ramblex committed Oct 10, 2009
1 parent 563c887 commit ea4d7bf
Showing 1 changed file with 94 additions and 87 deletions.
181 changes: 94 additions & 87 deletions textmate.el
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
;; textmate.el --- TextMate behaviour on Emacs
;; Copyright (C) 2008 Orestis Markou
;; (Modified by Alex Duller 2009)
;; textmate.el --- TextMate behaviour in Emacs
;; Copyright 2009 Alex Duller

;; This program is free software; you can redistribute it and/or
;; modify it under the terms of the GNU General Public License
Expand Down Expand Up @@ -44,8 +43,23 @@
"Textmate minor mode"
:group 'editor)

(setq skeleton-pair-alist
'((?\( _ ?\))
(?[ _ ?])
(?{ _ ?})
(?\" _ ?\")
(?\' _ ?\')))

(defcustom tm/non-insert-alist '((emacs-lisp-mode . '(?\'))
(lisp-mode . '(?\'))
(lisp-interaction-mode . '(?\')))
"The format of this list is '(major-mode . '(chars)) where the given list of
chars are not auto-inserted in major-mode"
:type '(alist :key-type symbol :value-type alist)
:group 'textmate)

(defcustom tm/use-goto-line nil
"If set to t, use \M-l to go to line"
"If set to t, use M-l to go to line"
:type 'boolean
:group 'textmate)

Expand All @@ -55,7 +69,7 @@
:group 'textmate)

(defcustom tm/use-open-next-line t
"If set to t, use \M-\r to start a new line"
"If set to t, use M-\r to start a new line"
:type 'boolean
:group 'textmate)

Expand All @@ -74,6 +88,8 @@

(defun tm/initialize ()
"Do the necessary initialization"
(setq skeleton-pair t)
(tm/set-keymap)
(add-hook 'after-change-major-mode-hook
'tm/minor-mode-auto-on))

Expand All @@ -90,6 +106,19 @@
(interactive)
(tm/minor-mode nil))

(defvar tm/minor-mode-map (make-sparse-keymap)
"Keymap for tm/minor-mode bindings")

(defun tm/set-keymap ()
"Automatically determine the appropriate key bindings"
(define-key tm/minor-mode-map [backspace] 'tm/pair-backspace)
(dolist (arg skeleton-pair-alist)
(define-key tm/minor-mode-map (string (car arg)) 'tm/pair-insert)
(define-key tm/minor-mode-map (string (car (last arg))) 'tm/pair-insert))
(tm/goto-line)
(tm/open-next-line-binding)
(add-to-list 'minor-mode-map-alist (cons 'tm/minor-mode tm/minor-mode-map)))

(define-minor-mode tm/minor-mode
"Toggle Textmate mode.
With no argument, this command toggles the mode.
Expand All @@ -100,31 +129,17 @@
;; The indicator for the mode line.
:lighter " TM"
;; The minor mode bindings.
:keymap '(([backspace] . tm/backspace)
("\"" . tm/move-over-dbl-quote)
("\'" . tm/move-over-quote)
(")" . tm/move-over-bracket)
("]" . tm/move-over-square)
("}" . tm/move-over-curly)
("[" . tm/insert-brace)
("(" . tm/insert-brace)
("{" . tm/insert-brace))
:group 'textmate
(progn
(setq skeleton-pair t)
;; Optional bindings
(tm/goto-line)
(tm/open-next-line-binding)))
:group 'textmate)

(defun tm/goto-line ()
"Enable users to decide whether or not to use \M-l as goto-line"
"Enable users to decide whether or not to use M-l as goto-line"
(let ((tm/goto-line-map (make-sparse-keymap)))
(define-key tm/goto-line-map "\M-l" 'goto-line)
(add-to-list 'minor-mode-map-alist
(cons 'tm/use-goto-line tm/goto-line-map))))
(define-key tm/goto-line-map "\M-l" 'goto-line)
(add-to-list 'minor-mode-map-alist
(cons 'tm/use-goto-line tm/goto-line-map))))

(defun tm/open-next-line-binding ()
"Enable users to decide whether or not to use \M-\r to start a new line"
"Enable users to decide whether or not to use M-\r to start a new line"
(let ((tm/open-next-line-map (make-sparse-keymap)))
(define-key tm/open-next-line-map "\M-\r" 'tm/open-next-line)
(add-to-list 'minor-mode-map-alist
Expand All @@ -136,17 +151,58 @@
(move-end-of-line nil)
(newline-and-indent))

;; The pairs that are supported by this mode
(setq textmate-pairs '(( ?\( . ?\) )
( ?\' . ?\' )
( ?\" . ?\" )
( ?[ . ?] )
( ?{ . ?} )))

(defun tm/is-empty-pair ()
"Check if a pair are next to each other. This is used to allow easy deletion"
(interactive)
(eq (cdr (assoc (char-before) textmate-pairs)) (char-after)))
;; The following set of functions are taken from
;; http://www.emacswiki.org/emacs/AutoPairs#toc2
(defun tm/pair-insert (arg)
(interactive "P")
(let ((ignore-list (car (last (assoc major-mode tm/non-insert-alist)))))
(cond
((member last-command-char ignore-list)
(insert-char last-command-char 1))
((assq last-command-char skeleton-pair-alist)
(tm/pair-open arg))
(t
(tm/pair-close arg)))))

(defun tm/pair-open (arg)
(interactive "P")
(let ((pair (assq last-command-char
skeleton-pair-alist)))
(cond
((and (not mark-active)
(eq (car pair) (car (last pair)))
(eq (car pair) (char-after)))
(tm/pair-close arg))
(t
(skeleton-pair-insert-maybe arg)))))

(defun tm/pair-close (arg)
(interactive "P")
(cond
(mark-active
(let (pair open)
(dolist (pair skeleton-pair-alist)
(when (eq last-command-char (car (last pair)))
(setq open (car pair))))
(setq last-command-char open)
(skeleton-pair-insert-maybe arg)))
((looking-at
(concat "[ \t\n]*"
(regexp-quote (string last-command-char))))
(replace-match (string last-command-char))
(indent-according-to-mode))
(t
(self-insert-command (prefix-numeric-value arg))
(indent-according-to-mode))))

(defun tm/pair-backspace (arg)
(interactive "p")
(if (eq (char-after)
(car (last (assq (char-before) skeleton-pair-alist))))
(and (char-after) (delete-char 1)))
(if (eq tm/backspace-delete-column t)
(tm/backward-delete-whitespace-to-column)
(delete-backward-char 1)))

;; Thanks to Trey Jackson
;; http://stackoverflow.com/questions/1450169/how-do-i-emulate-vims-softtabstop-in-emacs/1450454#1450454
Expand All @@ -162,55 +218,6 @@ or just one char if that's not possible"
(save-match-data
(if (string-match "\\w*\\(\\s-+\\)$" (buffer-substring-no-properties (- p movement) p))
(backward-delete-char-untabify (- (match-end 1) (match-beginning 1)))
(call-interactively 'backward-delete-char-untabify))))))

(defun tm/backspace ()
(interactive)
(if (eq (char-after) nil)
nil ;; if char-after is nil, just backspace
(if (tm/is-empty-pair)
(delete-char 1)))
(if (eq tm/backspace-delete-column t)
(tm/backward-delete-whitespace-to-column)
(delete-backward-char 1)))

;; These are used when user has manually inserted the trailing char of a pair
(setq pushovers
'((?\" . (lambda () (forward-char 1) ))
(?\' . (lambda () (forward-char 1) ))
(?\) . (lambda () (up-list 1) ))
(?\] . (lambda () (up-list 1) ))
(?\} . (lambda () (up-list 1) ))))

(setq defaults
'((?\" . (lambda () (skeleton-pair-insert-maybe nil)))
(?\' . (lambda () (skeleton-pair-insert-maybe nil)))
(?\) . (lambda () (insert-char ?\) 1) ))
(?\] . (lambda () (insert-char ?\] 1) ))
(?\} . (lambda () (insert-char ?\} 1) ))))

(defun tm/move-over (char)
"If the user has manually inserted the trailing char, don't insert another
one"
(interactive)
(if (eq (char-after) char)
(funcall (cdr (assoc char pushovers)))
(funcall (cdr (assoc char defaults))))
(indent-according-to-mode))

(defun tm/insert-brace ()
(interactive)
(skeleton-pair-insert-maybe nil)
(indent-according-to-mode))

(defun tm/move-over-bracket () (interactive)(tm/move-over ?\)))
(defun tm/move-over-curly () (interactive)(tm/move-over ?\}))
(defun tm/move-over-square () (interactive)(tm/move-over ?\]))
(defun tm/move-over-quote ()
(interactive)
(if (eq (member major-mode tm/exempt-quote-modes) nil)
(tm/move-over ?\')
(insert-char ?\' 1)))
(defun tm/move-over-dbl-quote () (interactive)(tm/move-over ?\"))
(call-interactively 'backward-delete-char-untabify))))))

(provide 'textmate)
(provide 'textmate)

0 comments on commit ea4d7bf

Please sign in to comment.