Stop imenu indexing after a certain number of seconds

* doc/emacs/programs.texi (Imenu): Document it.
* lisp/imenu.el (imenu-max-index-time): New user option.
(imenu-default-create-index-function, imenu--generic-function):
Use it (bug#18696).
This commit is contained in:
Lars Ingebrigtsen 2021-09-17 17:54:21 +02:00
parent f29abc3db6
commit a8103cf9e0
3 changed files with 29 additions and 4 deletions

View file

@ -275,8 +275,10 @@ a non-@code{nil} value. There is no need to rescan because of small
changes in the text.
@vindex imenu-auto-rescan-maxout
@vindex imenu-max-index-time
@code{imenu-auto-rescan} will be disabled in buffers that are larger
than @code{imenu-auto-rescan-maxout} in bytes.
than @code{imenu-auto-rescan-maxout} in bytes, and scanning is
stopped if it takes more than @code{imenu-max-index-time} seconds.
@vindex imenu-sort-function
You can customize the way the menus are sorted by setting the

View file

@ -2929,6 +2929,13 @@ This previously used to align subsequent lines with the last sibling,
but it now aligns with the first sibling (which is the preferred style
in Ruby).
** Imenu
+++
*** New user option 'imenu-max-index-time'.
If creating the imenu index takes longer than specified by this
variable (default 5 seconds), imenu indexing is stopped.
* New Modes and Packages in Emacs 28.1

View file

@ -85,7 +85,8 @@ This might not yet be honored by all index-building functions."
:type 'boolean)
(defcustom imenu-auto-rescan-maxout 600000
"Imenu auto-rescan is disabled in buffers larger than this size (in bytes)."
"Imenu auto-rescan is disabled in buffers larger than this size (in bytes).
Also see `imenu-max-index-time'."
:type 'integer
:version "26.2")
@ -153,6 +154,11 @@ uses `imenu--generic-function')."
:type 'boolean
:version "24.4")
(defcustom imenu-max-index-time 5
"Max time to use when creating imenu indices."
:type 'number
:version "28.1")
;;;###autoload
(defvar-local imenu-generic-expression nil
"List of definition matchers for creating an Imenu index.
@ -520,10 +526,13 @@ The alternate method, which is the one most often used, is to call
(cond ((and imenu-prev-index-position-function
imenu-extract-index-name-function)
(let ((index-alist '()) (pos (point-max))
(start (float-time))
name)
(goto-char pos)
;; Search for the function
(while (funcall imenu-prev-index-position-function)
(while (and (funcall imenu-prev-index-position-function)
;; Don't use an excessive amount of time.
(< (- (float-time) start) imenu-max-index-time))
(unless (< (point) pos)
(error "Infinite loop at %s:%d: imenu-prev-index-position-function does not move point" (buffer-name) pos))
(setq pos (point))
@ -576,6 +585,7 @@ depending on PATTERNS."
(not (local-variable-p 'font-lock-defaults)))
imenu-case-fold-search
(nth 2 font-lock-defaults)))
(start-time (float-time))
(old-table (syntax-table))
(table (copy-syntax-table (syntax-table)))
(slist imenu-syntax-alist))
@ -618,7 +628,13 @@ depending on PATTERNS."
(not invis))))))
;; Exit the loop if we get an empty match,
;; because it means a bad regexp was specified.
(not (= (match-beginning 0) (match-end 0))))
(not (= (match-beginning 0) (match-end 0)))
;; Don't take an excessive amount of time.
(or (< (- (float-time) start-time)
imenu-max-index-time)
(progn
(message "`imenu-max-index-time' exceeded")
nil)))
(setq start (point))
;; Record the start of the line in which the match starts.
;; That's the official position of this definition.