]> code.delx.au - gnu-emacs-elpa/blobdiff - packages/ggtags/ggtags.el
Merge branch 'master' of github.com:leoliu/ggtags
[gnu-emacs-elpa] / packages / ggtags / ggtags.el
index 2e986e8627b251371feb5afe9cfc7a639ca6c15a..c7a0673c0a6ecc9387de3cad10af2baf02758118 100644 (file)
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2013-2014  Free Software Foundation, Inc.
 
 ;; Author: Leo Liu <sdl.web@gmail.com>
-;; Version: 0.8.2
+;; Version: 0.8.3
 ;; Keywords: tools, convenience
 ;; Created: 2013-01-29
 ;; URL: https://github.com/leoliu/ggtags
@@ -625,11 +625,10 @@ source trees. See Info node `(global)gtags' for details."
          (setenv "GTAGSLABEL" "ctags"))
        (ggtags-with-temp-message "`gtags' in progress..."
          (let ((default-directory (file-name-as-directory root))
-               (args (cl-remove-if
-                      ;; Place --idutils first
-                      #'null (list (and ggtags-use-idutils "--idutils")
-                                   (and conf "--gtagsconf")
-                                   (and conf (ggtags-ensure-localname conf))))))
+               (args (cl-remove-if #'null
+                                   (list (and ggtags-use-idutils "--idutils")
+                                         (and conf "--gtagsconf")
+                                         (and conf (ggtags-ensure-localname conf))))))
            (condition-case err
                (apply #'ggtags-process-string "gtags" args)
              (error (if (and ggtags-use-idutils
@@ -659,6 +658,33 @@ Do nothing if GTAGS exceeds the oversize limit unless FORCE."
        (setf (ggtags-project-dirty-p (ggtags-find-project)) nil)
        (setf (ggtags-project-mtime (ggtags-find-project)) (float-time))))))
 
+(defun ggtags-delete-tags ()
+  "Delete file GTAGS, GRTAGS, GPATH, ID etc. generated by gtags."
+  (interactive (ignore (ggtags-check-project)))
+  (when (ggtags-current-project-root)
+    (let* ((re (concat "\\`" (regexp-opt '("GPATH" "GRTAGS" "GTAGS" "ID")) "\\'"))
+           (files (cl-remove-if-not
+                   (lambda (file)
+                     ;; Don't trust `directory-files'.
+                     (let ((case-fold-search nil))
+                       (string-match-p re (file-name-nondirectory file))))
+                   (directory-files (ggtags-current-project-root) t re)))
+           (buffer "*GTags File List*"))
+      (or files (user-error "No tag files found"))
+      (with-output-to-temp-buffer buffer
+        (princ (mapconcat #'identity files "\n")))
+      (let ((win (get-buffer-window buffer)))
+        (unwind-protect
+            (progn
+              (fit-window-to-buffer win)
+              (when (yes-or-no-p "Remove GNU Global tag files? ")
+                (with-demoted-errors (mapc #'delete-file files))
+                (remhash (ggtags-current-project-root) ggtags-projects)
+                (and (overlayp ggtags-highlight-tag-overlay)
+                     (delete-overlay ggtags-highlight-tag-overlay))))
+          (when (window-live-p win)
+            (quit-window t win)))))))
+
 (defvar-local ggtags-completion-cache nil)
 
 ;; See global/libutil/char.c
@@ -737,10 +763,9 @@ Do nothing if GTAGS exceeds the oversize limit unless FORCE."
                     args)))
     (mapconcat #'identity (delq nil xs) " ")))
 
-;; takes three values: nil, t and a marker
+;; Can be three values: nil, t and a marker; t means start marker has
+;; been saved in the tag ring.
 (defvar ggtags-global-start-marker nil)
-(defvar ggtags-global-exit-status 0)
-(defvar ggtags-global-match-count 0)
 (defvar ggtags-tag-ring-index nil)
 (defvar ggtags-global-search-history nil)
 
@@ -761,8 +786,6 @@ Do nothing if GTAGS exceeds the oversize limit unless FORCE."
           (nth 4 (assoc (ggtags-global-search-id command default-directory)
                         ggtags-global-search-history)))
     (ggtags-navigation-mode +1)
-    (setq ggtags-global-exit-status 0
-          ggtags-global-match-count 0)
     (ggtags-update-tags)
     (ggtags-with-current-project
      (with-current-buffer (with-display-buffer-no-window
@@ -792,7 +815,7 @@ Do nothing if GTAGS exceeds the oversize limit unless FORCE."
      (save-excursion
        (beginning-of-line)
        (and (looking-at re) (match-string sub))))
-    (_ (warn "Invalid value for `ggtags-include-pattern':%s"
+    (_ (warn "Invalid value for `ggtags-include-pattern': %s"
              ggtags-include-pattern)
        nil)))
 
@@ -811,7 +834,7 @@ definition tags."
      (if include (list include 'include)
        (list (ggtags-read-tag 'definition current-prefix-arg)
              (and current-prefix-arg 'definition)))))
-  (ggtags-check-project)     ; for `ggtags-current-project-root' below
+  (ggtags-check-project)     ; For `ggtags-current-project-root' below.
   (cond
    ((eq what 'include)
     (ggtags-find-file name))
@@ -1049,33 +1072,6 @@ Use \\[jump-to-register] to restore the search session."
 (defun ggtags-bookmark-jump (bmk)
   (ggtags-global-rerun-search-1 (bookmark-prop-get bmk 'ggtags-search)))
 
-(defun ggtags-delete-tag-files ()
-  "Delete the GTAGS, GRTAGS, GPATH etc. files generated by gtags."
-  (interactive (ignore (ggtags-check-project)))
-  (when (ggtags-current-project-root)
-    (let* ((re (concat "\\`" (regexp-opt '("GPATH" "GRTAGS" "GTAGS" "ID")) "\\'"))
-           (files (cl-remove-if-not
-                   (lambda (file)
-                     ;; Don't trust `directory-files'.
-                     (let ((case-fold-search nil))
-                       (string-match-p re (file-name-nondirectory file))))
-                   (directory-files (ggtags-current-project-root) t re)))
-           (buffer "*GTags File List*"))
-      (or files (user-error "No tag files found"))
-      (with-output-to-temp-buffer buffer
-        (princ (mapconcat #'identity files "\n")))
-      (let ((win (get-buffer-window buffer)))
-        (unwind-protect
-            (progn
-              (fit-window-to-buffer win)
-              (when (yes-or-no-p "Remove GNU Global tag files? ")
-                (with-demoted-errors (mapc #'delete-file files))
-                (remhash (ggtags-current-project-root) ggtags-projects)
-                (and (overlayp ggtags-highlight-tag-overlay)
-                     (delete-overlay ggtags-highlight-tag-overlay))))
-          (when (window-live-p win)
-            (quit-window t win)))))))
-
 (defun ggtags-browse-file-as-hypertext (file line)
   "Browse FILE in hypertext (HTML) form."
   (interactive (if (or current-prefix-arg (not buffer-file-name))
@@ -1223,41 +1219,46 @@ commands `next-error' and `previous-error'.
      (goto-char (marker-position m)))
     (_ (error "Dead marker"))))
 
+(defun ggtags-global-exit-message-1 ()
+  "Get the total of matches and db file used."
+  (save-excursion
+    (goto-char (point-max))
+    (if (re-search-backward
+         "^\\w+ \\(not found\\)\\|^\\([0-9]+\\) \\w+ located" nil t)
+        (cons (or (and (match-string 1) 0)
+                  (string-to-number (match-string 2)))
+              (when (re-search-forward
+                     "using \\(?:\\(idutils\\)\\|'[^']*/\\(\\w+\\)'\\)"
+                     (line-end-position)
+                     t)
+                (or (and (match-string 1) "ID")
+                    (match-string 2))))
+      (cons 0 nil))))
+
+(defvar-local ggtags-global-exit-info nil) ; (EXIT-STATUS COUNT DB)
+
 (defun ggtags-global-exit-message-function (_process-status exit-status msg)
-  (setq ggtags-global-exit-status exit-status)
-  (pcase-let ((`(,count . ,db)
-               (save-excursion
-                 (goto-char (point-max))
-                 (if (re-search-backward
-                      "^\\w+ \\(not found\\)\\|^\\([0-9]+\\) \\w+ located" nil t)
-                     (cons (or (and (match-string 1) 0)
-                               (string-to-number (match-string 2)))
-                           (when (re-search-forward
-                                  "using \\(?:\\(idutils\\)\\|'[^']*/\\(\\w+\\)'\\)"
-                                  (line-end-position)
-                                  t)
-                             (or (and (match-string 1) "ID")
-                                 (match-string 2))))
-                   (cons 0 nil)))))
-    (setq ggtags-global-match-count count)
-    ;; Clear the start marker in case of zero matches.
-    (and (zerop count)
-         (markerp ggtags-global-start-marker)
-         (setq ggtags-global-start-marker nil))
-    (cons (if (> exit-status 0)
-              msg
-            (format "found %d %s"
-                    count
-                    (funcall (if (= count 1) #'car #'cadr)
-                             (pcase db
-                               ;; ` required for 24.1 and 24.2
-                               (`"GTAGS"  '("definition" "definitions"))
-                               (`"GSYMS"  '("symbol"     "symbols"))
-                               (`"GRTAGS" '("reference"  "references"))
-                               (`"GPATH"  '("file"       "files"))
-                               (`"ID"     '("identifier" "identifiers"))
-                               (_         '("match"      "matches"))))))
-          exit-status)))
+  "A function for `compilation-exit-message-function'."
+  (pcase (ggtags-global-exit-message-1)
+    (`(,count . ,db)
+     (setq ggtags-global-exit-info (list exit-status count db))
+     ;; Clear the start marker in case of zero matches.
+     (and (zerop count)
+          (markerp ggtags-global-start-marker)
+          (setq ggtags-global-start-marker nil))
+     (cons (if (> exit-status 0)
+               msg
+             (format "found %d %s" count
+                     (funcall (if (= count 1) #'car #'cadr)
+                              (pcase db
+                                ;; ` required for 24.1 and 24.2
+                                (`"GTAGS"  '("definition" "definitions"))
+                                (`"GSYMS"  '("symbol"     "symbols"))
+                                (`"GRTAGS" '("reference"  "references"))
+                                (`"GPATH"  '("file"       "files"))
+                                (`"ID"     '("identifier" "identifiers"))
+                                (_         '("match"      "matches"))))))
+           exit-status))))
 
 (defun ggtags-global-column (start)
   ;; START is the beginning position of source text.
@@ -1306,7 +1307,7 @@ commands `next-error' and `previous-error'.
 
 (defun ggtags-abbreviate-files (start end)
   (goto-char start)
-  (let* ((error-re (cdr (assq ggtags-global-output-format
+  (let* ((error-re (cdr (assq (car compilation-error-regexp-alist)
                               ggtags-global-error-regexp-alist-alist)))
          (sub (cadr error-re)))
     (when (and ggtags-global-abbreviate-filename error-re)
@@ -1411,10 +1412,9 @@ commands `next-error' and `previous-error'.
 
 (define-compilation-mode ggtags-global-mode "Global"
   "A mode for showing outputs from gnu global."
-  ;; Make it buffer local for `ggtags-abbreviate-files'.
-  (make-local-variable 'ggtags-global-output-format)
-  (setq-local compilation-error-regexp-alist
-              (list ggtags-global-output-format))
+  ;; Note: Place `ggtags-global-output-format' as first element for
+  ;; `ggtags-abbreviate-files'.
+  (setq-local compilation-error-regexp-alist (list ggtags-global-output-format))
   (pcase ggtags-auto-jump-to-match
     (`history (make-local-variable 'ggtags-auto-jump-to-match-target)
               (setq-local compilation-auto-jump-to-first-error
@@ -1613,25 +1613,39 @@ commands `next-error' and `previous-error'.
                           ggtags-global-history-length))))
     (run-hooks 'ggtags-find-tag-hook)))
 
+(put 'ggtags-navigation-mode-lighter 'risky-local-variable t)
+
+(defvar ggtags-navigation-mode-lighter
+  '(" GG["
+    (:eval
+     (if (not (buffer-live-p ggtags-global-last-buffer))
+         '(:propertize "??" face error help-echo "No Global buffer")
+       (with-current-buffer ggtags-global-last-buffer
+         (pcase (or ggtags-global-exit-info '(0 0 ""))
+           (`(,exit ,count ,db)
+            `((:propertize ,(pcase db
+                              (`"GTAGS"  "D")
+                              (`"GRTAGS" "R")
+                              (`"GSYMS"  "S")
+                              (`"GPATH"  "F")
+                              (`"ID"     "I"))
+                           face success)
+              (:propertize
+               ,(pcase (get-text-property (line-beginning-position)
+                                          'compilation-message)
+                  (`nil "?")
+                  ;; Assume the first match appears at line 5
+                  (_ (number-to-string (- (line-number-at-pos) 4))))
+               face success)
+              "/"
+              (:propertize ,(number-to-string count) face success)
+              ,(unless (zerop exit)
+                 `(":" (:propertize ,(number-to-string exit) face error)))))))))
+    "]")
+  "Ligher for `ggtags-navigation-mode'; set to nil to disable it.")
+
 (define-minor-mode ggtags-navigation-mode nil
-  :lighter
-  (" GG[" (:eval
-           (ignore-errors
-             (ggtags-ensure-global-buffer
-               (let ((index (when (get-text-property (line-beginning-position)
-                                                     'compilation-message)
-                              ;; Assume the first match appears at line 5
-                              (- (line-number-at-pos) 4))))
-                 `((:propertize ,(if index
-                                     (number-to-string (max index 0))
-                                   "?") face success) "/")))))
-   (:propertize (:eval (number-to-string ggtags-global-match-count))
-                face success)
-   (:eval
-    (unless (zerop ggtags-global-exit-status)
-      `(":" (:propertize ,(number-to-string ggtags-global-exit-status)
-                         face error))))
-   "]")
+  :lighter ggtags-navigation-mode-lighter
   :global t
   (if ggtags-navigation-mode
       (progn
@@ -1750,7 +1764,7 @@ When finished invoke CALLBACK in BUFFER with process exit status."
   (let ((m (make-sparse-keymap)))
     ;; Globally bound to `M-g p'.
     ;; (define-key m "\M-'" 'previous-error)
-    (define-key m (kbd "M-DEL") 'ggtags-delete-tag-files)
+    (define-key m (kbd "M-DEL") 'ggtags-delete-tags)
     (define-key m "\M-p" 'ggtags-prev-mark)
     (define-key m "\M-n" 'ggtags-next-mark)
     (define-key m "\M-f" 'ggtags-find-file)
@@ -1800,8 +1814,9 @@ When finished invoke CALLBACK in BUFFER with process exit status."
       '(menu-item "Browse as hypertext" ggtags-browse-file-as-hypertext
                   :enable (ggtags-find-project)))
     (define-key menu [delete-tags]
-      '(menu-item "Delete tag files" ggtags-delete-tag-files
-                  :enable (ggtags-find-project)))
+      '(menu-item "Delete tags" ggtags-delete-tags
+                  :enable (ggtags-find-project)
+                  :help "Delete file GTAGS, GRTAGS, GPATH, ID etc."))
     (define-key menu [kill-buffers]
       '(menu-item "Kill project file buffers" ggtags-kill-file-buffers
                   :enable (ggtags-find-project)))
@@ -1815,14 +1830,14 @@ When finished invoke CALLBACK in BUFFER with process exit status."
     (define-key menu [prev-mark]
       '(menu-item "Previous mark" ggtags-prev-mark))
     (define-key menu [sep1] menu-bar-separator)
-    (define-key menu [rerun-search]
-      '(menu-item "Re-run past search" ggtags-global-rerun-search))
-    (define-key menu [save-to-register]
-      '(menu-item "Save search to register" ggtags-save-to-register))
     (define-key menu [previous-error]
       '(menu-item "Previous match" previous-error))
     (define-key menu [next-error]
       '(menu-item "Next match" next-error))
+    (define-key menu [rerun-search]
+      '(menu-item "Re-run past search" ggtags-global-rerun-search))
+    (define-key menu [save-to-register]
+      '(menu-item "Save search to register" ggtags-save-to-register))
     (define-key menu [find-file]
       '(menu-item "Find files" ggtags-find-file))
     (define-key menu [query-replace]
@@ -1832,7 +1847,8 @@ When finished invoke CALLBACK in BUFFER with process exit status."
     (define-key menu [grep]
       '(menu-item "Grep" ggtags-grep))
     (define-key menu [find-symbol]
-      '(menu-item "Find other symbol" ggtags-find-other-symbol))
+      '(menu-item "Find other symbol" ggtags-find-other-symbol
+                  :help "Find references without definition"))
     (define-key menu [find-tag-regexp]
       '(menu-item "Find tag matching regexp" ggtags-find-tag-regexp))
     (define-key menu [show-definition]