diff options
author | Rasmus <rasmus@gmx.us> | 2017-08-29 10:07:08 +0200 |
---|---|---|
committer | Rasmus <rasmus@gmx.us> | 2017-08-29 10:13:31 +0200 |
commit | 3ad8ca429bac5e1354881cf4411d6f41dab36b44 (patch) | |
tree | 41d8dc789a212dc3b1e09f402714b09dc1462fc5 /lisp/org/org.el | |
parent | c1854b1d31e1b0a3a9e91ef41110a5fa77bedb31 (diff) | |
download | emacs-3ad8ca429bac5e1354881cf4411d6f41dab36b44.tar.gz |
Update Org to v9.0.10
Please see etc/ORG-NEWS for major changes. Note, this is a bugfix
release.
Diffstat (limited to 'lisp/org/org.el')
-rw-r--r-- | lisp/org/org.el | 524 |
1 files changed, 253 insertions, 271 deletions
diff --git a/lisp/org/org.el b/lisp/org/org.el index 5d10eed1511..87758fdfdd0 100644 --- a/lisp/org/org.el +++ b/lisp/org/org.el @@ -128,6 +128,7 @@ Stars are put in group 1 and the trimmed body in group 2.") (declare-function org-clock-timestamps-down "org-clock" (&optional n)) (declare-function org-clock-timestamps-up "org-clock" (&optional n)) (declare-function org-clock-update-time-maybe "org-clock" ()) +(declare-function org-clocking-buffer "org-clock" ()) (declare-function org-clocktable-shift "org-clock" (dir n)) (declare-function org-element-at-point "org-element" ()) (declare-function org-element-cache-refresh "org-element" (pos)) @@ -1119,8 +1120,8 @@ Or return the original if not disputed." (defcustom org-ellipsis nil "The ellipsis to use in the Org mode outline. -When nil, just use the standard three dots. -When a string, use that string instead. +When nil, just use the standard three dots. When a non-empty string, +use that string instead. The change affects only Org mode (which will then use its own display table). Changing this requires executing `\\[org-mode]' in a buffer to become @@ -1128,10 +1129,10 @@ effective." :group 'org-startup :type '(choice (const :tag "Default" nil) (string :tag "String" :value "...#")) - :safe #'string-or-null-p) + :safe (lambda (v) (and (string-or-null-p v) (not (equal "" v))))) (defvar org-display-table nil - "The display table for org-mode, in case `org-ellipsis' is non-nil.") + "The display table for Org mode, in case `org-ellipsis' is non-nil.") (defgroup org-keywords nil "Keywords in Org mode." @@ -3573,8 +3574,10 @@ See also `org-tag-persistent-alist' to sidestep this behavior." :group 'org-tags :type '(repeat (choice - (cons (string :tag "Tag name") - (character :tag "Access char")) + (cons :tag "Tag with key" + (string :tag "Tag name") + (character :tag "Access char")) + (list :tag "Tag" (string :tag "Tag name")) (const :tag "Start radio group" (:startgroup)) (const :tag "Start tag group, non distinct" (:startgrouptag)) (const :tag "Group tags delimiter" (:grouptags)) @@ -3606,8 +3609,10 @@ on a per-file basis, insert anywhere in the file: :group 'org-tags :type '(repeat (choice - (cons (string :tag "Tag name") + (cons :tag "Tag with key" + (string :tag "Tag name") (character :tag "Access char")) + (list :tag "Tag" (string :tag "Tag name")) (const :tag "Start radio group" (:startgroup)) (const :tag "Start tag group, non distinct" (:startgrouptag)) (const :tag "Group tags delimiter" (:grouptags)) @@ -4852,7 +4857,9 @@ Otherwise, these types are allowed: :group 'org-sparse-trees) (defun org-cycle-hide-archived-subtrees (state) - "Re-hide all archived subtrees after a visibility state change." + "Re-hide all archived subtrees after a visibility state change. +STATE should be one of the symbols listed in the docstring of +`org-cycle-hook'." (when (and (not org-cycle-open-archived-trees) (not (memq state '(overview folded)))) (save-excursion @@ -5582,15 +5589,13 @@ The following commands are available: (setq-local outline-regexp org-outline-regexp) (setq-local outline-level 'org-outline-level) (setq bidi-paragraph-direction 'left-to-right) - (when (and org-ellipsis - (fboundp 'set-display-table-slot) (boundp 'buffer-display-table) - (fboundp 'make-glyph-code)) + (when (and (stringp org-ellipsis) (not (equal "" org-ellipsis))) (unless org-display-table (setq org-display-table (make-display-table))) (set-display-table-slot org-display-table 4 (vconcat (mapcar (lambda (c) (make-glyph-code c 'org-ellipsis)) - (if (stringp org-ellipsis) org-ellipsis "...")))) + org-ellipsis))) (setq buffer-display-table org-display-table)) (org-set-regexps-and-options) (org-set-font-lock-defaults) @@ -6210,9 +6215,10 @@ by a #." 'keymap org-mouse-map)) (org-rear-nonsticky-at (match-end 0)) (when org-display-custom-times - (if (match-end 3) - (org-display-custom-time (match-beginning 3) (match-end 3)) - (org-display-custom-time (match-beginning 1) (match-end 1)))) + ;; If it's a date range, activate custom time for second date. + (when (match-end 3) + (org-display-custom-time (match-beginning 3) (match-end 3))) + (org-display-custom-time (match-beginning 1) (match-end 1))) t)) (defvar-local org-target-link-regexp nil @@ -7318,12 +7324,13 @@ open and agenda-wise Org files." (defun org-cycle-hide-drawers (state &optional exceptions) "Re-hide all drawers after a visibility state change. -When non-nil, optional argument EXCEPTIONS is a list of strings -specifying which drawers should not be hidden." +STATE should be one of the symbols listed in the docstring of +`org-cycle-hook'. When non-nil, optional argument EXCEPTIONS is +a list of strings specifying which drawers should not be hidden." (when (and (derived-mode-p 'org-mode) (not (memq state '(overview folded contents)))) (save-excursion - (let* ((globalp (memq state '(contents all))) + (let* ((globalp (eq state 'all)) (beg (if globalp (point-min) (point))) (end (if globalp (point-max) (if (eq state 'children) @@ -9049,14 +9056,6 @@ A non-nil value for INTERACTIVE? is used to signal that this function is being called interactively." (interactive (list current-prefix-arg nil nil nil nil t)) (let ((case-func (if with-case 'identity 'downcase)) - (cmstr - ;; The clock marker is lost when using `sort-subr', let's - ;; store the clocking string. - (when (equal (marker-buffer org-clock-marker) (current-buffer)) - (save-excursion - (goto-char org-clock-marker) - (buffer-substring-no-properties (line-beginning-position) - (point))))) start beg end stars re re2 txt what tmp) ;; Find beginning and end of region to sort @@ -9138,9 +9137,20 @@ function is being called interactively." (save-restriction (narrow-to-region start end) - (let ((dcst (downcase sorting-type)) + (let ((restore-clock? + ;; The clock marker is lost when using `sort-subr'; mark + ;; the clock with temporary `:org-clock-marker-backup' + ;; text property. + (when (and (eq (org-clocking-buffer) (current-buffer)) + (<= start (marker-position org-clock-marker)) + (>= end (marker-position org-clock-marker))) + (org-with-silent-modifications + (put-text-property (1- org-clock-marker) org-clock-marker + :org-clock-marker-backup t)) + t)) + (dcst (downcase sorting-type)) (case-fold-search nil) - (now (current-time))) + (now (current-time))) (sort-subr (/= dcst sorting-type) ;; This function moves to the beginning character of the "record" to @@ -9222,14 +9232,14 @@ function is being called interactively." (concat "Function for comparing keys " "(empty for default `sort-subr' predicate): ") 'allow-empty)))) - ((member dcst '(?p ?t ?s ?d ?c ?k)) '<))))) + ((member dcst '(?p ?t ?s ?d ?c ?k)) '<))) + (when restore-clock? + (move-marker org-clock-marker + (1+ (next-single-property-change + start :org-clock-marker-backup))) + (remove-text-properties (1- org-clock-marker) org-clock-marker + '(:org-clock-marker-backup t))))) (run-hooks 'org-after-sorting-entries-or-items-hook) - ;; Reset the clock marker if needed - (when cmstr - (save-excursion - (goto-char start) - (search-forward cmstr nil t) - (move-marker org-clock-marker (point)))) (message "Sorting entries...done"))) ;;; The orgstruct minor mode @@ -9590,42 +9600,6 @@ Possible values in the list of contexts are `table', `headline', and `item'." (org-in-item-p))) (goto-char pos)))) -(defconst org-unique-local-variables - '(org-element--cache - org-element--cache-objects - org-element--cache-sync-keys - org-element--cache-sync-requests - org-element--cache-sync-timer) - "List of local variables that cannot be transferred to another buffer.") - -(defun org-get-local-variables () - "Return a list of all local variables in an Org mode buffer." - (delq nil - (mapcar - (lambda (x) - (let* ((binding (if (symbolp x) (list x) (list (car x) (cdr x)))) - (name (car binding))) - (and (not (get name 'org-state)) - (not (memq name org-unique-local-variables)) - (string-match-p - "\\`\\(org-\\|orgtbl-\\|outline-\\|comment-\\|paragraph-\\|\ -auto-fill\\|normal-auto-fill\\|fill-paragraph\\|indent-\\)" - (symbol-name name)) - binding))) - (with-temp-buffer - (org-mode) - (buffer-local-variables))))) - -(defun org-clone-local-variables (from-buffer &optional regexp) - "Clone local variables from FROM-BUFFER. -Optional argument REGEXP selects variables to clone." - (dolist (pair (buffer-local-variables from-buffer)) - (pcase pair - (`(,name . ,value) ;ignore unbound variables - (when (and (not (memq name org-unique-local-variables)) - (or (null regexp) (string-match-p regexp (symbol-name name)))) - (set (make-local-variable name) value)))))) - ;;;###autoload (defun org-run-like-in-org-mode (cmd) "Run a command, pretending that the current buffer is in Org mode. @@ -10780,9 +10754,10 @@ When optional argument REFERENCE-BUFFER is non-nil, it should specify a buffer from where the link search should happen. This is used internally by `org-open-link-from-string'. -On top of syntactically correct links, this function will open -the link at point in comments or comment blocks and the first -link in a property drawer line." +On top of syntactically correct links, this function will also +try to open links and time-stamps in comments, example +blocks... i.e., whenever point is on something looking like +a timestamp or a link." (interactive "P") ;; On a code block, open block's results. (unless (call-interactively 'org-babel-open-src-block-result) @@ -10795,38 +10770,51 @@ link in a property drawer line." ;; the closest one. (org-element-lineage (org-element-context) - '(clock comment comment-block footnote-definition - footnote-reference headline inlinetask keyword link - node-property timestamp) + '(clock footnote-definition footnote-reference headline + inlinetask link timestamp) t)) (type (org-element-type context)) (value (org-element-property :value context))) (cond - ((not context) (user-error "No link found")) - ;; Exception: open timestamps and links in properties - ;; drawers, keywords and comments. - ((memq type '(comment comment-block keyword node-property)) - (call-interactively #'org-open-at-point-global)) ;; On a headline or an inlinetask, but not on a timestamp, - ;; a link, a footnote reference or on tags. - ((and (memq type '(headline inlinetask)) - ;; Not on tags. - (let ((case-fold-search nil)) - (save-excursion - (beginning-of-line) - (looking-at org-complex-heading-regexp)) - (or (not (match-beginning 5)) - (< (point) (match-beginning 5))))) - (let* ((data (org-offer-links-in-entry (current-buffer) (point) arg)) - (links (car data)) - (links-end (cdr data))) - (if links - (dolist (link (if (stringp links) (list links) links)) - (search-forward link nil links-end) - (goto-char (match-beginning 0)) - (org-open-at-point)) - (require 'org-attach) - (org-attach-reveal 'if-exists)))) + ;; a link, a footnote reference. + ((memq type '(headline inlinetask)) + (org-match-line org-complex-heading-regexp) + (if (and (match-beginning 5) + (>= (point) (match-beginning 5)) + (< (point) (match-end 5))) + ;; On tags. + (org-tags-view arg (substring (match-string 5) 0 -1)) + ;; Not on tags. + (pcase (org-offer-links-in-entry (current-buffer) (point) arg) + (`(nil . ,_) + (require 'org-attach) + (org-attach-reveal 'if-exists)) + (`(,links . ,links-end) + (dolist (link (if (stringp links) (list links) links)) + (search-forward link nil links-end) + (goto-char (match-beginning 0)) + (org-open-at-point)))))) + ;; On a footnote reference or at definition's label. + ((or (eq type 'footnote-reference) + (and (eq type 'footnote-definition) + (save-excursion + ;; Do not validate action when point is on the + ;; spaces right after the footnote label, in + ;; order to be on par with behaviour on links. + (skip-chars-forward " \t") + (let ((begin + (org-element-property :contents-begin context))) + (if begin (< (point) begin) + (= (org-element-property :post-affiliated context) + (line-beginning-position))))))) + (org-footnote-action)) + ;; No valid context. Ignore catch-all types like `headline'. + ;; If point is on something looking like a link or + ;; a time-stamp, try opening it. It may be useful in + ;; comments, example blocks... + ((memq type '(footnote-definition headline inlinetask nil)) + (call-interactively #'org-open-at-point-global)) ;; On a clock line, make sure point is on the timestamp ;; before opening it. ((and (eq type 'clock) @@ -10842,14 +10830,6 @@ link in a property drawer line." (point))) (user-error "No link found")) ((eq type 'timestamp) (org-follow-timestamp-link)) - ;; On tags within a headline or an inlinetask. - ((and (memq type '(headline inlinetask)) - (let ((case-fold-search nil)) - (save-excursion (beginning-of-line) - (looking-at org-complex-heading-regexp)) - (and (match-beginning 5) - (>= (point) (match-beginning 5))))) - (org-tags-view arg (substring (match-string 5) 0 -1))) ((eq type 'link) ;; When link is located within the description of another ;; link (e.g., an inline image), always open the parent @@ -10919,20 +10899,6 @@ link in a property drawer line." (widen)) (goto-char destination)))) (t (browse-url-at-point)))))) - ;; On a footnote reference or at a footnote definition's label. - ((or (eq type 'footnote-reference) - (and (eq type 'footnote-definition) - (save-excursion - ;; Do not validate action when point is on the - ;; spaces right after the footnote label, in - ;; order to be on par with behaviour on links. - (skip-chars-forward " \t") - (let ((begin - (org-element-property :contents-begin context))) - (if begin (< (point) begin) - (= (org-element-property :post-affiliated context) - (line-beginning-position))))))) - (org-footnote-action)) (t (user-error "No link found"))))) (run-hook-with-args 'org-follow-link-hook))) @@ -11985,7 +11951,9 @@ prefix argument (`C-u C-u C-u C-c C-w')." (if (and arg (not (equal arg 3))) (progn (pop-to-buffer-same-window nbuf) - (goto-char pos) + (goto-char (cond (pos) + ((org-notes-order-reversed-p) (point-min)) + (t (point-max)))) (org-show-context 'org-goto)) (if regionp (progn @@ -12682,7 +12650,7 @@ When called through ELisp, arg is also interpreted in the following way: (replace-match next t t) (cond ((equal this org-state) (message "TODO state was already %s" (org-trim next))) - ((pos-visible-in-window-p hl-pos) + ((not (pos-visible-in-window-p hl-pos)) (message "TODO state changed to %s" (org-trim next)))) (unless head (setq head (org-get-todo-sequence-head org-state) @@ -13741,7 +13709,7 @@ EXTRA is additional text that will be inserted into the notes buffer." (org-switch-to-buffer-other-window "*Org Note*") (erase-buffer) (if (memq org-log-note-how '(time state)) - (let (current-prefix-arg) (org-store-log-note)) + (org-store-log-note) (let ((org-inhibit-startup t)) (org-mode)) (insert (format "# Insert note for %s. # Finish with C-c C-c, or cancel with C-c C-k.\n\n" @@ -13818,7 +13786,7 @@ EXTRA is additional text that will be inserted into the notes buffer." org-log-note-previous-state))))))) (when lines (setq note (concat note " \\\\"))) (push note lines)) - (when (and lines (not (or current-prefix-arg org-note-abort))) + (when (and lines (not org-note-abort)) (with-current-buffer (marker-buffer org-log-note-marker) (org-with-wide-buffer ;; Find location for the new note. @@ -14811,7 +14779,7 @@ it as a time string and apply `float-time' to it. If S is nil, just return 0." ((numberp s) s) ((stringp s) (condition-case nil - (float-time (apply 'encode-time (org-parse-time-string s))) + (float-time (apply #'encode-time (org-parse-time-string s nil t))) (error 0.))) (t 0.))) @@ -19030,9 +18998,7 @@ looks only before point, not after." (catch 'exit (let ((pos (point)) (dodollar (member "$" (plist-get org-format-latex-options :matchers))) - (lim (progn - (re-search-backward (concat "^\\(" paragraph-start "\\)") nil t) - (point))) + (lim (save-excursion (org-backward-paragraph) (point))) dd-on str (start 0) m re) (goto-char pos) (when dodollar @@ -19466,7 +19432,7 @@ a HTML file." (insert latex-header) (insert "\n\\begin{document}\n" string "\n\\end{document}\n"))) - (let* ((err-msg (format "Please adjust '%s' part of \ + (let* ((err-msg (format "Please adjust `%s' part of \ `org-preview-latex-process-alist'." processing-type)) (image-input-file @@ -20156,6 +20122,8 @@ overwritten, and the table is not marked as requiring realignment." (call-interactively 'org-self-insert-command))))) ((and (org-at-table-p) + (eq N 1) + (not (org-region-active-p)) (progn ;; Check if we blank the field, and if that triggers align. (and (featurep 'org-table) org-table-auto-blank-field @@ -20169,7 +20137,6 @@ overwritten, and the table is not marked as requiring realignment." ;; width. (org-table-blank-field))) t) - (eq N 1) (looking-at "[^|\n]* \\( \\)|")) ;; There is room for insertion without re-aligning the table. (delete-region (match-beginning 1) (match-end 1)) @@ -20198,14 +20165,24 @@ The detailed reaction depends on the user option `org-catch-invisible-edits'." (or (not (boundp 'visible-mode)) (not visible-mode)) (or (get-char-property (point) 'invisible) (get-char-property (max (point-min) (1- (point))) 'invisible))) - ;; OK, we need to take a closer look - (let* ((invisible-at-point (get-char-property (point) 'invisible)) - (invisible-before-point (unless (bobp) (get-char-property - (1- (point)) 'invisible))) + ;; OK, we need to take a closer look. Do not consider + ;; invisibility obtained through text properties (e.g., link + ;; fontification), as it cannot be toggled. + (let* ((invisible-at-point + (pcase (get-char-property-and-overlay (point) 'invisible) + (`(,_ . ,(and (pred overlayp) o)) o))) + ;; Assume that point cannot land in the middle of an + ;; overlay, or between two overlays. + (invisible-before-point + (and (not invisible-at-point) + (not (bobp)) + (pcase (get-char-property-and-overlay (1- (point)) 'invisible) + (`(,_ . ,(and (pred overlayp) o)) o)))) (border-and-ok-direction (or - ;; Check if we are acting predictably before invisible text - (and invisible-at-point (not invisible-before-point) + ;; Check if we are acting predictably before invisible + ;; text. + (and invisible-at-point (memq kind '(insert delete-backward))) ;; Check if we are acting predictably after invisible text ;; This works not well, and I have turned it off. It seems @@ -20213,8 +20190,7 @@ The detailed reaction depends on the user option `org-catch-invisible-edits'." ;; (and (not invisible-at-point) invisible-before-point ;; (memq kind '(insert delete))) ))) - (when (or (memq invisible-at-point '(outline org-hide-block t)) - (memq invisible-before-point '(outline org-hide-block t))) + (when (or invisible-at-point invisible-before-point) (when (eq org-catch-invisible-edits 'error) (user-error "Editing in invisible areas is prohibited, make them visible first")) (if (and org-custom-properties-overlays @@ -20223,9 +20199,17 @@ The detailed reaction depends on the user option `org-catch-invisible-edits'." ;; Make the area visible (save-excursion (when invisible-before-point - (goto-char (previous-single-char-property-change - (point) 'invisible))) - (outline-show-subtree)) + (goto-char + (previous-single-char-property-change (point) 'invisible))) + ;; Remove whatever overlay is currently making yet-to-be + ;; edited text invisible. Also remove nested invisibility + ;; related overlays. + (delete-overlay (or invisible-at-point invisible-before-point)) + (let ((origin (if invisible-at-point (point) (1- (point))))) + (while (pcase (get-char-property-and-overlay origin 'invisible) + (`(,_ . ,(and (pred overlayp) o)) + (delete-overlay o) + t))))) (cond ((eq org-catch-invisible-edits 'show) ;; That's it, we do the edit after showing @@ -20914,16 +20898,14 @@ this numeric value." (defun org-copy-visible (beg end) "Copy the visible parts of the region." (interactive "r") - (let (snippets s) - (save-excursion - (save-restriction - (narrow-to-region beg end) - (setq s (goto-char (point-min))) - (while (not (= (point) (point-max))) - (goto-char (org-find-invisible)) - (push (buffer-substring s (point)) snippets) - (setq s (goto-char (org-find-visible)))))) - (kill-new (apply 'concat (nreverse snippets))))) + (let ((result "")) + (while (/= beg end) + (when (get-char-property beg 'invisible) + (setq beg (next-single-char-property-change beg 'invisible nil end))) + (let ((next (next-single-char-property-change beg 'invisible nil end))) + (setq result (concat result (buffer-substring beg next))) + (setq beg next))) + (kill-new result))) (defun org-copy-special () "Copy region in table or copy current subtree. @@ -24416,74 +24398,74 @@ item, etc. It also provides some special moves for convenience: - On a table or a property drawer, jump after it. - On a verse or source block, stop after blank lines." (interactive) - (when (eobp) (user-error "Cannot move further down")) - (let* ((deactivate-mark nil) - (element (org-element-at-point)) - (type (org-element-type element)) - (post-affiliated (org-element-property :post-affiliated element)) - (contents-begin (org-element-property :contents-begin element)) - (contents-end (org-element-property :contents-end element)) - (end (let ((end (org-element-property :end element)) (parent element)) - (while (and (setq parent (org-element-property :parent parent)) - (= (org-element-property :contents-end parent) end)) - (setq end (org-element-property :end parent))) - end))) - (cond ((not element) - (skip-chars-forward " \r\t\n") - (or (eobp) (beginning-of-line))) - ;; On affiliated keywords, move to element's beginning. - ((< (point) post-affiliated) - (goto-char post-affiliated)) - ;; At a table row, move to the end of the table. Similarly, - ;; at a node property, move to the end of the property - ;; drawer. - ((memq type '(node-property table-row)) - (goto-char (org-element-property - :end (org-element-property :parent element)))) - ((memq type '(property-drawer table)) (goto-char end)) - ;; Consider blank lines as separators in verse and source - ;; blocks to ease editing. - ((memq type '(src-block verse-block)) - (when (eq type 'src-block) - (setq contents-end - (save-excursion (goto-char end) - (skip-chars-backward " \r\t\n") - (line-beginning-position)))) - (beginning-of-line) - (when (looking-at "[ \t]*$") (skip-chars-forward " \r\t\n")) - (if (not (re-search-forward "^[ \t]*$" contents-end t)) - (goto-char end) - (skip-chars-forward " \r\t\n") - (if (= (point) contents-end) (goto-char end) - (beginning-of-line)))) - ;; With no contents, just skip element. - ((not contents-begin) (goto-char end)) - ;; If contents are invisible, skip the element altogether. - ((org-invisible-p (line-end-position)) - (cl-case type - (headline - (org-with-limited-levels (outline-next-visible-heading 1))) - ;; At a plain list, make sure we move to the next item - ;; instead of skipping the whole list. - (plain-list (forward-char) - (org-forward-paragraph)) - (otherwise (goto-char end)))) - ((>= (point) contents-end) (goto-char end)) - ((>= (point) contents-begin) - ;; This can only happen on paragraphs and plain lists. - (cl-case type - (paragraph (goto-char end)) - ;; At a plain list, try to move to second element in - ;; first item, if possible. - (plain-list (end-of-line) - (org-forward-paragraph)))) - ;; When contents start on the middle of a line (e.g. in - ;; items and footnote definitions), try to reach first - ;; element starting after current line. - ((> (line-end-position) contents-begin) - (end-of-line) - (org-forward-paragraph)) - (t (goto-char contents-begin))))) + (unless (eobp) + (let* ((deactivate-mark nil) + (element (org-element-at-point)) + (type (org-element-type element)) + (post-affiliated (org-element-property :post-affiliated element)) + (contents-begin (org-element-property :contents-begin element)) + (contents-end (org-element-property :contents-end element)) + (end (let ((end (org-element-property :end element)) (parent element)) + (while (and (setq parent (org-element-property :parent parent)) + (= (org-element-property :contents-end parent) end)) + (setq end (org-element-property :end parent))) + end))) + (cond ((not element) + (skip-chars-forward " \r\t\n") + (or (eobp) (beginning-of-line))) + ;; On affiliated keywords, move to element's beginning. + ((< (point) post-affiliated) + (goto-char post-affiliated)) + ;; At a table row, move to the end of the table. Similarly, + ;; at a node property, move to the end of the property + ;; drawer. + ((memq type '(node-property table-row)) + (goto-char (org-element-property + :end (org-element-property :parent element)))) + ((memq type '(property-drawer table)) (goto-char end)) + ;; Consider blank lines as separators in verse and source + ;; blocks to ease editing. + ((memq type '(src-block verse-block)) + (when (eq type 'src-block) + (setq contents-end + (save-excursion (goto-char end) + (skip-chars-backward " \r\t\n") + (line-beginning-position)))) + (beginning-of-line) + (when (looking-at "[ \t]*$") (skip-chars-forward " \r\t\n")) + (if (not (re-search-forward "^[ \t]*$" contents-end t)) + (goto-char end) + (skip-chars-forward " \r\t\n") + (if (= (point) contents-end) (goto-char end) + (beginning-of-line)))) + ;; With no contents, just skip element. + ((not contents-begin) (goto-char end)) + ;; If contents are invisible, skip the element altogether. + ((org-invisible-p (line-end-position)) + (cl-case type + (headline + (org-with-limited-levels (outline-next-visible-heading 1))) + ;; At a plain list, make sure we move to the next item + ;; instead of skipping the whole list. + (plain-list (forward-char) + (org-forward-paragraph)) + (otherwise (goto-char end)))) + ((>= (point) contents-end) (goto-char end)) + ((>= (point) contents-begin) + ;; This can only happen on paragraphs and plain lists. + (cl-case type + (paragraph (goto-char end)) + ;; At a plain list, try to move to second element in + ;; first item, if possible. + (plain-list (end-of-line) + (org-forward-paragraph)))) + ;; When contents start on the middle of a line (e.g. in + ;; items and footnote definitions), try to reach first + ;; element starting after current line. + ((> (line-end-position) contents-begin) + (end-of-line) + (org-forward-paragraph)) + (t (goto-char contents-begin)))))) (defun org-backward-paragraph () "Move backward to start of previous paragraph or equivalent. @@ -24498,55 +24480,55 @@ convenience: - On a table or a property drawer, move to its beginning. - On a verse or source block, stop before blank lines." (interactive) - (when (bobp) (user-error "Cannot move further up")) - (let* ((deactivate-mark nil) - (element (org-element-at-point)) - (type (org-element-type element)) - (contents-begin (org-element-property :contents-begin element)) - (contents-end (org-element-property :contents-end element)) - (post-affiliated (org-element-property :post-affiliated element)) - (begin (org-element-property :begin element))) - (cond - ((not element) (goto-char (point-min))) - ((= (point) begin) - (backward-char) - (org-backward-paragraph)) - ((<= (point) post-affiliated) (goto-char begin)) - ((memq type '(node-property table-row)) - (goto-char (org-element-property - :post-affiliated (org-element-property :parent element)))) - ((memq type '(property-drawer table)) (goto-char begin)) - ((memq type '(src-block verse-block)) - (when (eq type 'src-block) - (setq contents-begin - (save-excursion (goto-char begin) (forward-line) (point)))) - (if (= (point) contents-begin) (goto-char post-affiliated) - ;; Inside a verse block, see blank lines as paragraph - ;; separators. - (let ((origin (point))) - (skip-chars-backward " \r\t\n" contents-begin) - (when (re-search-backward "^[ \t]*$" contents-begin 'move) - (skip-chars-forward " \r\t\n" origin) - (if (= (point) origin) (goto-char contents-begin) - (beginning-of-line)))))) - ((not contents-begin) (goto-char (or post-affiliated begin))) - ((eq type 'paragraph) - (goto-char contents-begin) - ;; When at first paragraph in an item or a footnote definition, - ;; move directly to beginning of line. - (let ((parent-contents - (org-element-property - :contents-begin (org-element-property :parent element)))) - (when (and parent-contents (= parent-contents contents-begin)) - (beginning-of-line)))) - ;; At the end of a greater element, move to the beginning of the - ;; last element within. - ((>= (point) contents-end) - (goto-char (1- contents-end)) - (org-backward-paragraph)) - (t (goto-char (or post-affiliated begin)))) - ;; Ensure we never leave point invisible. - (when (org-invisible-p (point)) (beginning-of-visual-line)))) + (unless (bobp) + (let* ((deactivate-mark nil) + (element (org-element-at-point)) + (type (org-element-type element)) + (contents-begin (org-element-property :contents-begin element)) + (contents-end (org-element-property :contents-end element)) + (post-affiliated (org-element-property :post-affiliated element)) + (begin (org-element-property :begin element))) + (cond + ((not element) (goto-char (point-min))) + ((= (point) begin) + (backward-char) + (org-backward-paragraph)) + ((<= (point) post-affiliated) (goto-char begin)) + ((memq type '(node-property table-row)) + (goto-char (org-element-property + :post-affiliated (org-element-property :parent element)))) + ((memq type '(property-drawer table)) (goto-char begin)) + ((memq type '(src-block verse-block)) + (when (eq type 'src-block) + (setq contents-begin + (save-excursion (goto-char begin) (forward-line) (point)))) + (if (= (point) contents-begin) (goto-char post-affiliated) + ;; Inside a verse block, see blank lines as paragraph + ;; separators. + (let ((origin (point))) + (skip-chars-backward " \r\t\n" contents-begin) + (when (re-search-backward "^[ \t]*$" contents-begin 'move) + (skip-chars-forward " \r\t\n" origin) + (if (= (point) origin) (goto-char contents-begin) + (beginning-of-line)))))) + ((not contents-begin) (goto-char (or post-affiliated begin))) + ((eq type 'paragraph) + (goto-char contents-begin) + ;; When at first paragraph in an item or a footnote definition, + ;; move directly to beginning of line. + (let ((parent-contents + (org-element-property + :contents-begin (org-element-property :parent element)))) + (when (and parent-contents (= parent-contents contents-begin)) + (beginning-of-line)))) + ;; At the end of a greater element, move to the beginning of the + ;; last element within. + ((>= (point) contents-end) + (goto-char (1- contents-end)) + (org-backward-paragraph)) + (t (goto-char (or post-affiliated begin)))) + ;; Ensure we never leave point invisible. + (when (org-invisible-p (point)) (beginning-of-visual-line))))) (defun org-forward-element () "Move forward by one element. |