From mboxrd@z Thu Jan 1 00:00:00 1970 From: Nicolas Goaziou Subject: Re: Outline cycling does not preserve point's position Date: Wed, 11 Sep 2013 22:01:31 +0200 Message-ID: <87fvtb6sbo.fsf@gmail.com> References: <7CB7B681-DD2E-446C-AE45-DDCA204EE95C@gmail.com> <5855E8E1-9730-4A29-89FF-E35C64E54EDD@gmail.com> <20130910073257.GO20690@kuru.dyndns-at-home.com> <20130910075345.GP20690@kuru.dyndns-at-home.com> <25A21DB7-B2E5-47BB-8A64-594A15CB24B8@gmail.com> <20130910085057.GQ20690@kuru.dyndns-at-home.com> <4ED2509E-8A2E-4ED2-BFCF-CB7B27F1D2B4@gmail.com> <20130910095043.GR20690@kuru.dyndns-at-home.com> <87a9jk8wmr.fsf@gmail.com> <20130910185843.GA20690@kuru.dyndns-at-home.com> <871u4w8nkq.fsf@gmail.com> <8761u8m5sd.fsf@gmail.com> <87ioy78vib.fsf@gmail.com> <878uz3e5nu.fsf@gmail.com> <87txhr74f7.fsf@gmail.com> <87zjrjcp4e.fsf@gmail.com> Mime-Version: 1.0 Content-Type: text/plain Return-path: Received: from eggs.gnu.org ([2001:4830:134:3::10]:42572) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VJqbT-0007kf-Qr for emacs-orgmode@gnu.org; Wed, 11 Sep 2013 16:01:40 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1VJqbI-0004ZZ-4x for emacs-orgmode@gnu.org; Wed, 11 Sep 2013 16:01:31 -0400 Received: from mail-ea0-x233.google.com ([2a00:1450:4013:c01::233]:55781) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VJqbH-0004Yo-QQ for emacs-orgmode@gnu.org; Wed, 11 Sep 2013 16:01:20 -0400 Received: by mail-ea0-f179.google.com with SMTP id b10so4887900eae.10 for ; Wed, 11 Sep 2013 13:01:18 -0700 (PDT) In-Reply-To: <87zjrjcp4e.fsf@gmail.com> (Jambunathan K.'s message of "Wed, 11 Sep 2013 21:44:09 +0530") List-Id: "General discussions about Org-mode." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-orgmode-bounces+geo-emacs-orgmode=m.gmane.org@gnu.org Sender: emacs-orgmode-bounces+geo-emacs-orgmode=m.gmane.org@gnu.org To: Jambunathan K Cc: emacs-orgmode@gnu.org, Carsten Dominik Jambunathan K writes: > I am happy with whatever is the latest version. You may want to commit > it. I copy here[fn:1] the current version, for the record, along with its backward counterpart. Some points are still to be discussed: 1. What to do on node properties? 2. What to do on source blocks? [fn:1] Here is the code: (defun org-forward-linear-element () "Move forward to beginning of next element, ignoring depth. The function implements some special moves for convenience: - On an affiliated keyword, jump to the beginning of the relative element. - On an item or a footnote definition, move to the second element inside, if any. - On a table, jump after it. - On a verse block, stop after each blank line." (interactive) (when (eobp) (user-error "Cannot move further down")) (let* ((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. ((and post-affiliated (< (point) post-affiliated)) (goto-char post-affiliated)) ;; At a table row, move to the end of the table. ((eq type 'table-row) (goto-char (org-element-property :end (org-element-property :parent element)))) ((eq type 'table) (goto-char end)) ((not contents-begin) (goto-char end)) ;; If current element contents are invisible, skip the ;; element altogether. ((outline-invisible-p (line-end-position)) (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-linear-element)) (otherwise (goto-char end)))) ((>= (point) contents-end) (goto-char end)) ((>= (point) contents-begin) ;; Handle special cases. In all other situations, point is ;; where it should be. (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-linear-element)) ;; Consider blank lines as separators in verse blocks to ;; ease editing. (verse-block (beginning-of-line) (if (not (re-search-forward "^[ \t]*$" contents-end t)) (goto-char end) (skip-chars-forward " \r\t\n") (if (= (point) contents-end) (goto-char contents) (beginning-of-line)))))) ;; 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-linear-element)) (t (goto-char contents-begin))))) (defun org-backward-linear-element () "Move backward to start of previous element, ignoring depth." (interactive) (when (bobp) (user-error "Cannot move further up")) (let* ((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-linear-element)) ((and post-affiliated (<= (point) post-affiliated)) (goto-char begin)) ((eq type 'table-row) (goto-char (org-element-property :contents-begin (org-element-property :parent element)))) ((eq type 'table) (goto-char begin)) ((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)))) ((eq type 'verse-block) (if (= (point) contents-begin) (goto-char (or post-affiliated begin)) ;; 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)))))) ;; 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-linear-element)) (t (goto-char (or post-affiliated begin)))) ;; Ensure we never leave point invisible. (when (outline-invisible-p (point)) (beginning-of-visual-line)))) Regards, -- Nicolas Goaziou