*** add-log.el.~1.205.~ Sun Jan 27 20:52:46 2008 --- add-log.el Mon Feb 18 18:45:28 2008 *************** *** 300,309 **** ;; name. (progn (re-search-forward change-log-file-names-re nil t) ! (match-string 2)) (if (looking-at change-log-file-names-re) ;; We found a file name. ! (match-string 2) ;; Look backwards for either a file name or the log entry start. (if (re-search-backward (concat "\\(" change-log-start-entry-re --- 300,309 ---- ;; name. (progn (re-search-forward change-log-file-names-re nil t) ! (match-string-no-properties 2)) (if (looking-at change-log-file-names-re) ;; We found a file name. ! (match-string-no-properties 2) ;; Look backwards for either a file name or the log entry start. (if (re-search-backward (concat "\\(" change-log-start-entry-re *************** *** 314,324 **** ;; file name. (progn (re-search-forward change-log-file-names-re nil t) ! (match-string 2)) ! (match-string 4)) ;; We must be before any file name, look forward. (re-search-forward change-log-file-names-re nil t) ! (match-string 2)))))) (defun change-log-find-file () "Visit the file for the change under point." --- 314,324 ---- ;; file name. (progn (re-search-forward change-log-file-names-re nil t) ! (match-string-no-properties 2)) ! (match-string-no-properties 4)) ;; We must be before any file name, look forward. (re-search-forward change-log-file-names-re nil t) ! (match-string-no-properties 2)))))) (defun change-log-find-file () "Visit the file for the change under point." *************** *** 328,338 **** --- 328,487 ---- (find-file file) (message "No such file or directory: %s" file)))) + (defun change-log-search-tag-name-1 (&optional from) + "Search for a tag name within subexpression 1 of last match. + Optional argument FROM specifies a buffer position where the tag + name should be located. Return value is a cons whose car is the + string representing the tag and whose cdr is the position where + the tag was found." + (save-restriction + (narrow-to-region (match-beginning 1) (match-end 1)) + (when from (goto-char from)) + ;; The regexp below skips any symbol near `point' (FROM) followed by + ;; whitespace and another symbol. This should skip, for example, + ;; "struct" in a specification like "(struct buffer)" and move to + ;; "buffer". A leading paren is ignored. + (when (looking-at + "[(]?\\(?:\\(?:\\sw\\|\\s_\\)+\\(?:[ \t]+\\(\\sw\\|\\s_\\)+\\)\\)") + (goto-char (match-beginning 1))) + (cons (find-tag-default) (point)))) + + (defconst change-log-tag-re + "(\\(\\(?:\\sw\\|\\s_\\)+\\(?:[, \t]+\\(?:\\sw\\|\\s_\\)+\\)*\\))" + "Regexp matching a tag name in change log entries.") + + (defun change-log-search-tag-name (&optional at) + "Search for a tag name near `point'. + Optional argument AT non-nil means search near buffer position + AT. Return value is a cons whose car is the string representing + the tag and whose cdr is the position where the tag was found." + (save-excursion + (goto-char (setq at (or at (point)))) + (save-restriction + (widen) + (or (condition-case nil + ;; Within parenthesized list? + (save-excursion + (backward-up-list) + (when (looking-at change-log-tag-re) + (change-log-search-tag-name-1 at))) + (error nil)) + (condition-case nil + ;; Before parenthesized list? + (save-excursion + (when (and (skip-chars-forward " \t") + (looking-at change-log-tag-re)) + (change-log-search-tag-name-1))) + (error nil)) + (condition-case nil + ;; Near filename? + (save-excursion + (when (and (progn + (beginning-of-line) + (looking-at change-log-file-names-re)) + (goto-char (match-end 0)) + (skip-syntax-forward " ") + (looking-at change-log-tag-re)) + (change-log-search-tag-name-1))) + (error nil)) + (condition-case nil + ;; Before filename? + (save-excursion + (when (and (progn + (skip-syntax-backward " ") + (beginning-of-line) + (looking-at change-log-file-names-re)) + (goto-char (match-end 0)) + (skip-syntax-forward " ") + (looking-at change-log-tag-re)) + (change-log-search-tag-name-1))) + (error nil)) + (condition-case nil + ;; Near start entry? + (save-excursion + (when (and (progn + (beginning-of-line) + (looking-at change-log-start-entry-re)) + (forward-line) ; Won't work for multiple + ; names, etc. + (skip-syntax-forward " ") + (progn + (beginning-of-line) + (looking-at change-log-file-names-re)) + (goto-char (match-end 0)) + (re-search-forward change-log-tag-re)) + (change-log-search-tag-name-1))) + (error nil)) + (condition-case nil + ;; After parenthesized list?. + (when (re-search-backward change-log-tag-re) + (save-restriction + (narrow-to-region (match-beginning 1) (match-end 1)) + (goto-char (point-max)) + (cons (find-tag-default) (point-max)))) + (error nil)))))) + + (defvar change-log-tag-buffer nil + "Buffer visiting source file for last call of `change-log-find-tag'.") + + (defvar change-log-tag-list nil + "List of matches found by last call of `change-log-find-tag'. + When matches exist a cons cell whose caar denotes the function to + call for going to a matching location and whose cdr is the list + of locations.") + + (defvar change-log-tag-arg nil + "Index used for rotating `change-log-tag-list'.") + + (defun change-log-find-tag () + "Display source code matching change log entry near `point'. + Invoking this repeatedly will rotate through matches found." + (interactive) + (save-excursion + (if (equal last-command 'change-log-find-tag) + ;; Rotate hits. + (if (or (not change-log-tag-buffer) (null change-log-tag-list)) + (message "No matches to display") + (setq change-log-tag-arg (1+ change-log-tag-arg)) + (when (= change-log-tag-arg (length (cdr change-log-tag-list))) + (when (> (length (cdr change-log-tag-list)) 1) + (message "Wrapping to first match")) ; Inform user. + (setq change-log-tag-arg 0)) + (let ((fun (caar change-log-tag-list)) + (hit (nth change-log-tag-arg (cdr change-log-tag-list)))) + (with-selected-window (display-buffer change-log-tag-buffer) + (push-mark nil t) + (funcall fun hit)))) + ;; Get new hits. + (let* ((tag-at (change-log-search-tag-name)) + (tag (car tag-at)) + (file (when tag-at + (change-log-search-file-name (cdr tag-at))))) + (if (not tag) + (error "No suitable tag name near `point'") + (set (make-local-variable 'change-log-tag-buffer) + (find-file-noselect file)) + (require 'local-tags) + (set (make-local-variable 'change-log-tag-list) + (with-current-buffer change-log-tag-buffer + (local-tags-find tag))) + (if (null change-log-tag-list) + (message "No matches for `%s' in %s" tag file) + (when (> (length (cdr change-log-tag-list)) 1) + (message "Repeat this command to display more matches")) + (set (make-local-variable 'change-log-tag-arg) 0) + (let ((fun (caar change-log-tag-list)) + (hit (cadr change-log-tag-list))) + (with-selected-window (display-buffer change-log-tag-buffer) + (push-mark nil t) + (funcall fun hit))))))))) + (defvar change-log-mode-map (let ((map (make-sparse-keymap))) (define-key map [?\C-c ?\C-p] 'add-log-edit-prev-comment) (define-key map [?\C-c ?\C-n] 'add-log-edit-next-comment) (define-key map [?\C-c ?\C-f] 'change-log-find-file) + (define-key map [?\C-c ?\C-t] 'change-log-find-tag) map) "Keymap for Change Log major mode.") *************** *** 938,944 **** having-next-defun previous-defun-end next-defun-beginning) ! (save-excursion (setq having-previous-defun (c-beginning-of-defun)) --- 1087,1093 ---- having-next-defun previous-defun-end next-defun-beginning) ! (save-excursion (setq having-previous-defun (c-beginning-of-defun))