diff options
| author | Martin Rudalics | 2008-07-13 07:35:15 +0000 |
|---|---|---|
| committer | Martin Rudalics | 2008-07-13 07:35:15 +0000 |
| commit | f06b5ed2ce9329fb6112f2ccfd7e3271c5cbe70c (patch) | |
| tree | a5306a883c58100899a49144a8ed387fe58b7179 | |
| parent | 241d447bd378cbe9cb7f7c0d73ff2e9f1e48a9eb (diff) | |
| download | emacs-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/NEWS | 3 | ||||
| -rw-r--r-- | lisp/ChangeLog | 9 | ||||
| -rw-r--r-- | lisp/add-log.el | 196 |
3 files changed, 203 insertions, 5 deletions
| @@ -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) |
| 723 | finds the file associated with the current log entry. | 723 | finds 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) | ||
| 726 | goes 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). |
| 726 | If `default-directory' is a remote file name, subprocesses are started | 729 | If `default-directory' is a remote file name, subprocesses are started |
| 727 | on the corresponding remote system. | 730 | on 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 @@ | |||
| 1 | 2008-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 | |||
| 1 | 2008-07-13 Jay Belanger <jay.p.belanger@gmail.com> | 10 | 2008-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. | ||
| 331 | Optional argument FROM specifies a buffer position where the tag | ||
| 332 | name should be located. Return value is a cons whose car is the | ||
| 333 | string representing the tag and whose cdr is the position where | ||
| 334 | the 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'. | ||
| 353 | Optional argument AT non-nil means search near buffer position | ||
| 354 | AT. Return value is a cons whose car is the string representing | ||
| 355 | the 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. | ||
| 428 | REGEXP is a regular expression for TAG. The remaining arguments | ||
| 429 | are optional: WINDOW denotes the window to display the results of | ||
| 430 | the search. FIRST is a position in BUFFER denoting the first | ||
| 431 | match from previous searches for TAG. LAST is the position in | ||
| 432 | BUFFER 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'. | ||
| 485 | A change log tag is a symbol within a parenthesized, | ||
| 486 | comma-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 | ||