Subject: bug#20629: 25.0.50; Regression: TAGS broken, can't find anything in C++ files.

From: Dmitry Gutov <[email-masked]>
Date: Thu, 28 May 2015 15:59:20 +0300

And here's an attempt to simplify the regexp and use the input string.

It brings us down to 200ms in the best case (completions for "get_"), 
and that can be improved further, but the worst case (completions for 
"") gets considerably worse: 3 seconds.

diff --git a/lisp/progmodes/etags.el b/lisp/progmodes/etags.el
index 9ff164e..230fffa 100644
--- a/lisp/progmodes/etags.el
+++ b/lisp/progmodes/etags.el
@@ -753,31 +753,18 @@ Assumes the tags table is the current buffer."
        (setq tags-included-tables (funcall 
tags-included-tables-function))))
  
  (defun tags-completion-table ()
-  "Build `tags-completion-table' on demand.
+  "Return tags completion table.
  The tags included in the completion table are those in the current
  tags table and its (recursively) included tags tables."
-  (or tags-completion-table
-      ;; No cached value for this buffer.
-      (condition-case ()
-	  (let (current-table combined-table)
-	    (message "Making tags completion table for %s..." buffer-file-name)
-	    (save-excursion
-	      ;; Iterate over the current list of tags tables.
-	      (while (visit-tags-table-buffer (and combined-table t))
-		;; Find possible completions in this table.
-		(setq current-table (funcall tags-completion-table-function))
-		;; Merge this buffer's completions into the combined table.
-		(if combined-table
-		    (mapatoms
-		     (lambda (sym) (intern (symbol-name sym) combined-table))
-		     current-table)
-		  (setq combined-table current-table))))
-	    (message "Making tags completion table for %s...done"
-		     buffer-file-name)
-	    ;; Cache the result in a buffer-local variable.
-	    (setq tags-completion-table combined-table))
-	(quit (message "Tags completion table construction aborted.")
-	      (setq tags-completion-table nil)))))
+  (completion-table-with-cache
+   (lambda (string)
+     (let (cont tables)
+       (save-excursion
+         ;; Iterate over the current list of tags tables.
+         (while (visit-tags-table-buffer (or cont (progn (setq cont t) 
nil)))
+           ;; Find possible completions in this table.
+           (push (funcall tags-completion-table-function string) tables)))
+       (nreverse (apply #'nconc tables))))))

  ;;;###autoload
  (defun tags-lazy-completion-table ()
@@ -1218,7 +1205,7 @@ buffer-local values of tags table format variables."
         (mapc (lambda (elt) (set (make-local-variable (car elt)) (cdr 
elt)))
  	     '((file-of-tag-function . etags-file-of-tag)
  	       (tags-table-files-function . etags-tags-table-files)
-	       (tags-completion-table-function . etags-tags-completion-table)
+	       (tags-completion-table-function . etags-tags-completions)
  	       (snarf-tag-function . etags-snarf-tag)
  	       (goto-tag-location-function . etags-goto-tag-location)
  	       (find-tag-regexp-search-function . re-search-forward)
@@ -1255,12 +1242,9 @@ buffer-local values of tags table format variables."
  	(expand-file-name str (file-truename default-directory))))))

-(defun etags-tags-completion-table () ; Doc string?
-  (let ((table (make-vector 511 0))
-	(progress-reporter
-	 (make-progress-reporter
-	  (format "Making tags completion table for %s..." buffer-file-name)
-	  (point-min) (point-max))))
+(defun etags-tags-completions (string) ; Doc string?
+  (let ((table nil)
+        (re (format "[\n \t()=,;\177]%s" (regexp-quote string))))
      (save-excursion
        (goto-char (point-min))
        ;; This monster regexp matches an etags tag line.
@@ -1271,18 +1255,16 @@ buffer-local values of tags table format variables."
        ;;   \5 is the explicitly-specified tag name.
        ;;   \6 is the line to start searching at;
        ;;   \7 is the char to start searching at.
-      (while (re-search-forward
-	      "^\\(\\([^\177]+[^-a-zA-Z0-9_+*$:\177]+\\)?\
-\\([-a-zA-Z0-9_+*$?:]+\\)[^-a-zA-Z0-9_+*$?:\177]*\\)\177\
-\\(\\([^\n\001]+\\)\001\\)?\\([0-9]+\\)?,\\([0-9]+\\)?\n"
-	      nil t)
-	(intern	(prog1 (if (match-beginning 5)
-			   ;; There is an explicit tag name.
-			   (buffer-substring (match-beginning 5) (match-end 5))
-			 ;; No explicit tag name.  Best guess.
-			 (buffer-substring (match-beginning 3) (match-end 3)))
-		  (progress-reporter-update progress-reporter (point)))
-		table)))
+      (while (re-search-forward re nil t)
+        (save-excursion
+          (goto-char (match-beginning 0))
+          (let ((match-re (if (eq (char-after) ?\177)
+                              ;; Explicit tag name.
+                              "\177\\([^\001]+\\)\001"
+                            ;; Implicit tag name.
+                            "[\n \t()=,;]\\([^\177 \t()=,;]+\\)\177")))
+            (when (looking-at match-re)
+              (push (match-string 1) table))))))
      table))

  (defun etags-snarf-tag (&optional use-explicit) ; Doc string?