# HG changeset patch # User Augie Fackler # Date 1253060902 14400 # Node ID e30655eb70506d577e59f6cb37f45c24be922093 # Parent 7fa84e297c847aacb09b7d3319610574f01c7a01 textmate.el: synced with upstream Includes discovering that ido-imenu was a better textmate-goto-symbol and support for excluding files from grepping that are otherwise tracked in VCS. Useful for symlinks to large trees, and other such things. diff --git a/.elisp/settings/10.require.el b/.elisp/settings/10.require.el --- a/.elisp/settings/10.require.el +++ b/.elisp/settings/10.require.el @@ -13,7 +13,6 @@ (require 'textmate) (textmate-mode) -(textmate-also-ignore "eggs|cover|daisy|.*.pyc") (require 'yaml-mode) (add-to-list 'auto-mode-alist '("\\.yml$" . yaml-mode)) diff --git a/.elisp/settings/50.localfuncs.el b/.elisp/settings/50.localfuncs.el --- a/.elisp/settings/50.localfuncs.el +++ b/.elisp/settings/50.localfuncs.el @@ -7,50 +7,6 @@ nil (lambda (mode) "*pyflakes*"))) - -(defun ido-imenu () - "Update the imenu index and then use ido to select a symbol to navigate to. -Symbols matching the text at point are put first in the completion list." - (interactive) - (imenu--make-index-alist) - (let ((name-and-pos '()) - (symbol-names '())) - (flet ((addsymbols (symbol-list) - (when (listp symbol-list) - (dolist (symbol symbol-list) - (let ((name nil) (position nil)) - (cond - ((and (listp symbol) (imenu--subalist-p symbol)) - (addsymbols symbol)) - - ((listp symbol) - (setq name (car symbol)) - (setq position (cdr symbol))) - - ((stringp symbol) - (setq name symbol) - (setq position (get-text-property 1 'org-imenu-marker symbol)))) - - (unless (or (null position) (null name)) - (add-to-list 'symbol-names name) - (add-to-list 'name-and-pos (cons name position)))))))) - (addsymbols imenu--index-alist)) - ;; If there are matching symbols at point, put them at the beginning of `symbol-names'. - (let ((symbol-at-point (thing-at-point 'symbol))) - (when symbol-at-point - (let* ((regexp (concat (regexp-quote symbol-at-point) "$")) - (matching-symbols (delq nil (mapcar (lambda (symbol) - (if (string-match regexp symbol) symbol)) - symbol-names)))) - (when matching-symbols - (sort matching-symbols (lambda (a b) (> (length a) (length b)))) - (mapc (lambda (symbol) (setq symbol-names (cons symbol (delete symbol symbol-names)))) - matching-symbols))))) - (let* ((selected-symbol (ido-completing-read "Symbol? " symbol-names)) - (position (cdr (assoc selected-symbol name-and-pos)))) - (goto-char position)))) - - (defun fullscreen () (interactive) (set-frame-parameter nil 'fullscreen diff --git a/.elisp/settings/90.keybindings.el b/.elisp/settings/90.keybindings.el --- a/.elisp/settings/90.keybindings.el +++ b/.elisp/settings/90.keybindings.el @@ -19,7 +19,7 @@ (global-set-key [(control backspace)] 'kill-word) ;; M-j for jump to function definition -(global-set-key [(meta j)] 'ido-imenu) +(global-set-key [(meta j)] 'textmate-goto-symbol) ;; commit emacs heresy? (global-set-key [(meta r)] 'execute-extended-command) diff --git a/.elisp/textmate.el b/.elisp/textmate.el --- a/.elisp/textmate.el +++ b/.elisp/textmate.el @@ -1,18 +1,16 @@ ;; textmate.el --- TextMate minor mode for Emacs -;; Copyright (C) 2008 Chris Wanstrath +;; Copyright (C) 2008 Chris Wanstrath and others ;; Licensed under the same terms as Emacs. ;; Version: 0.1.0 ;; Keywords: textmate osx mac ;; Created: 22 Nov 2008 -;; Author: Chris Wanstrath +;; Author: Chris Wanstrath and others ;; This file is NOT part of GNU Emacs. -;; Licensed under the same terms as Emacs. - ;;; Commentary: ;; This minor mode exists to mimick TextMate's awesome @@ -22,12 +20,14 @@ ;; ⇧⌘T - Go to Symbol ;; ⌘L - Go to Line ;; ⌘/ - Comment Line (or Selection/Region) -;; ⌘] - Shift Right (currently indents region) -;; ⌘[ - Shift Left (not yet implemented) +;; ⌘] - Shift Right +;; ⌘[ - Shift Left ;; ⌥⌘] - Align Assignments ;; ⌥⌘[ - Indent Line ;; ⌘RET - Insert Newline at Line's End -;; ⌥⌘T - Reset File Cache (for Go to File, cache unused if using git/hg root) +;; ⌥⌘T - Reset File Cache (for Go to File, cache unused if using git/hg root, +;; but resets cached root location, useful if roots +;; are nested) ;; A "project" in textmate-mode is determined by the presence of ;; a .git directory. If no .git directory is found in your current @@ -54,6 +54,10 @@ ;;; Depends on imenu (require 'imenu) +;;; Needed for flet +(eval-when-compile + (require 'cl)) + ;;; Minor mode (defvar textmate-use-file-cache t @@ -73,39 +77,65 @@ (none ,(lambda (a) ()))) "The list of functions to enable and disable completing minor modes") -(defvar *textmate-mode-map* (make-sparse-keymap)) +(defvar *textmate-mode-map* + (let ((map (make-sparse-keymap))) + (cond ((featurep 'aquamacs) + (define-key map [A-return] 'textmate-next-line) + (define-key map (kbd "A-M-t") 'textmate-clear-cache) + (define-key map (kbd "A-M-]") 'align) + (define-key map (kbd "A-M-[") 'indent-according-to-mode) + (define-key map (kbd "A-]") 'textmate-shift-right) + (define-key map (kbd "A-[") 'textmate-shift-left) + (define-key map (kbd "A-/") 'comment-or-uncomment-region-or-line) + (define-key map (kbd "A-t") 'textmate-goto-file) + (define-key map (kbd "A-T") 'textmate-goto-symbol)) + ((and (featurep 'mac-carbon) (eq window-system 'mac) mac-key-mode) + (define-key map [(alt meta return)] 'textmate-next-line) + (define-key map [(alt meta t)] 'textmate-clear-cache) + (define-key map [(alt meta \])] 'align) + (define-key map [(alt meta \[)] 'indent-according-to-mode) + (define-key map [(alt \])] 'textmate-shift-right) + (define-key map [(alt \[)] 'textmate-shift-left) + (define-key map [(meta /)] 'comment-or-uncomment-region-or-line) + (define-key map [(alt t)] 'textmate-goto-file) + (define-key map [(alt shift t)] 'textmate-goto-symbol)) + ((featurep 'ns) ;; Emacs.app + (define-key map [(super meta return)] 'textmate-next-line) + (define-key map [(super meta t)] 'textmate-clear-cache) + (define-key map [(super meta \])] 'align) + (define-key map [(super meta \[)] 'indent-according-to-mode) + (define-key map [(super \])] 'textmate-shift-right) + (define-key map [(super \[)] 'textmate-shift-left) + (define-key map [(super /)] 'comment-or-uncomment-region-or-line) + (define-key map [(super t)] 'textmate-goto-file) + (define-key map [(super shift t)] 'textmate-goto-symbol)) + (t ;; Any other version + (define-key map [(meta return)] 'textmate-next-line) + (define-key map [(control c)(control t)] 'textmate-clear-cache) + (define-key map [(control c)(control a)] 'align) + (define-key map [(control tab)] 'textmate-shift-right) + (define-key map [(control shift tab)] 'textmate-shift-left) + (define-key map [(control c)(control k)] 'comment-or-uncomment-region-or-line) + (define-key map [(meta t)] 'textmate-goto-file) + (define-key map [(meta shift t)] 'textmate-goto-symbol))) + map)) + + (defvar *textmate-project-root* nil) (defvar *textmate-project-files* '()) + (defvar *textmate-gf-exclude* - "/\\.|vendor|fixtures|tmp|log|build|\\.xcodeproj|\\.nib|\\.framework|\\.app|\\.pbproj|\\.pbxproj|\\.xcode|\\.xcodeproj|\\.bundle") - -(defvar *textmate-keybindings-list* `((textmate-next-line - [A-return] [M-return]) - (textmate-clear-cache - ,(kbd "A-M-t") [(control c)(control t)]) - (align - ,(kbd "A-M-]") [(control c)(control a)]) - (indent-according-to-mode - ,(kbd "A-M-[") nil) - (indent-region - ,(kbd "A-]") [(control tab)]) - (comment-or-uncomment-region-or-line - ,(kbd "A-/") [(control c)(control k)]) - (textmate-goto-file - ,(kbd "A-t") [(meta t)]) - (textmate-goto-symbol - ,(kbd "A-T") [(meta T)]) - (textmate-toggle-camel-case - ,(kbd "C-_") [(control _)]))) - -(defvar *textmate-project-root-p* - #'(lambda (coll) (or (member ".git" coll) - (member ".hg" coll) - )) - "*Lambda that, given a collection of directory entries, returns - non-nil if it represents the project root.") + "/\\.|vendor|fixtures|tmp|log|build|\\.xcodeproj|\\.nib|\\.framework|\\.app|\\.pbproj|\\.pbxproj|\\.xcode|\\.xcodeproj|\\.bundle|\\.pyc") + +(defvar *textmate-project-roots* + '(".git" ".hg" "Rakefile" "Makefile" "README" "build.xml")) + +(defvar *textmate-vcs-exclude* nil + "string to give to grep -V to exclude some VCS paths from being grepped." + ) (defvar *textmate-find-in-project-default* nil) + (defvar *textmate-find-in-project-type-default* nil) ;;; Bindings @@ -115,26 +145,34 @@ (define-key ido-completion-map [up] 'ido-prev-match) (define-key ido-completion-map [down] 'ido-next-match)) -(defun textmate-bind-keys () - (add-hook 'ido-setup-hook 'textmate-ido-fix) - - ; weakness until i figure out how to do this right - (when (boundp 'osx-key-mode-map) - (define-key osx-key-mode-map (kbd "A-t") 'textmate-goto-file) - (define-key osx-key-mode-map (kbd "A-T") 'textmate-goto-symbol)) - - (let ((member) (i 0) (access (if (boundp 'aquamacs-version) 'cadr 'caddr))) - (setq member (nth i *textmate-keybindings-list*)) - (while member - (if (funcall access member) - (define-key *textmate-mode-map* (funcall access member) (car member))) - (setq member (nth i *textmate-keybindings-list*)) - (setq i (+ i 1))))) - (defun textmate-completing-read (&rest args) (let ((reading-fn (cadr (assoc textmate-completing-library *textmate-completing-function-alist*)))) (apply (symbol-function reading-fn) args))) +;;; allow-line-as-region-for-function adds an "-or-line" version of +;;; the given comment function which (un)comments the current line is +;;; the mark is not active. This code comes from Aquamac's osxkeys.el +;;; and is licensed under the GPL + +(defmacro allow-line-as-region-for-function (orig-function) +`(defun ,(intern (concat (symbol-name orig-function) "-or-line")) + () + ,(format "Like `%s', but acts on the current line if mark is not active." orig-function) + (interactive) + (if mark-active + (call-interactively (function ,orig-function)) + (save-excursion + ;; define a region (temporarily) -- so any C-u prefixes etc. are preserved. + (beginning-of-line) + (set-mark (point)) + (end-of-line) + (call-interactively (function ,orig-function)))))) + +(defun textmate-define-comment-line () + "Add or-line (un)comment function if not already defined" + (unless (fboundp 'comment-or-uncomment-region-or-line) + (allow-line-as-region-for-function comment-or-uncomment-region))) + ;;; Commands (defun textmate-next-line () @@ -144,7 +182,8 @@ ;; http://chopmo.blogspot.com/2008/09/quickly-jumping-to-symbols.html (defun textmate-goto-symbol () - "Will update the imenu index and then use ido to select a symbol to navigate to" + "Update the imenu index and then use ido to select a symbol to navigate to. +Symbols matching the text at point are put first in the completion list." (interactive) (imenu--make-index-alist) (let ((name-and-pos '()) @@ -169,7 +208,18 @@ (add-to-list 'symbol-names name) (add-to-list 'name-and-pos (cons name position)))))))) (addsymbols imenu--index-alist)) - (let* ((selected-symbol (textmate-completing-read "Symbol: " symbol-names)) + ;; If there are matching symbols at point, put them at the beginning of `symbol-names'. + (let ((symbol-at-point (thing-at-point 'symbol))) + (when symbol-at-point + (let* ((regexp (concat (regexp-quote symbol-at-point) "$")) + (matching-symbols (delq nil (mapcar (lambda (symbol) + (if (string-match regexp symbol) symbol)) + symbol-names)))) + (when matching-symbols + (sort matching-symbols (lambda (a b) (> (length a) (length b)))) + (mapc (lambda (symbol) (setq symbol-names (cons symbol (delete symbol symbol-names)))) + matching-symbols))))) + (let* ((selected-symbol (ido-completing-read "Symbol? " symbol-names)) (position (cdr (assoc selected-symbol name-and-pos)))) (goto-char position)))) @@ -177,7 +227,11 @@ (interactive) (let ((root (textmate-project-root))) (when (null root) - (error "Can't find any .git directory")) + (error + (concat + "Can't find a sutiable project root (" + (string-join " " *textmate-project-roots* ) + ")"))) (find-file (concat (expand-file-name root) "/" @@ -219,6 +273,9 @@ " ; " (cond ((string= type "git") "git ls-files") ((string= type "hg") "hg manifest")) + (if *textmate-vcs-exclude* + (concat " | grep -v " (shell-quote-argument *textmate-vcs-exclude*)) + "") " | xargs grep -nR " (if pattern (concat " --include='" pattern "' ") "") " -- " @@ -271,11 +328,6 @@ ;;; Utilities -(defun textmate-also-ignore (pattern) - "Also ignore PATTERN in project files." - (setq *textmate-gf-exclude* - (concat *textmate-gf-exclude* "|" pattern))) - (defun textmate-project-root-type (root) (cond ((member ".git" (directory-files root)) "git") ((member ".hg" (directory-files root)) "hg") @@ -323,18 +375,46 @@ (setq *textmate-project-root* nil)))) *textmate-project-root*) +(defun root-match(root names) + (member (car names) (directory-files root))) + +(defun root-matches(root names) + (if (root-match root names) + (root-match root names) + (if (eq (length (cdr names)) 0) + 'nil + (root-matches root (cdr names)) + ))) + (defun textmate-find-project-root (&optional root) (when (null root) (setq root default-directory)) (cond - ((funcall *textmate-project-root-p* (directory-files root)) - (expand-file-name root)) + ((root-matches root *textmate-project-roots*) + (expand-file-name root)) ((equal (expand-file-name root) "/") nil) (t (textmate-find-project-root (concat (file-name-as-directory root) ".."))))) +(defun textmate-shift-right (&optional arg) + "Shift the line or region to the ARG places to the right. + +A place is considered `tab-width' character columns." + (interactive) + (let ((deactivate-mark nil) + (beg (or (and mark-active (region-beginning)) + (line-beginning-position))) + (end (or (and mark-active (region-end)) (line-end-position)))) + (indent-rigidly beg end (* (or arg 1) tab-width)))) + +(defun textmate-shift-left (&optional arg) + "Shift the line or region to the ARG places to the left." + (interactive) + (textmate-shift-right (* -1 (or arg 1)))) + ;;;###autoload (define-minor-mode textmate-mode "TextMate Emulation Minor Mode" :lighter " mate" :global t :keymap *textmate-mode-map* - (textmate-bind-keys) + (add-hook 'ido-setup-hook 'textmate-ido-fix) + (textmate-define-comment-line) ; activate preferred completion library (dolist (mode *textmate-completing-minor-mode-alist*) (if (eq (car mode) textmate-completing-library)