Function: org-element--parse-to

org-element--parse-to is a byte-compiled function defined in org-element.el.gz.

Signature

(org-element--parse-to POS &optional SYNCP TIME-LIMIT)

Documentation

Parse elements in current section, down to POS.

Start parsing from the closest between the last known element in cache or headline above. Return the smallest element containing POS.

When optional argument SYNCP is non-nil, return the parent of the element containing POS instead. In that case, it is also possible to provide TIME-LIMIT, which is a time value specifying when the parsing should stop. The function throws org-element--cache-interrupt if the process stopped before finding the expected result.

Source Code

;; Defined in /usr/src/emacs/lisp/org/org-element.el.gz
(defun org-element--parse-to (pos &optional syncp time-limit)
  "Parse elements in current section, down to POS.

Start parsing from the closest between the last known element in
cache or headline above.  Return the smallest element containing
POS.

When optional argument SYNCP is non-nil, return the parent of the
element containing POS instead.  In that case, it is also
possible to provide TIME-LIMIT, which is a time value specifying
when the parsing should stop.  The function throws
`org-element--cache-interrupt' if the process stopped before finding
the expected result."
  (catch 'exit
    (org-with-base-buffer nil
      (org-with-wide-buffer
       (goto-char pos)
       (save-excursion
         (forward-line 1)
         (skip-chars-backward " \r\t\n")
         ;; Within blank lines at the beginning of buffer, return nil.
         (when (bobp) (throw 'exit nil)))
       (let* ((cached (and (org-element--cache-active-p)
			   (org-element--cache-find pos nil)))
              (mode (org-element-property :mode cached))
              element next)
         (cond
          ;; Nothing in cache before point: start parsing from first
          ;; element in buffer down to POS or from the beginning of the
          ;; file.
          ((and (not cached) (org-element--cache-active-p))
           (setq element (org-element-org-data-parser))
           (unless (org-element-begin element)
             (org-element--cache-warn "Error parsing org-data. Got %S\nPlease report to Org mode mailing list (M-x org-submit-bug-report)." element))
           (org-element--cache-log-message
            "Nothing in cache. Adding org-data: %S"
            (org-element--format-element element))
           (org-element--cache-put element)
           (goto-char (org-element-contents-begin element))
	   (setq mode 'org-data))
          ;; Nothing in cache before point because cache is not active.
          ;; Parse from previous heading to avoid re-parsing the whole
          ;; buffer above.  Arrange `:parent' to be calculated on demand.
          ((not cached)
           (forward-line 1) ; ensure the end of current heading.
           (if (re-search-backward
                (org-get-limited-outline-regexp t)
                nil 'move)
               (progn
                 (setq element (org-element-headline-parser nil 'fast))
                 (org-element-put-property
                  element :parent
                  org-element--headline-parent-deferred)
                 (setq mode 'planning)
                 (forward-line))
             (setq element (org-element-org-data-parser))
	     (setq mode 'org-data))
           (org-skip-whitespace)
           (forward-line 0))
          ;; Check if CACHED or any of its ancestors contain point.
          ;;
          ;; If there is such an element, we inspect it in order to know
          ;; if we return it or if we need to parse its contents.
          ;; Otherwise, we just start parsing from location, which is
          ;; right after the top-most element containing CACHED but
          ;; still before POS.
          ;;
          ;; As a special case, if POS is at the end of the buffer, we
          ;; want to return the innermost element ending there.
          ;;
          ;; Also, if we find an ancestor and discover that we need to
          ;; parse its contents, make sure we don't start from
          ;; `:contents-begin', as we would otherwise go past CACHED
          ;; again.  Instead, in that situation, we will resume parsing
          ;; from NEXT, which is located after CACHED or its higher
          ;; ancestor not containing point.
          (t
           (let ((up cached)
                 (pos (if (= (point-max) pos) (1- pos) pos)))
             (while (and up (<= (org-element-end up) pos))
               (setq next (org-element-end up)
                     element up
                     mode (org-element--next-mode (org-element-property :mode element) (org-element-type element) nil)
                     ;; Cached elements cannot have deferred `:parent'.
                     up (org-element-property-raw :parent up)))
             (when next (goto-char next))
             (when up (setq element up)))))
         ;; Parse successively each element until we reach POS.
         (let ((end (or (org-element-end element) (point-max)))
	       (parent (org-element-property-raw :parent element)))
           (while t
	     (when (org-element--cache-interrupt-p time-limit)
               (throw 'org-element--cache-interrupt nil))
             (when (and inhibit-quit org-element--cache-interrupt-C-g quit-flag)
               (when quit-flag
                 (cl-incf org-element--cache-interrupt-C-g-count)
                 (setq quit-flag nil))
               (when (>= org-element--cache-interrupt-C-g-count
                         org-element--cache-interrupt-C-g-max-count)
                 (setq quit-flag t)
                 (setq org-element--cache-interrupt-C-g-count 0)
                 (org-element-cache-reset)
                 (error "org-element: Parsing aborted by user.  Cache has been cleared.
If you observe Emacs hangs frequently, please report this to Org mode mailing list (M-x org-submit-bug-report)"))
               (message (substitute-command-keys
                         "`org-element--parse-to': Suppressed `\\[keyboard-quit]'.  Press `\\[keyboard-quit]' %d more times to force interruption.")
                        (- org-element--cache-interrupt-C-g-max-count
                           org-element--cache-interrupt-C-g-count)))
	     (unless element
               ;; Do not try to parse within blank at EOB.
               (unless (save-excursion
                         (org-skip-whitespace)
                         (eobp))
                 (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
                   (setq element (or (org-element--cache-put element) element))
                 ;; Nothing to parse (i.e. empty file).
                 (throw 'exit parent))
               (unless (or parent (not (org-element--cache-active-p)))
                 (org-element--cache-warn
                  "Got empty parent while parsing. Please report it to Org mode mailing list (M-x org-submit-bug-report).\n Backtrace:\n%S"
                  (when (and (fboundp 'backtrace-get-frames)
                             (fboundp 'backtrace-to-string))
                    (backtrace-to-string (backtrace-get-frames 'backtrace))
                    (org-element-cache-reset)
                    (error "org-element--cache: Emergency exit"))))
	       (org-element-put-property element :parent parent))
	     (let ((elem-end (org-element-end element))
                   (type (org-element-type element)))
	       (cond
                ;; Skip any element ending before point.  Also skip
                ;; element ending at point (unless it is also the end of
                ;; buffer) since we're sure that another element begins
                ;; after it.
                ((and (<= elem-end pos) (/= (point-max) elem-end))
                 ;; Avoid parsing headline siblings above.
                 (goto-char elem-end)
                 (when (eq type 'headline)
                   (unless (when (and (/= 1 (org-element-property :true-level element))
                                      (re-search-forward
                                       (org-headline-re (1- (org-element-property :true-level element)))
                                       pos t))
                             (forward-line 0)
                             t)
                     ;; There are headings with lower level than
                     ;; ELEMENT between ELEM-END and POS.  Siblings
                     ;; may exist though.  Parse starting from the
                     ;; last sibling or from ELEM-END if there are
                     ;; no other siblings.
                     (goto-char pos)
                     (unless
                         (re-search-backward
                          (org-headline-re (org-element-property :true-level element))
                          elem-end t)
                       ;; Roll-back to normal parsing.
                       (goto-char elem-end))))
                 (setq mode (org-element--next-mode mode type nil)))
                ;; A non-greater element contains point: return it.
                ((not (memq type org-element-greater-elements))
                 (throw 'exit (if syncp parent element)))
                ;; Otherwise, we have to decide if ELEMENT really
                ;; contains POS.  In that case we start parsing from
                ;; contents' beginning.
                ;;
                ;; If POS is at contents' beginning but it is also at
                ;; the beginning of the first item in a list or a table.
                ;; In that case, we need to create an anchor for that
                ;; list or table, so return it.
                ;;
                ;; Also, if POS is at the end of the buffer, no element
                ;; can start after it, but more than one may end there.
                ;; Arbitrarily, we choose to return the innermost of
                ;; such elements.
                ((let ((cbeg (org-element-contents-begin element))
		       (cend (org-element-contents-end element)))
                   (when (and cbeg cend
			      (or (< cbeg pos)
                                  (and (= cbeg pos)
				       (not (memq type '(plain-list table)))))
			      (or (> cend pos)
                                  ;; When we are at cend or within blank
                                  ;; lines after, it is a special case:
                                  ;; 1. At the end of buffer we return
                                  ;; the innermost element.
                                  (= pos cend (point-max))
                                  ;; 2. At cend of element with return
                                  ;; that element (thus, no need to
                                  ;; parse inside).
                                  nil))
		     (goto-char (or next cbeg))
		     (setq mode (if next mode (org-element--next-mode mode type t))
                           next nil
                           parent element
                           end (org-element-contents-end element)))))
                ;; Otherwise, return ELEMENT as it is the smallest
                ;; element containing POS.
                (t (throw 'exit (if syncp parent element)))))
	     (setq element nil))))))))