aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Rudalics2008-07-13 07:35:15 +0000
committerMartin Rudalics2008-07-13 07:35:15 +0000
commitf06b5ed2ce9329fb6112f2ccfd7e3271c5cbe70c (patch)
treea5306a883c58100899a49144a8ed387fe58b7179
parent241d447bd378cbe9cb7f7c0d73ff2e9f1e48a9eb (diff)
downloademacs-f06b5ed2ce9329fb6112f2ccfd7e3271c5cbe70c.tar.gz
emacs-f06b5ed2ce9329fb6112f2ccfd7e3271c5cbe70c.zip
(change-log-search-file-name): Use match-string-no-properties.
(change-log-search-tag-name-1, change-log-search-tag-name) (change-log-goto-source-1, change-log-goto-source): New functions. (change-log-tag-re, change-log-find-head, change-log-find-tail): New variables. (change-log-mode-map): Bind C-c C-c to change-log-goto-source.
-rw-r--r--etc/NEWS3
-rw-r--r--lisp/ChangeLog9
-rw-r--r--lisp/add-log.el196
3 files changed, 203 insertions, 5 deletions
diff --git a/etc/NEWS b/etc/NEWS
index 00d668b79d9..993975293e9 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -722,6 +722,9 @@ to update it to the new VC.
722*** In Change Log mode, the new command C-c C-f (change-log-find-file) 722*** In Change Log mode, the new command C-c C-f (change-log-find-file)
723finds the file associated with the current log entry. 723finds the file associated with the current log entry.
724 724
725*** In Change Log mode, the new command C-c C-c (change-log-goto-source)
726goes to the source code associated with a log entry.
727
725*** comint-mode uses `start-file-process' now (see Lisp Changes). 728*** comint-mode uses `start-file-process' now (see Lisp Changes).
726If `default-directory' is a remote file name, subprocesses are started 729If `default-directory' is a remote file name, subprocesses are started
727on the corresponding remote system. 730on the corresponding remote system.
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index cee88696b69..e7c29b98e7f 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,12 @@
12008-07-13 Martin Rudalics <rudalics@gmx.at>
2
3 * add-log.el (change-log-search-file-name): Use match-string-no-properties.
4 (change-log-search-tag-name-1, change-log-search-tag-name)
5 (change-log-goto-source-1, change-log-goto-source): New functions.
6 (change-log-tag-re, change-log-find-head, change-log-find-tail):
7 New variables.
8 (change-log-mode-map): Bind C-c C-c to change-log-goto-source.
9
12008-07-13 Jay Belanger <jay.p.belanger@gmail.com> 102008-07-13 Jay Belanger <jay.p.belanger@gmail.com>
2 11
3 * calc-help.el (calc-describe-key): Add angles to special key 12 * calc-help.el (calc-describe-key): Add angles to special key
diff --git a/lisp/add-log.el b/lisp/add-log.el
index fc8224293ca..19a537fc0da 100644
--- a/lisp/add-log.el
+++ b/lisp/add-log.el
@@ -298,10 +298,10 @@ Note: The search is conducted only within 10%, at the beginning of the file."
298 ;; name. 298 ;; name.
299 (progn 299 (progn
300 (re-search-forward change-log-file-names-re nil t) 300 (re-search-forward change-log-file-names-re nil t)
301 (match-string 2)) 301 (match-string-no-properties 2))
302 (if (looking-at change-log-file-names-re) 302 (if (looking-at change-log-file-names-re)
303 ;; We found a file name. 303 ;; We found a file name.
304 (match-string 2) 304 (match-string-no-properties 2)
305 ;; Look backwards for either a file name or the log entry start. 305 ;; Look backwards for either a file name or the log entry start.
306 (if (re-search-backward 306 (if (re-search-backward
307 (concat "\\(" change-log-start-entry-re 307 (concat "\\(" change-log-start-entry-re
@@ -312,11 +312,11 @@ Note: The search is conducted only within 10%, at the beginning of the file."
312 ;; file name. 312 ;; file name.
313 (progn 313 (progn
314 (re-search-forward change-log-file-names-re nil t) 314 (re-search-forward change-log-file-names-re nil t)
315 (match-string 2)) 315 (match-string-no-properties 2))
316 (match-string 4)) 316 (match-string-no-properties 4))
317 ;; We must be before any file name, look forward. 317 ;; We must be before any file name, look forward.
318 (re-search-forward change-log-file-names-re nil t) 318 (re-search-forward change-log-file-names-re nil t)
319 (match-string 2)))))) 319 (match-string-no-properties 2))))))
320 320
321(defun change-log-find-file () 321(defun change-log-find-file ()
322 "Visit the file for the change under point." 322 "Visit the file for the change under point."
@@ -326,11 +326,197 @@ Note: The search is conducted only within 10%, at the beginning of the file."
326 (find-file file) 326 (find-file file)
327 (message "No such file or directory: %s" file)))) 327 (message "No such file or directory: %s" file))))
328 328
329(defun change-log-search-tag-name-1 (&optional from)
330 "Search for a tag name within subexpression 1 of last match.
331Optional argument FROM specifies a buffer position where the tag
332name should be located. Return value is a cons whose car is the
333string representing the tag and whose cdr is the position where
334the tag was found."
335 (save-restriction
336 (narrow-to-region (match-beginning 1) (match-end 1))
337 (when from (goto-char from))
338 ;; The regexp below skips any symbol near `point' (FROM) followed by
339 ;; whitespace and another symbol. This should skip, for example,
340 ;; "struct" in a specification like "(struct buffer)" and move to
341 ;; "buffer". A leading paren is ignored.
342 (when (looking-at
343 "[(]?\\(?:\\(?:\\sw\\|\\s_\\)+\\(?:[ \t]+\\(\\sw\\|\\s_\\)+\\)\\)")
344 (goto-char (match-beginning 1)))
345 (cons (find-tag-default) (point))))
346
347(defconst change-log-tag-re
348 "(\\(\\(?:\\sw\\|\\s_\\)+\\(?:[, \t]+\\(?:\\sw\\|\\s_\\)+\\)*\\))"
349 "Regexp matching a tag name in change log entries.")
350
351(defun change-log-search-tag-name (&optional at)
352 "Search for a tag name near `point'.
353Optional argument AT non-nil means search near buffer position
354AT. Return value is a cons whose car is the string representing
355the tag and whose cdr is the position where the tag was found."
356 (save-excursion
357 (goto-char (setq at (or at (point))))
358 (save-restriction
359 (widen)
360 (or (condition-case nil
361 ;; Within parenthesized list?
362 (save-excursion
363 (backward-up-list)
364 (when (looking-at change-log-tag-re)
365 (change-log-search-tag-name-1 at)))
366 (error nil))
367 (condition-case nil
368 ;; Before parenthesized list?
369 (save-excursion
370 (when (and (skip-chars-forward " \t")
371 (looking-at change-log-tag-re))
372 (change-log-search-tag-name-1)))
373 (error nil))
374 (condition-case nil
375 ;; Near filename?
376 (save-excursion
377 (when (and (progn
378 (beginning-of-line)
379 (looking-at change-log-file-names-re))
380 (goto-char (match-end 0))
381 (skip-syntax-forward " ")
382 (looking-at change-log-tag-re))
383 (change-log-search-tag-name-1)))
384 (error nil))
385 (condition-case nil
386 ;; Before filename?
387 (save-excursion
388 (when (and (progn
389 (skip-syntax-backward " ")
390 (beginning-of-line)
391 (looking-at change-log-file-names-re))
392 (goto-char (match-end 0))
393 (skip-syntax-forward " ")
394 (looking-at change-log-tag-re))
395 (change-log-search-tag-name-1)))
396 (error nil))
397 (condition-case nil
398 ;; Near start entry?
399 (save-excursion
400 (when (and (progn
401 (beginning-of-line)
402 (looking-at change-log-start-entry-re))
403 (forward-line) ; Won't work for multiple
404 ; names, etc.
405 (skip-syntax-forward " ")
406 (progn
407 (beginning-of-line)
408 (looking-at change-log-file-names-re))
409 (goto-char (match-end 0))
410 (re-search-forward change-log-tag-re))
411 (change-log-search-tag-name-1)))
412 (error nil))
413 (condition-case nil
414 ;; After parenthesized list?.
415 (when (re-search-backward change-log-tag-re)
416 (save-restriction
417 (narrow-to-region (match-beginning 1) (match-end 1))
418 (goto-char (point-max))
419 (cons (find-tag-default) (point-max))))
420 (error nil))))))
421
422(defvar change-log-find-head nil)
423(defvar change-log-find-tail nil)
424
425(defun change-log-goto-source-1 (tag regexp file buffer
426 &optional window first last)
427 "Search for tag TAG in buffer BUFFER visiting file FILE.
428REGEXP is a regular expression for TAG. The remaining arguments
429are optional: WINDOW denotes the window to display the results of
430the search. FIRST is a position in BUFFER denoting the first
431match from previous searches for TAG. LAST is the position in
432BUFFER denoting the last match for TAG in the last search."
433 (with-current-buffer buffer
434 (save-excursion
435 (save-restriction
436 (widen)
437 (if last
438 (progn
439 ;; When LAST is set make sure we continue from the next
440 ;; line end to not find the same tag again.
441 (goto-char last)
442 (end-of-line)
443 (condition-case nil
444 ;; Try to go to the end of the current defun to avoid
445 ;; false positives within the current defun's body
446 ;; since these would match `add-log-current-defun'.
447 (end-of-defun)
448 ;; Don't fall behind when `end-of-defun' fails.
449 (error (progn (goto-char last) (end-of-line))))
450 (setq last nil))
451 ;; When LAST was not set start at beginning of BUFFER.
452 (goto-char (point-min)))
453 (let (current-defun)
454 (while (and (not last) (re-search-forward regexp nil t))
455 ;; Verify that `add-log-current-defun' invoked at the end
456 ;; of the match returns TAG. This heuristic works well
457 ;; whenever the name of the defun occurs within the first
458 ;; line of the defun.
459 (setq current-defun (add-log-current-defun))
460 (when (and current-defun (string-equal current-defun tag))
461 ;; Record this as last match.
462 (setq last (line-beginning-position))
463 ;; Record this as first match when there's none.
464 (unless first (setq first last)))))))
465 (if (or last first)
466 (with-selected-window (or window (display-buffer buffer))
467 (if last
468 (progn
469 (when (or (< last (point-min)) (> last (point-max)))
470 ;; Widen to show TAG.
471 (widen))
472 (push-mark)
473 (goto-char last))
474 ;; When there are no more matches go (back) to FIRST.
475 (message "No more matches for tag `%s' in file `%s'" tag file)
476 (setq last first)
477 (goto-char first))
478 ;; Return new "tail".
479 (list (selected-window) first last))
480 (message "Source location of tag `%s' not found in file `%s'" tag file)
481 nil)))
482
483(defun change-log-goto-source ()
484 "Go to source location of change log tag near `point'.
485A change log tag is a symbol within a parenthesized,
486comma-separated list."
487 (interactive)
488 (if (and (eq last-command 'change-log-goto-source)
489 change-log-find-tail)
490 (setq change-log-find-tail
491 (condition-case nil
492 (apply 'change-log-goto-source-1
493 (append change-log-find-head change-log-find-tail))
494 (error
495 (format "Cannot find more matches for tag `%s' in file `%s'"
496 (car change-log-find-head)
497 (nth 2 change-log-find-head)))))
498 (save-excursion
499 (let* ((tag-at (change-log-search-tag-name))
500 (tag (car tag-at))
501 (file (when tag-at
502 (change-log-search-file-name (cdr tag-at)))))
503 (if (not tag)
504 (error "No suitable tag near `point'")
505 (setq change-log-find-head
506 (list tag (concat "\\_<" (regexp-quote tag) "\\_>")
507 file (find-file-noselect file)))
508 (condition-case nil
509 (setq change-log-find-tail
510 (apply 'change-log-goto-source-1 change-log-find-head))
511 (error (format "Cannot find matches for tag `%s' in `%s'"
512 tag file))))))))
513
329(defvar change-log-mode-map 514(defvar change-log-mode-map
330 (let ((map (make-sparse-keymap))) 515 (let ((map (make-sparse-keymap)))
331 (define-key map [?\C-c ?\C-p] 'add-log-edit-prev-comment) 516 (define-key map [?\C-c ?\C-p] 'add-log-edit-prev-comment)
332 (define-key map [?\C-c ?\C-n] 'add-log-edit-next-comment) 517 (define-key map [?\C-c ?\C-n] 'add-log-edit-next-comment)
333 (define-key map [?\C-c ?\C-f] 'change-log-find-file) 518 (define-key map [?\C-c ?\C-f] 'change-log-find-file)
519 (define-key map [?\C-c ?\C-c] 'change-log-goto-source)
334 map) 520 map)
335 "Keymap for Change Log major mode.") 521 "Keymap for Change Log major mode.")
336 522