0
0
Fork 1
mirror of https://git.savannah.gnu.org/git/emacs/org-mode.git synced 2024-09-29 20:37:51 +00:00

Fix `C-e' with visible lines and arguments

* lisp/org.el (org-end-of-line): Correctly go to the end of visible
  line, when appropriate.
* testing/lisp/test-org.el (test-org/end-of-line): Add tests.
This commit is contained in:
Nicolas Goaziou 2016-10-15 00:48:47 +02:00
parent 2971c48cf1
commit 45048eb783
2 changed files with 120 additions and 49 deletions

View file

@ -23766,42 +23766,63 @@ the cursor is already beyond the end of the headline."
(when (and (= (point) pos) (eq last-command this-command))
(goto-char after-bullet))))))))
(defun org-end-of-line (&optional arg)
"Go to the end of the line.
(defun org-end-of-line (&optional n)
"Go to the end of the line, but before ellipsis, if any.
If this is a headline, and `org-special-ctrl-a/e' is set, ignore
tags on the first attempt, and only move to after the tags when
the cursor is already beyond the end of the headline."
(interactive "P")
(let ((special (if (consp org-special-ctrl-a/e) (cdr org-special-ctrl-a/e)
org-special-ctrl-a/e))
(move-fun (cond ((bound-and-true-p visual-line-mode)
'end-of-visual-line)
((fboundp 'move-end-of-line) 'move-end-of-line)
(t 'end-of-line)))
the cursor is already beyond the end of the headline.
With argument N not nil or 1, move forward N - 1 lines first."
(interactive "^p")
(let ((origin (point))
(special (pcase org-special-ctrl-a/e
(`(_ . ,C-e) C-e) (_ org-special-ctrl-a/e)))
deactivate-mark)
(if (or (not special) arg) (call-interactively move-fun)
(let* ((element (save-excursion (beginning-of-line)
(org-element-at-point)))
(type (org-element-type element)))
(cond
((memq type '(headline inlinetask))
(let ((pos (point)))
(beginning-of-line 1)
(if (looking-at ".*?\\(?:\\([ \t]*\\)\\(:[[:alnum:]_@#%:]+:\\)?[ \t]*\\)?$")
(if (eq special t)
(if (or (< pos (match-beginning 1)) (= pos (match-end 0)))
(goto-char (match-beginning 1))
(goto-char (match-end 0)))
(if (or (< pos (match-end 0))
(not (eq this-command last-command)))
(goto-char (match-end 0))
(goto-char (match-beginning 1))))
(call-interactively move-fun))))
((outline-invisible-p (line-end-position))
;; If element is hidden, `move-end-of-line' would put point
;; after it. Use `end-of-line' to stay on current line.
(call-interactively 'end-of-line))
(t (call-interactively move-fun))))))
;; First move to a visible line.
(if (bound-and-true-p visual-line-mode)
(beginning-of-visual-line n)
(move-beginning-of-line n))
(cond
;; At a headline, with tags.
((and special
(save-excursion
(beginning-of-line)
(looking-at org-complex-heading-regexp))
(match-end 5))
(let ((tags (save-excursion
(goto-char (match-beginning 5))
(skip-chars-backward " \t")
(point)))
(visual-end (and (bound-and-true-p visual-line-mode)
(save-excursion
(end-of-visual-line)
(point)))))
;; If `end-of-visual-line' brings us before end of line or
;; even tags, i.e., the headline spans over multiple visual
;; lines, move there.
(cond ((and visual-end
(< visual-end tags)
(<= origin visual-end))
(goto-char visual-end))
((eq special 'reversed)
(if (and (= origin (line-end-position))
(eq this-command last-command))
(goto-char tags)
(end-of-line)))
(t
(if (or (< origin tags) (= origin (line-end-position)))
(goto-char tags)
(end-of-line))))))
((bound-and-true-p visual-line-mode)
(let ((bol (line-beginning-position)))
(end-of-visual-line)
;; If `end-of-visual-line' gets us past the ellipsis at the
;; end of a line, backtrack and use `end-of-line' instead.
(when (/= bol (line-beginning-position))
(goto-char bol)
(end-of-line))))
(t (end-of-line))))
(setq disable-point-adjustment
(or (not (invisible-p (point)))
(not (invisible-p (max (point-min) (1- (point))))))))

View file

@ -2511,35 +2511,80 @@ http://article.gmane.org/gmane.emacs.orgmode/21459/"
(should
(org-test-with-temp-text "Some text\nSome other text"
(progn (org-end-of-line) (eolp))))
;; Standard test with `visual-line-mode'.
;; With `visual-line-mode' active, move to end of visible line.
;; However, never go past ellipsis.
(should-not
(org-test-with-temp-text "A long line of text\nSome other text"
(progn (visual-line-mode)
(forward-char 2)
(dotimes (i 1000) (insert "very "))
(goto-char (point-min))
(org-end-of-line)
(eolp))))
;; At an headline with special movement.
(org-test-with-temp-text "A <point>long line of text\nSome other text"
(visual-line-mode)
(dotimes (i 1000) (insert "very "))
(goto-char (point-min))
(org-end-of-line)
(eolp)))
(should-not
(org-test-with-temp-text "* A short headline\nSome contents"
(visual-line-mode)
(org-overview)
(org-end-of-line)
(eobp)))
;; In a wide headline, with `visual-line-mode', prefer going to end
;; of visible line if tags, or end of line, are farther.
(should-not
(org-test-with-temp-text "* A <point>long headline"
(visual-line-mode)
(dotimes (i 1000) (insert "very "))
(goto-char (point-min))
(org-end-of-line)
(eolp)))
(should-not
(org-test-with-temp-text "* A <point>long headline :tag:"
(visual-line-mode)
(dotimes (i 1000) (insert "very "))
(goto-char (point-min))
(org-end-of-line)
(eolp)))
;; At an headline without special movement, go to end of line.
;; However, never go past ellipsis.
(should
(org-test-with-temp-text "* Headline2b :tag:\n"
(let ((org-special-ctrl-a/e nil))
(and (progn (org-end-of-line) (eolp))
(progn (org-end-of-line) (eolp))))))
(should
(org-test-with-temp-text "* Headline2a :tag:\n** Sub"
(org-overview)
(let ((org-special-ctrl-a/e nil))
(org-end-of-line)
(= 1 (line-beginning-position)))))
;; At an headline with special movement, first move before tags,
;; then at the end of line, rinse, repeat. However, never go past
;; ellipsis.
(should
(org-test-with-temp-text "* Headline1 :tag:\n"
(let ((org-special-ctrl-a/e t))
(and (progn (org-end-of-line) (looking-at " :tag:"))
(progn (org-end-of-line) (eolp))
(progn (org-end-of-line) (looking-at " :tag:"))))))
;; At an headline without special movement.
(should
(org-test-with-temp-text "* Headline2 :tag:\n"
(let ((org-special-ctrl-a/e nil))
(and (progn (org-end-of-line) (eolp))
(progn (org-end-of-line) (eolp))))))
;; At an headline, with reversed movement.
(org-test-with-temp-text "* Headline2a :tag:\n** Sub"
(org-overview)
(let ((org-special-ctrl-a/e t))
(org-end-of-line)
(org-end-of-line)
(= 1 (line-beginning-position)))))
;; At an headline, with reversed movement, first go to end of line,
;; then before tags. However, never go past ellipsis.
(should
(org-test-with-temp-text "* Headline3 :tag:\n"
(let ((org-special-ctrl-a/e 'reversed)
(this-command last-command))
(and (progn (org-end-of-line) (eolp))
(progn (org-end-of-line) (looking-at " :tag:"))))))
(should
(org-test-with-temp-text "* Headline2a :tag:\n** Sub"
(org-overview)
(let ((org-special-ctrl-a/e 'reversed))
(org-end-of-line)
(= 1 (line-beginning-position)))))
;; At a block without hidden contents.
(should
(org-test-with-temp-text "#+BEGIN_CENTER\nContents\n#+END_CENTER"
@ -2550,7 +2595,12 @@ http://article.gmane.org/gmane.emacs.orgmode/21459/"
(let ((org-special-ctrl-a/e t))
(org-hide-block-toggle)
(org-end-of-line)
(eobp)))))
(eobp))))
;; Get past invisible characters at the end of line.
(should
(org-test-with-temp-text "[[http://orgmode.org]]"
(org-end-of-line)
(eolp))))
(ert-deftest test-org/open-line ()
"Test `org-open-line' specifications."