aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias EngdegÄrd2023-10-14 11:42:44 +0200
committerMattias EngdegÄrd2023-10-14 12:15:33 +0200
commitfbbe40cf50ecd9f4ce5f2ff684190d8ed37f2aa9 (patch)
treeb2a1db4a7216c07f728dbad665c3f05787c7963d
parent548bc3e3d18ea6776032ca83dafbc89e3ddb5a5a (diff)
downloademacs-fbbe40cf50ecd9f4ce5f2ff684190d8ed37f2aa9.tar.gz
emacs-fbbe40cf50ecd9f4ce5f2ff684190d8ed37f2aa9.zip
Make the docstrings-wide check 70x faster
Instead of performing a number of expensive transformations on the original doc string and then use a dynamically-created regexp to find wide lines, step through the lines in the unmodified string and only perform the transformations on lines that exceed the limit. This is sound because the transformations are contractive. The new check will usually not cons nor perform any regexp matching. * lisp/emacs-lisp/bytecomp.el (bytecomp--docstring-line-width): New. (byte-compile--wide-docstring-p): Cheaper implementation.
-rw-r--r--lisp/emacs-lisp/bytecomp.el97
1 files changed, 58 insertions, 39 deletions
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el
index b3ddc7dd208..f3e27a511da 100644
--- a/lisp/emacs-lisp/bytecomp.el
+++ b/lisp/emacs-lisp/bytecomp.el
@@ -1680,47 +1680,66 @@ This is a heuristic for guessing the width of a documentation
1680string: `byte-compile--wide-docstring-p' assumes that any 1680string: `byte-compile--wide-docstring-p' assumes that any
1681`substitute-command-keys' command substitutions are this long.") 1681`substitute-command-keys' command substitutions are this long.")
1682 1682
1683(defun byte-compile--wide-docstring-p (docstring col) 1683(defun bytecomp--docstring-line-width (str)
1684 "Return t if string DOCSTRING is wider than COL. 1684 "An approximation of the displayed width of docstring line STR."
1685 (when (string-search "\\`" str)
1686 (setq str (replace-regexp-in-string
1687 (rx "\\`" (group (* (not "'"))) "'")
1688 "\\1"
1689 str t)))
1690 (when (string-search "\\[" str)
1691 (setq str (replace-regexp-in-string
1692 (rx "\\[" (* (not "]")) "]")
1693 (make-string byte-compile--wide-docstring-substitution-len ?x)
1694 str t t)))
1695 (setq str
1696 (replace-regexp-in-string
1697 (rx (or
1698 ;; Ignore some URLs.
1699 (seq "http" (? "s") "://" (* nonl))
1700 ;; Ignore these `substitute-command-keys' substitutions.
1701 (seq "\\" (or "="
1702 (seq "<" (* (not ">")) ">")
1703 (seq "{" (* (not "}")) "}")))
1704 ;; Ignore the function signature that's stashed at the end of
1705 ;; the doc string (in some circumstances).
1706 (seq bol "(" (+ (any word "-/:[]&"))
1707 ;; One or more arguments.
1708 (+ " " (or
1709 ;; Arguments.
1710 (+ (or (syntax symbol)
1711 (any word "-/:[]&=()<>.,?^\\#*'\"")))
1712 ;; Argument that is a list.
1713 (seq "(" (* (not ")")) ")")))
1714 ")")))
1715 "" str t t))
1716 (length str))
1717
1718(defun byte-compile--wide-docstring-p (docstring max-width)
1719 "Whether DOCSTRING contains a line wider than MAX-WIDTH.
1685Ignore all `substitute-command-keys' substitutions, except for 1720Ignore all `substitute-command-keys' substitutions, except for
1686the `\\\\=[command]' ones that are assumed to be of length 1721the `\\\\=[command]' ones that are assumed to be of length
1687`byte-compile--wide-docstring-substitution-len'. Also ignore 1722`byte-compile--wide-docstring-substitution-len'. Also ignore URLs."
1688URLs." 1723 (let ((string-len (length docstring))
1689 (string-match 1724 (start 0)
1690 (format "^.\\{%d,\\}$" (min (1+ col) #xffff)) ; Heed RE_DUP_MAX. 1725 (too-wide nil))
1691 (replace-regexp-in-string 1726 (while (< start string-len)
1692 (rx (or 1727 (let ((eol (or (string-search "\n" docstring start)
1693 ;; Ignore some URLs. 1728 string-len)))
1694 (seq "http" (? "s") "://" (* nonl)) 1729 ;; Since `bytecomp--docstring-line-width' is almost always
1695 ;; Ignore these `substitute-command-keys' substitutions. 1730 ;; contractive, we can safely assume that if the raw length is
1696 (seq "\\" (or "=" 1731 ;; within the allowed width, then so is the transformed width.
1697 (seq "<" (* (not ">")) ">") 1732 ;; This allows us to avoid the very expensive transformation in
1698 (seq "{" (* (not "}")) "}"))) 1733 ;; most cases.
1699 ;; Ignore the function signature that's stashed at the end of 1734 (if (and (> (- eol start) max-width)
1700 ;; the doc string (in some circumstances). 1735 (> (bytecomp--docstring-line-width
1701 (seq bol "(" (+ (any word "-/:[]&")) 1736 (substring docstring start eol))
1702 ;; One or more arguments. 1737 max-width))
1703 (+ " " (or 1738 (progn
1704 ;; Arguments. 1739 (setq too-wide t)
1705 (+ (or (syntax symbol) 1740 (setq start string-len))
1706 (any word "-/:[]&=()<>.,?^\\#*'\""))) 1741 (setq start (1+ eol)))))
1707 ;; Argument that is a list. 1742 too-wide))
1708 (seq "(" (* (not ")")) ")")))
1709 ")")))
1710 ""
1711 ;; Heuristic: We can't reliably do `substitute-command-keys'
1712 ;; substitutions, since the value of a keymap in general can't be
1713 ;; known at compile time. So instead, we assume that these
1714 ;; substitutions are of some length N.
1715 (replace-regexp-in-string
1716 (rx "\\[" (* (not "]")) "]")
1717 (make-string byte-compile--wide-docstring-substitution-len ?x)
1718 ;; For literal key sequence substitutions (e.g. "\\`C-h'"), just
1719 ;; remove the markup as `substitute-command-keys' would.
1720 (replace-regexp-in-string
1721 (rx "\\`" (group (* (not "'"))) "'")
1722 "\\1"
1723 docstring)))))
1724 1743
1725(defcustom byte-compile-docstring-max-column 80 1744(defcustom byte-compile-docstring-max-column 80
1726 "Recommended maximum width of doc string lines. 1745 "Recommended maximum width of doc string lines.