org-element--current-element: Do not try to query cache

* lisp/org-element.el (org-element--current-element): Do not try to
search cache.  This is rarely useful and forces an awkward
`org-element-copy' workaround what parsing buffer.
(org-element--parse-elements): Do not use `org-element-copy' for
element at point - it is now safe to assume that
`org-element--current-element' does not return cached.
(org-element--parse-to): Do not force disabled cache when calling
`org-element--current-element'.  It is no longer needed.
This commit is contained in:
Ihor Radchenko 2023-05-01 23:45:24 +02:00
parent bc4ee1c72a
commit 534045979d
No known key found for this signature in database
GPG Key ID: 6470762A7DA11D8B
1 changed files with 173 additions and 218 deletions

View File

@ -4187,7 +4187,7 @@ Assume point is at the first equal sign marker."
(defvar org-inlinetask-min-level); Declared in org-inlinetask.el
(defvar org-element--cache-sync-requests); Declared later
(defun org-element--current-element (limit &optional granularity mode structure add-to-cache)
(defun org-element--current-element (limit &optional granularity mode structure)
"Parse the element starting at point.
Return value is a list like (TYPE PROPS) where TYPE is the type
@ -4212,207 +4212,176 @@ Optional argument MODE, when non-nil, can be either
If STRUCTURE isn't provided but MODE is set to `item', it will be
computed.
Optional argument ADD-TO-CACHE, when non-nil, and when cache is active,
will also add current element to cache if it is not yet there. Use
this argument with care, as validity of the element in parse tree is
not checked.
This function assumes point is always at the beginning of the
element it has to parse."
(let* ((element (and (not (buffer-narrowed-p))
(org-element--cache-active-p)
(not org-element--cache-sync-requests)
(org-element--cache-find (point) t)))
(element (progn (while (and element
(not (and (eq (point) (org-element-property :begin element))
(eq mode (org-element-property :mode element)))))
(setq element (org-element-property :parent element)))
element))
(old-element element)
(element (when
(pcase (org-element-property :granularity element)
(`nil t)
(`object t)
(`element (not (memq granularity '(nil object))))
(`greater-element (not (memq granularity '(nil object element))))
(`headline (eq granularity 'headline)))
element)))
(if element
element
(save-excursion
(let ((case-fold-search t)
;; Determine if parsing depth allows for secondary strings
;; parsing. It only applies to elements referenced in
;; `org-element-secondary-value-alist'.
(raw-secondary-p (and granularity (not (eq granularity 'object))))
result)
(setq
result
;; Regexp matches below should avoid modifying match data,
;; if possible. Doing it unnecessarily degrades regexp
;; matching performance an order of magnitude, which
;; becomes important when parsing large buffers with huge
;; amount of elements to be parsed.
;;
;; In general, the checks below should be as efficient as
;; possible, especially early in the `cond' form. (The
;; early checks will contribute to al subsequent parsers as
;; well).
(cond
;; Item.
((eq mode 'item) (org-element-item-parser limit structure raw-secondary-p))
;; Table Row.
((eq mode 'table-row) (org-element-table-row-parser limit))
;; Node Property.
((eq mode 'node-property) (org-element-node-property-parser limit))
;; Headline.
((and (looking-at-p "^\\*+ ")
(or (not (featurep 'org-inlinetask))
(save-excursion
(< (skip-chars-forward "*")
(if org-odd-levels-only
(1- (* org-inlinetask-min-level 2))
org-inlinetask-min-level)))))
(org-element-headline-parser limit raw-secondary-p))
;; Sections (must be checked after headline).
((memq mode '(section first-section)) (org-element-section-parser nil))
;; Comments.
((looking-at-p "^[ \t]*#\\(?: \\|$\\)") (org-element-comment-parser limit))
;; Planning.
((and (eq mode 'planning)
(eq ?* (char-after (line-beginning-position 0)))
(looking-at-p org-element-planning-line-re))
(org-element-planning-parser limit))
;; Property drawer.
((and (pcase mode
(`planning (eq ?* (char-after (line-beginning-position 0))))
((or `property-drawer `top-comment)
(save-excursion
(beginning-of-line 0)
(not (looking-at-p "[[:blank:]]*$"))))
(_ nil))
(looking-at-p org-property-drawer-re))
(org-element-property-drawer-parser limit))
;; When not at bol, point is at the beginning of an item or
;; a footnote definition: next item is always a paragraph.
((not (bolp)) (org-element-paragraph-parser limit (list (point))))
;; Clock.
((looking-at-p org-element-clock-line-re) (org-element-clock-parser limit))
;; Inlinetask.
((looking-at-p "^\\*+ ") (org-element-inlinetask-parser limit raw-secondary-p))
;; From there, elements can have affiliated keywords.
(t (let ((affiliated (org-element--collect-affiliated-keywords
limit (memq granularity '(nil object)))))
(cond
;; Jumping over affiliated keywords put point off-limits.
;; Parse them as regular keywords.
((and (cdr affiliated) (>= (point) limit))
(goto-char (car affiliated))
(org-element-keyword-parser limit nil))
;; LaTeX Environment.
((looking-at-p org-element--latex-begin-environment)
(org-element-latex-environment-parser limit affiliated))
;; Drawer.
((looking-at-p org-element-drawer-re)
(org-element-drawer-parser limit affiliated))
;; Fixed Width
((looking-at-p "[ \t]*:\\( \\|$\\)")
(org-element-fixed-width-parser limit affiliated))
;; Inline Comments, Blocks, Babel Calls, Dynamic Blocks and
;; Keywords.
((looking-at "[ \t]*#\\+")
(goto-char (match-end 0))
(cond
((looking-at "BEGIN_\\(\\S-+\\)")
(beginning-of-line)
(funcall (pcase (upcase (match-string 1))
("CENTER" #'org-element-center-block-parser)
("COMMENT" #'org-element-comment-block-parser)
("EXAMPLE" #'org-element-example-block-parser)
("EXPORT" #'org-element-export-block-parser)
("QUOTE" #'org-element-quote-block-parser)
("SRC" #'org-element-src-block-parser)
("VERSE" #'org-element-verse-block-parser)
(_ #'org-element-special-block-parser))
limit
affiliated))
((looking-at-p "CALL:")
(beginning-of-line)
(org-element-babel-call-parser limit affiliated))
((save-excursion
(beginning-of-line)
(looking-at-p org-element-dynamic-block-open-re))
(beginning-of-line)
(org-element-dynamic-block-parser limit affiliated))
((looking-at-p "\\S-+:")
(beginning-of-line)
(org-element-keyword-parser limit affiliated))
(t
(beginning-of-line)
(org-element-paragraph-parser limit affiliated))))
;; Footnote Definition.
((looking-at-p org-footnote-definition-re)
(org-element-footnote-definition-parser limit affiliated))
;; Horizontal Rule.
((looking-at-p "[ \t]*-\\{5,\\}[ \t]*$")
(org-element-horizontal-rule-parser limit affiliated))
;; Diary Sexp.
((looking-at-p "%%(")
(org-element-diary-sexp-parser limit affiliated))
;; Table.
((or (looking-at-p "[ \t]*|")
;; There is no strict definition of a table.el
;; table. Try to prevent false positive while being
;; quick.
(let ((rule-regexp
(rx (zero-or-more (any " \t"))
"+"
(one-or-more (one-or-more "-") "+")
(zero-or-more (any " \t"))
eol))
(non-table.el-line
(rx bol
(zero-or-more (any " \t"))
(or eol (not (any "+| \t")))))
(next (line-beginning-position 2)))
;; Start with a full rule.
(and
(looking-at-p rule-regexp)
(< next limit) ;no room for a table.el table
(save-excursion
(end-of-line)
(cond
;; Must end with a full rule.
((not (re-search-forward non-table.el-line limit 'move))
(if (bolp) (forward-line -1) (beginning-of-line))
(looking-at-p rule-regexp))
;; Ignore pseudo-tables with a single
;; rule.
((= next (line-beginning-position))
nil)
;; Must end with a full rule.
(t
(forward-line -1)
(looking-at-p rule-regexp)))))))
(org-element-table-parser limit affiliated))
;; List.
((looking-at-p (org-item-re))
(org-element-plain-list-parser
limit affiliated
(or structure (org-element--list-struct limit))))
;; Default element: Paragraph.
(t (org-element-paragraph-parser limit affiliated)))))))
(when result
(org-element-put-property result :mode mode)
(org-element-put-property result :granularity granularity))
(when (and add-to-cache(not (buffer-narrowed-p))
(not org-element--cache-sync-requests)
(org-element--cache-active-p))
(if (not old-element)
(setq result (org-element--cache-put result))
(org-element-set-element old-element result)
(setq result old-element)))
result)))))
(save-excursion
(let ((case-fold-search t)
;; Determine if parsing depth allows for secondary strings
;; parsing. It only applies to elements referenced in
;; `org-element-secondary-value-alist'.
(raw-secondary-p (and granularity (not (eq granularity 'object))))
result at-task?)
(setq
result
;; Regexp matches below should avoid modifying match data,
;; if possible. Doing it unnecessarily degrades regexp
;; matching performance an order of magnitude, which
;; becomes important when parsing large buffers with huge
;; amount of elements to be parsed.
;;
;; In general, the checks below should be as efficient as
;; possible, especially early in the `cond' form. (The
;; early checks will contribute to al subsequent parsers as
;; well).
(cond
;; Item.
((eq mode 'item) (org-element-item-parser limit structure raw-secondary-p))
;; Table Row.
((eq mode 'table-row) (org-element-table-row-parser limit))
;; Node Property.
((eq mode 'node-property) (org-element-node-property-parser limit))
;; Headline.
((and (looking-at-p "^\\*+ ")
(setq at-task? t)
(or (not (featurep 'org-inlinetask))
(save-excursion
(< (skip-chars-forward "*")
(if org-odd-levels-only
(1- (* org-inlinetask-min-level 2))
org-inlinetask-min-level)))))
(org-element-headline-parser limit raw-secondary-p))
;; Sections (must be checked after headline).
((memq mode '(section first-section)) (org-element-section-parser nil))
;; Comments.
((looking-at-p "^[ \t]*#\\(?: \\|$\\)") (org-element-comment-parser limit))
;; Planning.
((and (eq mode 'planning)
(eq ?* (char-after (line-beginning-position 0)))
(looking-at-p org-element-planning-line-re))
(org-element-planning-parser limit))
;; Property drawer.
((and (pcase mode
(`planning (eq ?* (char-after (line-beginning-position 0))))
((or `property-drawer `top-comment)
(save-excursion
(beginning-of-line 0)
(not (looking-at-p "[[:blank:]]*$"))))
(_ nil))
(looking-at-p org-property-drawer-re))
(org-element-property-drawer-parser limit))
;; When not at bol, point is at the beginning of an item or
;; a footnote definition: next item is always a paragraph.
((not (bolp)) (org-element-paragraph-parser limit (list (point))))
;; Clock.
((looking-at-p org-element-clock-line-re) (org-element-clock-parser limit))
;; Inlinetask.
(at-task? (org-element-inlinetask-parser limit raw-secondary-p))
;; From there, elements can have affiliated keywords.
(t (let ((affiliated (org-element--collect-affiliated-keywords
limit (memq granularity '(nil object)))))
(cond
;; Jumping over affiliated keywords put point off-limits.
;; Parse them as regular keywords.
((and (cdr affiliated) (>= (point) limit))
(goto-char (car affiliated))
(org-element-keyword-parser limit nil))
;; LaTeX Environment.
((looking-at-p org-element--latex-begin-environment)
(org-element-latex-environment-parser limit affiliated))
;; Drawer.
((looking-at-p org-element-drawer-re)
(org-element-drawer-parser limit affiliated))
;; Fixed Width
((looking-at-p "[ \t]*:\\( \\|$\\)")
(org-element-fixed-width-parser limit affiliated))
;; Inline Comments, Blocks, Babel Calls, Dynamic Blocks and
;; Keywords.
((looking-at "[ \t]*#\\+")
(goto-char (match-end 0))
(cond
((looking-at "BEGIN_\\(\\S-+\\)")
(beginning-of-line)
(funcall (pcase (upcase (match-string 1))
("CENTER" #'org-element-center-block-parser)
("COMMENT" #'org-element-comment-block-parser)
("EXAMPLE" #'org-element-example-block-parser)
("EXPORT" #'org-element-export-block-parser)
("QUOTE" #'org-element-quote-block-parser)
("SRC" #'org-element-src-block-parser)
("VERSE" #'org-element-verse-block-parser)
(_ #'org-element-special-block-parser))
limit
affiliated))
((looking-at-p "CALL:")
(beginning-of-line)
(org-element-babel-call-parser limit affiliated))
((save-excursion
(beginning-of-line)
(looking-at-p org-element-dynamic-block-open-re))
(beginning-of-line)
(org-element-dynamic-block-parser limit affiliated))
((looking-at-p "\\S-+:")
(beginning-of-line)
(org-element-keyword-parser limit affiliated))
(t
(beginning-of-line)
(org-element-paragraph-parser limit affiliated))))
;; Footnote Definition.
((looking-at-p org-footnote-definition-re)
(org-element-footnote-definition-parser limit affiliated))
;; Horizontal Rule.
((looking-at-p "[ \t]*-\\{5,\\}[ \t]*$")
(org-element-horizontal-rule-parser limit affiliated))
;; Diary Sexp.
((looking-at-p "%%(")
(org-element-diary-sexp-parser limit affiliated))
;; Table.
((or (looking-at-p "[ \t]*|")
;; There is no strict definition of a table.el
;; table. Try to prevent false positive while being
;; quick.
(let ((rule-regexp
(rx (zero-or-more (any " \t"))
"+"
(one-or-more (one-or-more "-") "+")
(zero-or-more (any " \t"))
eol))
(non-table.el-line
(rx bol
(zero-or-more (any " \t"))
(or eol (not (any "+| \t")))))
(next (line-beginning-position 2)))
;; Start with a full rule.
(and
(looking-at-p rule-regexp)
(< next limit) ;no room for a table.el table
(save-excursion
(end-of-line)
(cond
;; Must end with a full rule.
((not (re-search-forward non-table.el-line limit 'move))
(if (bolp) (forward-line -1) (beginning-of-line))
(looking-at-p rule-regexp))
;; Ignore pseudo-tables with a single
;; rule.
((= next (line-beginning-position))
nil)
;; Must end with a full rule.
(t
(forward-line -1)
(looking-at-p rule-regexp)))))))
(org-element-table-parser limit affiliated))
;; List.
((looking-at-p (org-item-re))
(org-element-plain-list-parser
limit affiliated
(or structure (org-element--list-struct limit))))
;; Default element: Paragraph.
(t (org-element-paragraph-parser limit affiliated)))))))
(when result
(org-element-put-property result :mode mode)
(org-element-put-property result :granularity granularity))
result)))
;; Most elements can have affiliated keywords. When looking for an
@ -4824,20 +4793,7 @@ Elements are accumulated into ACC."
(when (and (eolp) (not (eobp))) (forward-char)))
;; Find current element's type and parse it accordingly to
;; its category.
(let* ((element (org-element-copy
;; `org-element--current-element' may return cached
;; elements. Below code reassigns
;; `:parent' property of the element and
;; may interfere with cache
;; synchronization if parent element is not
;; yet in cache. Moreover, the returned
;; structure may be altered by caller code
;; arbitrarily. Hence, we return a copy of
;; the potentially cached element to make
;; potential modifications safe for element
;; cache.
(org-element--current-element
end granularity mode structure)))
(let* ((element (org-element--current-element end granularity mode structure))
(type (org-element-type element))
(cbeg (org-element-property :contents-begin element)))
(goto-char (org-element-property :end element))
@ -6577,10 +6533,9 @@ If you observe Emacs hangs frequently, please report this to Org mode mailing li
(unless (save-excursion
(org-skip-whitespace)
(eobp))
(org-element-with-disabled-cache
(setq element (org-element--current-element
end 'element mode
(org-element-property :structure parent)))))
(setq element (org-element--current-element
end 'element mode
(org-element-property :structure parent))))
;; Make sure that we return referenced element in cache
;; that can be altered directly.
(if element