diff options
| author | Mattias EngdegÄrd | 2023-10-14 11:42:44 +0200 |
|---|---|---|
| committer | Mattias EngdegÄrd | 2023-10-14 12:15:33 +0200 |
| commit | fbbe40cf50ecd9f4ce5f2ff684190d8ed37f2aa9 (patch) | |
| tree | b2a1db4a7216c07f728dbad665c3f05787c7963d | |
| parent | 548bc3e3d18ea6776032ca83dafbc89e3ddb5a5a (diff) | |
| download | emacs-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.el | 97 |
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 | |||
| 1680 | string: `byte-compile--wide-docstring-p' assumes that any | 1680 | string: `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. | ||
| 1685 | Ignore all `substitute-command-keys' substitutions, except for | 1720 | Ignore all `substitute-command-keys' substitutions, except for |
| 1686 | the `\\\\=[command]' ones that are assumed to be of length | 1721 | the `\\\\=[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." |
| 1688 | URLs." | 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. |