summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Goaziou <mail@nicolasgoaziou.fr>2016-10-15 00:48:47 +0200
committerNicolas Goaziou <mail@nicolasgoaziou.fr>2016-10-15 11:36:09 +0200
commit45048eb78359fc742097982fc1adc5ca5e4b2509 (patch)
treea79c58f79cb23517d6619fe7b15be6e0005fb22c
parent2971c48cf133d88e61ceb1c6887af2204d0cc665 (diff)
downloadorg-mode-45048eb78359fc742097982fc1adc5ca5e4b2509.tar.gz
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.
-rw-r--r--lisp/org.el87
-rw-r--r--testing/lisp/test-org.el82
2 files changed, 120 insertions, 49 deletions
diff --git a/lisp/org.el b/lisp/org.el
index 8664e28..85e7807 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -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))))))))
diff --git a/testing/lisp/test-org.el b/testing/lisp/test-org.el
index 164ed89..08ce4d8 100644
--- a/testing/lisp/test-org.el
+++ b/testing/lisp/test-org.el
@@ -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."