Function: org-element-context

org-element-context is an autoloaded and byte-compiled function defined in org-element.el.gz.

Signature

(org-element-context &optional ELEMENT)

Documentation

Return smallest element or object around point.

Return value is a list like (TYPE PROPS) where TYPE is the type of the element or object and PROPS a plist of properties associated to it.

Possible types are defined in org-element-all-elements and org-element-all-objects. Properties depend on element or object type, but always include :begin, :end, :parent and
:post-blank.

As a special case, if point is right after an object and not at the beginning of any other object, return that object.

Optional argument ELEMENT, when non-nil, is the closest element containing point, as returned by org-element-at-point. Providing it allows for quicker computation.

Source Code

;; Defined in /usr/src/emacs/lisp/org/org-element.el.gz
;;;###autoload
(defun org-element-context (&optional element)
  "Return smallest element or object around point.

Return value is a list like (TYPE PROPS) where TYPE is the type
of the element or object and PROPS a plist of properties
associated to it.

Possible types are defined in `org-element-all-elements' and
`org-element-all-objects'.  Properties depend on element or
object type, but always include `:begin', `:end', `:parent' and
`:post-blank'.

As a special case, if point is right after an object and not at
the beginning of any other object, return that object.

Optional argument ELEMENT, when non-nil, is the closest element
containing point, as returned by `org-element-at-point'.
Providing it allows for quicker computation."
  (save-match-data
    (catch 'objects-forbidden
      (org-with-wide-buffer
       (let* ((pos (point))
	      (element (or element (org-element-at-point)))
	      (type (org-element-type element))
	      (post (org-element-property :post-affiliated element)))
         ;; If point is inside an element containing objects or
         ;; a secondary string, narrow buffer to the container and
         ;; proceed with parsing.  Otherwise, return ELEMENT.
         (cond
	  ;; At a parsed affiliated keyword, check if we're inside main
	  ;; or dual value.
	  ((and post (< pos post))
	   (beginning-of-line)
	   (let ((case-fold-search t)) (looking-at org-element--affiliated-re))
	   (cond
	    ((not (member-ignore-case (match-string 1)
				    org-element-parsed-keywords))
	     (throw 'objects-forbidden element))
	    ((< (match-end 0) pos)
	     (narrow-to-region (match-end 0) (line-end-position)))
	    ((and (match-beginning 2)
		  (>= pos (match-beginning 2))
		  (< pos (match-end 2)))
	     (narrow-to-region (match-beginning 2) (match-end 2)))
	    (t (throw 'objects-forbidden element)))
	   ;; Also change type to retrieve correct restrictions.
	   (setq type 'keyword))
	  ;; At an item, objects can only be located within tag, if any.
	  ((eq type 'item)
	   (let ((tag (org-element-property :tag element)))
	     (if (or (not tag) (/= (line-beginning-position) post))
                 (throw 'objects-forbidden element)
	       (beginning-of-line)
	       (search-forward tag (line-end-position))
	       (goto-char (match-beginning 0))
	       (if (and (>= pos (point)) (< pos (match-end 0)))
		   (narrow-to-region (point) (match-end 0))
                 (throw 'objects-forbidden element)))))
	  ;; At an headline or inlinetask, objects are in title.
	  ((memq type '(headline inlinetask))
	   (let ((case-fold-search nil))
	     (goto-char (org-element-property :begin element))
	     (looking-at org-complex-heading-regexp)
	     (let ((end (match-end 4)))
	       (if (not end) (throw 'objects-forbidden element)
                 (goto-char (match-beginning 4))
                 (when (looking-at org-element-comment-string)
		   (goto-char (match-end 0)))
                 (if (>= (point) end) (throw 'objects-forbidden element)
		   (narrow-to-region (point) end))))))
	  ;; At a paragraph, a table-row or a verse block, objects are
	  ;; located within their contents.
	  ((memq type '(paragraph table-row verse-block))
	   (let ((cbeg (org-element-property :contents-begin element))
                 (cend (org-element-property :contents-end element)))
	     ;; CBEG is nil for table rules.
	     (if (and cbeg cend (>= pos cbeg)
		      (or (< pos cend) (and (= pos cend) (eobp))))
                 (narrow-to-region cbeg cend)
	       (throw 'objects-forbidden element))))
	  (t (throw 'objects-forbidden element)))
         (goto-char (point-min))
         (let ((restriction (org-element-restriction type))
	       (parent element)
	       last)
	   (catch 'exit
	     (while t
	       (let ((next (org-element--object-lex restriction)))
                 (when next (org-element-put-property next :parent parent))
                 ;; Process NEXT, if any, in order to know if we need to
                 ;; skip it, return it or move into it.
                 (if (or (not next) (> (org-element-property :begin next) pos))
		     (throw 'exit (or last parent))
		   (let ((end (org-element-property :end next))
                         (cbeg (org-element-property :contents-begin next))
                         (cend (org-element-property :contents-end next)))
		     (cond
		      ;; Skip objects ending before point.  Also skip
		      ;; objects ending at point unless it is also the
		      ;; end of buffer, since we want to return the
		      ;; innermost object.
		      ((and (<= end pos) (/= (point-max) end))
		       (goto-char end)
		       ;; For convenience, when object ends at POS,
		       ;; without any space, store it in LAST, as we
		       ;; will return it if no object starts here.
		       (when (and (= end pos)
				  (not (memq (char-before) '(?\s ?\t))))
                         (setq last next)))
		      ;; If POS is within a container object, move into
		      ;; that object.
		      ((and cbeg cend
			    (>= pos cbeg)
			    (or (< pos cend)
                                ;; At contents' end, if there is no
                                ;; space before point, also move into
                                ;; object, for consistency with
                                ;; convenience feature above.
                                (and (= pos cend)
				     (or (= (point-max) pos)
                                         (not (memq (char-before pos)
                                                    '(?\s ?\t)))))))
		       (goto-char cbeg)
		       (narrow-to-region (point) cend)
		       (setq parent next)
		       (setq restriction (org-element-restriction next)))
		      ;; Otherwise, return NEXT.
		      (t (throw 'exit next))))))))))))))