From 77aad13b9a322032763148b17dd9cb3073bdbf23 Mon Sep 17 00:00:00 2001 From: Nicolas Goaziou Date: Sun, 20 Feb 2011 13:44:00 +0100 Subject: [PATCH] Integrate lists with org-indent-mode and visual-line-mode * lisp/org-list.el (org-list-insert-item): keep prefix properties when inserting a new item. (org-list-struct-apply-struct): keep prefix properties when modifying an item. * lisp/org-indent.el (org-indent-mode): promoting and demoting should refresh subtree. (org-indent-add-properties): Add lists support. Refactor and comment code. (org-indent-refresh-subtree): No need to remove properties before refreshing. Also, make sure beg is at beginning of line. (org-indent-refresh-to, org-indent-refresh-section): Refactor. No need to remove properties before refreshing either. --- lisp/org-indent.el | 132 ++++++++++++++++++++++----------------------------- lisp/org-list.el | 18 ++++++- 2 files changed, 73 insertions(+), 77 deletions(-) diff --git a/lisp/org-indent.el b/lisp/org-indent.el index a177a6f..4411cd2 100644 --- a/lisp/org-indent.el +++ b/lisp/org-indent.el @@ -39,6 +39,7 @@ (require 'cl)) (defvar org-inlinetask-min-level) +(declare-function org-in-item-p "org-list" ()) (declare-function org-inlinetask-get-task-level "org-inlinetask" ()) (declare-function org-inlinetask-in-task-p "org-inlinetask" ()) @@ -161,13 +162,12 @@ FIXME: How to update when broken?" (add-to-list 'buffer-substring-filters 'org-indent-remove-properties-from-string) (org-add-hook 'org-after-demote-entry-hook - 'org-indent-refresh-section nil 'local) + 'org-indent-refresh-subtree nil 'local) (org-add-hook 'org-after-promote-entry-hook - 'org-indent-refresh-section nil 'local) + 'org-indent-refresh-subtree nil 'local) (org-add-hook 'org-font-lock-hook 'org-indent-refresh-to nil 'local) - (and font-lock-mode (org-restart-font-lock)) - ) + (and font-lock-mode (org-restart-font-lock))) (t ;; mode was turned off (or we refused to turn it on) (save-excursion @@ -181,9 +181,9 @@ FIXME: How to update when broken?" (delq 'org-indent-remove-properties-from-string buffer-substring-filters)) (remove-hook 'org-after-promote-entry-hook - 'org-indent-refresh-section 'local) + 'org-indent-refresh-subtree 'local) (remove-hook 'org-after-demote-entry-hook - 'org-indent-refresh-section 'local) + 'org-indent-refresh-subtree 'local) (and font-lock-mode (org-restart-font-lock)) (redraw-display)))))) @@ -222,82 +222,66 @@ useful to make it ever so slightly different." (defun org-indent-add-properties (beg end) "Add indentation properties between BEG and END. -Assumes that BEG is at the beginning of a line." +Assume BEG is at an headline, inline task, or at beginning of buffer." (let* ((inhibit-modification-hooks t) (inlinetaskp (featurep 'org-inlinetask)) - (get-real-level (lambda (pos lvl) - (save-excursion - (goto-char pos) - (if (and inlinetaskp (org-inlinetask-in-task-p)) - (org-inlinetask-get-task-level) - lvl)))) - (b beg) - (e end) - (level 0) - (n 0) - exit nstars) + (m end)) (with-silent-modifications + ;; 1. Starting from END, move to each headline and inline task, + ;; and set prefixes point and the headline/inline task below + ;; (saved in M). `line-prefix' property is only set on inner + ;; part of that area, not on headlines. (save-excursion + (goto-char end) + (while (re-search-backward org-indent-outline-re beg 'move) + (let ((pf (aref org-indent-strings + (if (and inlinetaskp (org-inlinetask-at-task-p)) + (1+ (org-inlinetask-get-task-level)) + (1+ (org-current-level)))))) + (add-text-properties (point) m `(wrap-prefix ,pf)) + (add-text-properties (point-at-eol) m `(line-prefix ,pf)) + (setq m (point)))) + ;; Special case for area before first headline. + (when (bobp) + (add-text-properties (point) m '(wrap-prefix nil line-prefix nil))) + ;; 2. Set `wrap-prefix' in lists between BEG and END. For each + ;; item, length of prefix is the sum of length of + ;; `line-prefix', indentation and size of bullet. (goto-char beg) - (while (not exit) - (setq e end) - (if (not (re-search-forward org-indent-outline-re nil t)) - (setq e (point-max) exit t) - (setq e (match-beginning 0)) - (if (>= e end) (setq exit t)) - (unless (and inlinetaskp (org-inlinetask-in-task-p)) - (setq level (- (match-end 0) (match-beginning 0) 1))) - (setq nstars (* (1- (funcall get-real-level e level)) - (1- org-indent-indentation-per-level))) - (add-text-properties - (point-at-bol) (point-at-eol) - (list 'line-prefix - (aref org-indent-stars nstars) - 'wrap-prefix - (aref org-indent-strings - (* (funcall get-real-level e level) - org-indent-indentation-per-level))))) - (when (> e b) - (add-text-properties - b e (list 'line-prefix (aref org-indent-strings n) - 'wrap-prefix (aref org-indent-strings n)))) - (setq b (1+ (point-at-eol)) - n (* (funcall get-real-level b level) - org-indent-indentation-per-level))))))) + (while (org-list-search-forward (org-item-beginning-re) end t) + (let ((struct (org-list-struct))) + (mapc (lambda (itm) + (let ((pf (aref org-indent-strings + (+ (length (get-text-property + (car itm) 'line-prefix)) + (nth 1 itm) + (length (nth 2 itm)))))) + (add-text-properties (car itm) (1- (nth 6 itm)) + `(wrap-prefix ,pf)))) + struct) + (goto-char (org-list-get-bottom-point struct)))))))) (defvar org-inlinetask-min-level) (defun org-indent-refresh-section () - "Refresh indentation properties in the current outline section. -Point is assumed to be at the beginning of a headline." + "Refresh indentation properties between point and end next outline section." (interactive) (when org-indent-mode - (let (beg end) - (save-excursion - (when (ignore-errors (let ((outline-regexp (format "\\*\\{1,%s\\}[ \t]+" - (if (featurep 'org-inlinetask) - (1- org-inlinetask-min-level) - "")))) - (org-back-to-heading))) - (setq beg (point)) - (setq end (or (save-excursion (or (outline-next-heading) (point))))) - (org-indent-remove-properties beg end) - (org-indent-add-properties beg end)))))) + (save-excursion + (org-with-limited-levels + (let ((beg (or (ignore-errors (org-back-to-heading)) + (point-min))) + (end (progn (outline-next-heading) (point)))) + (org-indent-add-properties beg end)))))) (defun org-indent-refresh-to (limit) - "Refresh indentation properties in the current outline section. -Point is assumed to be at the beginning of a headline." + "Refresh indentation properties in the current outline section." (interactive) (when org-indent-mode - (let ((beg (point)) (end limit)) - (save-excursion - (and (ignore-errors (let ((outline-regexp (format "\\*\\{1,%s\\}[ \t]+" - (if (featurep 'org-inlinetask) - (1- org-inlinetask-min-level) - "")))) - (org-back-to-heading))) - (setq beg (point)))) - (org-indent-remove-properties beg end) - (org-indent-add-properties beg end))) + (save-excursion + (org-with-limited-levels + (let ((beg (or (and (ignore-errors (org-back-to-heading)) (point)) + (point-min)))) + (org-indent-add-properties beg limit))))) (goto-char limit)) (defun org-indent-refresh-subtree () @@ -306,15 +290,13 @@ Point is assumed to be at the beginning of a headline." (interactive) (when org-indent-mode (save-excursion - (let (beg end) - (setq beg (point)) - (setq end (save-excursion (org-end-of-subtree t t))) - (org-indent-remove-properties beg end) - (org-indent-add-properties beg end))))) + (org-with-limited-levels + (let ((beg (point-at-bol)) + (end (save-excursion (org-end-of-subtree t t)))) + (org-indent-add-properties beg end)))))) (defun org-indent-refresh-buffer () - "Refresh indentation properties in the current outline subtree. -Point is assumed to be at the beginning of a headline." + "Refresh indentation properties in the current outline subtree." (interactive) (when org-indent-mode (org-indent-mode -1) diff --git a/lisp/org-list.el b/lisp/org-list.el index 4700477..8ffe4d0 100644 --- a/lisp/org-list.el +++ b/lisp/org-list.el @@ -1156,9 +1156,12 @@ This function modifies STRUCT." ;; functions, position of point with regards to item start ;; (BEFOREP), blank lines number separating items (BLANK-NB), ;; position of split (POS) if we're allowed to (SPLIT-LINE-P). + ;; Also, save prefix properties for `org-indent-mode'. (let* ((item (goto-char (org-list-get-item-begin))) (item-end (org-list-get-item-end item struct)) (item-end-no-blank (org-list-get-item-end-before-blank item struct)) + (wrap (get-text-property (point) 'wrap-prefix)) + (line (get-text-property (point) 'line-prefix)) (beforep (and (looking-at org-list-full-item-re) (<= pos (match-end 0)))) (split-line-p (org-get-alist-option org-M-RET-may-split-line 'item)) @@ -1194,6 +1197,9 @@ This function modifies STRUCT." (goto-char item) (org-indent-to-column ind) (insert body) + (when (and (featurep 'org-indent) org-indent-mode) + (add-text-properties item (point) + `(line-prefix ,line wrap-prefix ,wrap))) (insert item-sep) ;; 5. Add new item to STRUCT. (mapc (lambda (e) @@ -1628,7 +1634,9 @@ Initial position of cursor is restored after the changes." (new-bul (org-list-bullet-string (org-list-get-bullet item struct))) (old-bul (org-list-get-bullet item old-struct)) - (new-box (org-list-get-checkbox item struct))) + (new-box (org-list-get-checkbox item struct)) + (wrap (get-text-property (point) 'wrap-prefix)) + (line (get-text-property (point) 'line-prefix))) (looking-at org-list-full-item-re) ;; a. Replace bullet (unless (equal old-bul new-bul) @@ -1652,7 +1660,13 @@ Initial position of cursor is restored after the changes." (unless (= new-ind old-ind) (delete-region (goto-char (point-at-bol)) (progn (skip-chars-forward " \t") (point))) - (indent-to new-ind))))))) + (indent-to new-ind)) + ;; d. If `org-indent-mode' is on, keep prefix + ;; properties. + (when (and (featurep 'org-indent) org-indent-mode) + (add-text-properties + (point-at-bol) (point-at-eol) + `(line-prefix ,line wrap-prefix ,wrap)))))))) ;; 1. First get list of items and position endings. We maintain ;; two alists: ITM-SHIFT, determining indentation shift needed ;; at item, and END-POS, a pseudo-alist where key is ending -- 1.7.4.1