comparison .elisp/textmate.el @ 22:8715ccb6f61b

Start using textmate.el.
author Augie Fackler <durin42@gmail.com>
date Fri, 12 Dec 2008 09:38:16 -0600
parents
children d6fd2964258c
comparison
equal deleted inserted replaced
21:b465892f75e4 22:8715ccb6f61b
1 ;; textmate.el --- TextMate minor mode for Emacs
2
3 ;; Copyright (C) 2008 Chris Wanstrath <chris@ozmm.org>
4
5 ;; Licensed under the same terms as Emacs.
6
7 ;; Version: 0.1.0
8 ;; Keywords: textmate osx mac
9 ;; Created: 22 Nov 2008
10 ;; Author: Chris Wanstrath <chris@ozmm.org>
11
12 ;; This file is NOT part of GNU Emacs.
13
14 ;; Licensed under the same terms as Emacs.
15
16 ;;; Commentary:
17
18 ;; This minor mode exists to mimick TextMate's awesome
19 ;; features.
20
21 ;; ⌘T - Go to File
22 ;; ⇧⌘T - Go to Symbol
23 ;; ⌘L - Go to Line
24 ;; ⌘/ - Comment Line (or Selection/Region)
25 ;; ⌘] - Shift Right (currently indents region)
26 ;; ⌘[ - Shift Left (not yet implemented)
27 ;; ⌥⌘] - Align Assignments
28 ;; ⌥⌘[ - Indent Line
29 ;; ⌘RET - Insert Newline at Line's End
30 ;; ⌥⌘T - Reset File Cache (for Go to File)
31
32 ;; A "project" in textmate-mode is determined by the presence of
33 ;; a .git directory. If no .git directory is found in your current
34 ;; directory, textmate-mode will traverse upwards until one (or none)
35 ;; is found. The directory housing the .git directory is presumed
36 ;; to be the project's root.
37
38 ;; In other words, calling Go to File from
39 ;; ~/Projects/fieldrunners/app/views/towers/show.html.erb will use
40 ;; ~/Projects/fieldrunners/ as the root if ~/Projects/fieldrunners/.git
41 ;; exists.
42
43 ;;; Installation
44
45 ;; $ cd ~/.emacs.d/vendor
46 ;; $ git clone git://github.com/defunkt/textmate.el.git
47 ;;
48 ;; In your emacs config:
49 ;;
50 ;; (add-to-list 'load-path "~/.emacs.d/vendor/textmate.el")
51 ;; (require 'textmate)
52 ;; (textmate-mode)
53
54 ;;; Depends on imenu
55 (require 'imenu)
56
57 ;;; Minor mode
58
59 (defvar textmate-use-file-cache t
60 "* Should `textmate-goto-file' keep a local cache of files?")
61
62 (defvar textmate-completing-library 'ido
63 "The library `textmade-goto-symbol' and `textmate-goto-file' should use for completing filenames and symbols (`ido' by default)")
64
65 (defvar *textmate-completing-function-alist* '((ido ido-completing-read)
66 (icicles icicle-completing-read)
67 (none completing-read))
68 "The function to call to read file names and symbols from the user")
69
70 (defvar *textmate-completing-minor-mode-alist*
71 `((ido ,(lambda (a) (progn (ido-mode a) (setq ido-enable-flex-matching t))))
72 (icicles ,(lambda (a) (icy-mode a)))
73 (none ,(lambda (a) ())))
74 "The list of functions to enable and disable completing minor modes")
75
76 (defvar *textmate-mode-map* (make-sparse-keymap))
77 (defvar *textmate-project-root* nil)
78 (defvar *textmate-project-files* '())
79 (defvar *textmate-gf-exclude*
80 "/\\.|vendor|fixtures|tmp|log|build|\\.xcodeproj|\\.nib|\\.framework|\\.app|\\.pbproj|\\.pbxproj|\\.xcode|\\.xcodeproj|\\.bundle")
81
82 (defvar *textmate-keybindings-list* `((textmate-next-line
83 [A-return] [M-return])
84 (textmate-clear-cache
85 ,(kbd "A-M-t") [(control c)(control t)])
86 (align
87 ,(kbd "A-M-]") [(control c)(control a)])
88 (indent-according-to-mode
89 ,(kbd "A-M-[") nil)
90 (indent-region
91 ,(kbd "A-]") [(control tab)])
92 (comment-or-uncomment-region-or-line
93 ,(kbd "A-/") [(control c)(control k)])
94 (textmate-goto-file
95 ,(kbd "A-t") [(meta t)])
96 (textmate-goto-symbol
97 ,(kbd "A-T") [(meta T)])))
98
99 (defvar *textmate-project-root-p*
100 #'(lambda (coll) (or (member ".git" coll)
101 (member ".hg" coll)
102 ))
103 "*Lambda that, given a collection of directory entries, returns
104 non-nil if it represents the project root.")
105
106 ;;; Bindings
107
108 (defun textmate-ido-fix ()
109 "Add up/down keybindings for ido."
110 (define-key ido-completion-map [up] 'ido-prev-match)
111 (define-key ido-completion-map [down] 'ido-next-match))
112
113 (defun textmate-bind-keys ()
114 (add-hook 'ido-setup-hook 'textmate-ido-fix)
115
116 ; weakness until i figure out how to do this right
117 (when (boundp 'osx-key-mode-map)
118 (define-key osx-key-mode-map (kbd "A-t") 'textmate-goto-file)
119 (define-key osx-key-mode-map (kbd "A-T") 'textmate-goto-symbol))
120
121 (let ((member) (i 0) (access (if (boundp 'aquamacs-version) 'cadr 'caddr)))
122 (setq member (nth i *textmate-keybindings-list*))
123 (while member
124 (if (funcall access member)
125 (define-key *textmate-mode-map* (funcall access member) (car member)))
126 (setq member (nth i *textmate-keybindings-list*))
127 (setq i (+ i 1)))))
128
129 (defun textmate-completing-read (&rest args)
130 (let ((reading-fn (cadr (assoc textmate-completing-library *textmate-completing-function-alist*))))
131 (apply (symbol-function reading-fn) args)))
132
133 ;;; Commands
134
135 (defun textmate-next-line ()
136 (interactive)
137 (end-of-line)
138 (newline-and-indent))
139
140 ;; http://chopmo.blogspot.com/2008/09/quickly-jumping-to-symbols.html
141 (defun textmate-goto-symbol ()
142 "Will update the imenu index and then use ido to select a symbol to navigate to"
143 (interactive)
144 (imenu--make-index-alist)
145 (let ((name-and-pos '())
146 (symbol-names '()))
147 (flet ((addsymbols (symbol-list)
148 (when (listp symbol-list)
149 (dolist (symbol symbol-list)
150 (let ((name nil) (position nil))
151 (cond
152 ((and (listp symbol) (imenu--subalist-p symbol))
153 (addsymbols symbol))
154
155 ((listp symbol)
156 (setq name (car symbol))
157 (setq position (cdr symbol)))
158
159 ((stringp symbol)
160 (setq name symbol)
161 (setq position (get-text-property 1 'org-imenu-marker symbol))))
162
163 (unless (or (null position) (null name))
164 (add-to-list 'symbol-names name)
165 (add-to-list 'name-and-pos (cons name position))))))))
166 (addsymbols imenu--index-alist))
167 (let* ((selected-symbol (textmate-completing-read "Symbol: " symbol-names))
168 (position (cdr (assoc selected-symbol name-and-pos))))
169 (goto-char position))))
170
171 (defun textmate-goto-file ()
172 (interactive)
173 (let ((root (textmate-project-root)))
174 (when (null root)
175 (error "Can't find any .git directory"))
176 (find-file
177 (concat
178 (expand-file-name root) "/"
179 (textmate-completing-read
180 "Find file: "
181 (textmate-cached-project-files root))))))
182
183 (defun textmate-clear-cache ()
184 (interactive)
185 (setq *textmate-project-root* nil)
186 (setq *textmate-project-files* nil)
187 (message "textmate-mode cache cleared."))
188
189 ;;; Utilities
190
191 (defun textmate-also-ignore (pattern)
192 "Also ignore PATTERN in project files."
193 (setq *textmate-gf-exclude*
194 (concat *textmate-gf-exclude* "|" pattern)))
195
196 (defun textmate-project-files (root)
197 (split-string
198 (shell-command-to-string
199 (concat
200 "find "
201 root
202 " -type f | grep -vE '"
203 *textmate-gf-exclude*
204 "' | sed 's:"
205 *textmate-project-root*
206 "/::'")) "\n" t))
207
208 (defun textmate-cached-project-files (&optional root)
209 (cond
210 ((null textmate-use-file-cache) (textmate-project-files root))
211 ((equal (textmate-project-root) (car *textmate-project-files*))
212 (cdr *textmate-project-files*))
213 (t (cdr (setq *textmate-project-files*
214 `(,root . ,(textmate-project-files root)))))))
215
216 (defun textmate-project-root ()
217 (when (or
218 (null *textmate-project-root*)
219 (not (string-match *textmate-project-root* default-directory)))
220 (let ((root (textmate-find-project-root)))
221 (if root
222 (setq *textmate-project-root* (expand-file-name (concat root "/")))
223 (setq *textmate-project-root* nil))))
224 *textmate-project-root*)
225
226 (defun textmate-find-project-root (&optional root)
227 (when (null root) (setq root default-directory))
228 (cond
229 ((funcall *textmate-project-root-p* (directory-files root))
230 (expand-file-name root))
231 ((equal (expand-file-name root) "/") nil)
232 (t (textmate-find-project-root (concat (file-name-as-directory root) "..")))))
233
234 ;;;###autoload
235 (define-minor-mode textmate-mode "TextMate Emulation Minor Mode"
236 :lighter " mate" :global t :keymap *textmate-mode-map*
237 (textmate-bind-keys)
238 ; activate preferred completion library
239 (dolist (mode *textmate-completing-minor-mode-alist*)
240 (if (eq (car mode) textmate-completing-library)
241 (funcall (cadr mode) t)
242 (when (fboundp
243 (cadr (assoc (car mode) *textmate-completing-function-alist*)))
244 (funcall (cadr mode) -1)))))
245
246 (provide 'textmate)
247 ;;; textmate.el ends here