From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Dmitry Gutov Newsgroups: gmane.emacs.devel Subject: Re: etags completion table Date: Sat, 30 May 2015 02:58:26 +0300 Message-ID: <5568FD22.4010004@yandex.ru> References: <555EC552.5010600@swipnet.se> <837frvywfn.fsf@gnu.org> <55650812.60909@yandex.ru> <831ti2yu1a.fsf@gnu.org> <5565E28A.5040507@yandex.ru> <83wpzuxbtd.fsf@gnu.org> <5565E8AB.5020107@yandex.ru> <83r3q2xa3q.fsf@gnu.org> <5566583F.7020503@yandex.ru> <83h9qxxvo4.fsf@gnu.org> <5566EC49.8010907@yandex.ru> <837frsycly.fsf@gnu.org> <5567351E.7020006@yandex.ru> <83zj4owthp.fsf@gnu.org> <5567AE52.1000600@yandex.ru> <83fv6fx0nk.fsf@gnu.org> <55687241.5030200@yandex.ru> <55689E02.5040605@yandex.ru> <5568CD36.2030703@yandex.ru> NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------070007040305090701050401" X-Trace: ger.gmane.org 1432943943 3800 80.91.229.3 (29 May 2015 23:59:03 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Fri, 29 May 2015 23:59:03 +0000 (UTC) Cc: emacs-devel@gnu.org To: Stefan Monnier Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Sat May 30 01:58:59 2015 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1YyUAz-00049A-F2 for ged-emacs-devel@m.gmane.org; Sat, 30 May 2015 01:58:57 +0200 Original-Received: from localhost ([::1]:37957 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YyUAy-0005kM-HY for ged-emacs-devel@m.gmane.org; Fri, 29 May 2015 19:58:56 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:55566) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YyUAl-0005jK-5M for emacs-devel@gnu.org; Fri, 29 May 2015 19:58:44 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YyUAh-000397-V4 for emacs-devel@gnu.org; Fri, 29 May 2015 19:58:43 -0400 Original-Received: from mail-wg0-x234.google.com ([2a00:1450:400c:c00::234]:33221) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YyUAh-000385-JL for emacs-devel@gnu.org; Fri, 29 May 2015 19:58:39 -0400 Original-Received: by wgez8 with SMTP id z8so74489980wge.0 for ; Fri, 29 May 2015 16:58:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:subject:to:references:cc:from:message-id:date:user-agent :mime-version:in-reply-to:content-type; bh=uJYBzzG6noEkYNz7HIN5MCxYhWlNfrrsmDV213IwEIo=; b=XWyIDI/3CYeHk4wqmrX762NrD0unq8onU1ebwTqrARLiJ4CluwNR5b87wHB4l8krKq gDq/7iPwLKDnQ7r8dLmbF8EmiasIuRTfusdAIMC2kVyUyODwyD7r9HlrsnAguw8KzAbK Bs9bNnqMGXQNO3rQE+Lxq1phbdtWv7x369jmS2W68lqHg9fgvcC0OmFDL2t8//YATwXF RVGTEfgaxi6/KJdMYIIfQB96Z18ynRTImTMwYPnUqC5TTgiPjyWrhEvvMJHKHzPANM35 mlUHo0pvDQIDPfFYhMGt0b5XAUygAqHUTgl+KBwS2T35mK4wCh22JV5GH63zRZlCTqW+ Gifg== X-Received: by 10.180.99.39 with SMTP id en7mr173785wib.31.1432943908928; Fri, 29 May 2015 16:58:28 -0700 (PDT) Original-Received: from [192.168.1.2] ([82.102.93.54]) by mx.google.com with ESMTPSA id um5sm10450949wjc.1.2015.05.29.16.58.28 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 29 May 2015 16:58:28 -0700 (PDT) User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.0 In-Reply-To: X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2a00:1450:400c:c00::234 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:186946 Archived-At: This is a multi-part message in MIME format. --------------070007040305090701050401 Content-Type: text/plain; charset=windows-1252; format=flowed Content-Transfer-Encoding: 7bit On 05/30/2015 12:41 AM, Stefan Monnier wrote: > I see the first patch says that it takes 1.34s to build the obarray and > 0.78s to build an equivalent list of strings, so we could change the > code so as to keep the completion table as a pre-built list of strings > instead of a pre-built obarray. It will also save us a bit of memory. Maybe. The difference isn't much, though, and it's a one-time thing. > As for doing the search each time, the possible gain on the first > completion (0.3s instead of 0.78s) The possible gain is from 1.34s down to 0.78s. I haven't managed to bring the time to generate all completions for "" down any further. > doesn't make up for the loss of going > from 0.02s to 0.3s on subsequent completions. I think you mean 0.02 to 0.2. > So that seems like a non-starter, unless we can speed it up > significantly. It shouldn't be too hard to keep the worst case at > 0.76s, but lowering the 0.3s seems harder. Lowering 0.2 is not too hard if the prefix is at least 2-3 characters long: you drop [\n \t()=,;\177] from the first regexp and simply search for the string. This way, the search for completions for "test" takes only 0.05s (with 37 matches). Of course, that doesn't work at all for an empty prefix. Seems like support for lookbehind in the regexp engine would help unify these cases. However, the worst case is going to come up a lot. After all, that's what you trigger with `C-u M-. TAB'. > Obviously we could get rid > of the "looking-at" within the loop (fold it into the preceding > re-search-forward), but it seems unlikely that this would gain us much > when there are few matches. Indeed. It brings us to 0.78 in the worst case and 0.26 in the best case (I'm blaming the regexp engine), with no easy opportunity for a speed-up when matching a longer string. Patch attached. --------------070007040305090701050401 Content-Type: text/x-patch; name="etags-completion.diff" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="etags-completion.diff" diff --git a/lisp/progmodes/etags.el b/lisp/progmodes/etags.el index 9ff164e..98bbabd 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) @@ -1254,35 +1241,20 @@ buffer-local values of tags table format variables." str (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 + (qs (regexp-quote string)) + (re (format (concat "[\n \t()=,;]\\(%s[^\177 \t()=,;]*\\)\177[0-9]" + "\\|" + "\177\\(%s[^\001]*\\)\001") + qs qs))) (save-excursion (goto-char (point-min)) - ;; This monster regexp matches an etags tag line. - ;; \1 is the string to match; - ;; \2 is not interesting; - ;; \3 is the guessed tag name; XXX guess should be better eg DEFUN - ;; \4 is not interesting; - ;; \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) + (push (if (match-beginning 1) + (match-string-no-properties 1) + (match-string-no-properties 2)) + table))) table)) (defun etags-snarf-tag (&optional use-explicit) ; Doc string? --------------070007040305090701050401--