Improve compatibility between org-indent-mode and visual-line-mode

* lisp/org-indent.el (org-indent-mode): completely refresh buffer
  before starting org-indent-mode. Also set idle timer to refresh only
  visible portion of buffer, and refresh the subtree instead of
  section when promoting or demoting it.
  (org-indent-add-properties): rewrite function to proceed line by
  line, as required by `wrap-prefix' specificity.
  (org-indent-refresh-section,org-indent-refresh-subtree): refactor.
  (org-indent-refresh-view): new function.
  (org-indent-refresh-to, org-indent-refresh-section): removed
  functions.
* lisp/org.el (org-unfontify-region): do not remove prefix properties
  when unfontifying a region.
This commit is contained in:
Nicolas Goaziou 2011-02-20 13:44:00 +01:00
parent 3100838dcc
commit 4771caa09c
2 changed files with 117 additions and 114 deletions

View File

@ -37,9 +37,9 @@
(eval-when-compile
(require 'cl))
(defvar org-inlinetask-min-level)
(declare-function org-inlinetask-get-task-level "org-inlinetask" ())
(declare-function org-inlinetask-in-task-p "org-inlinetask" ())
(declare-function org-inlinetask-outline-regexp "org-inlinetask" ())
(defgroup org-indent nil
"Options concerning dynamic virtual outline indentation."
@ -109,7 +109,7 @@ this variable can be set to nil to get rid of the timer."
(when org-indent-fix-section-after-idle-time
(run-with-idle-timer
org-indent-fix-section-after-idle-time
t 'org-indent-refresh-section)))
t 'org-indent-refresh-view)))
;; Initialize the indentation and star vectors
(setq org-indent-strings (make-vector (1+ org-indent-max) nil))
(setq org-indent-stars (make-vector (1+ org-indent-max) nil))
@ -130,9 +130,9 @@ this variable can be set to nil to get rid of the timer."
(define-minor-mode org-indent-mode
"When active, indent text according to outline structure.
Internally this works by adding `line-prefix' properties to all non-headlines.
These properties are updated locally in idle time.
FIXME: How to update when broken?"
Internally this works by adding `line-prefix' and `wrap-prefix'
properties to all lines. These properties are updated locally in idle
time."
nil " Ind" nil
(cond
((org-bound-and-true-p org-inhibit-startup)
@ -150,6 +150,7 @@ FIXME: How to update when broken?"
;; mode was turned on.
(org-set-local 'indent-tabs-mode nil)
(or org-indent-strings (org-indent-initialize))
(org-indent-indent-buffer)
(when org-indent-mode-turns-off-org-adapt-indentation
(org-set-local 'org-adapt-indentation nil))
(when org-indent-mode-turns-on-hiding-stars
@ -160,13 +161,10 @@ 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-add-hook 'org-font-lock-hook
'org-indent-refresh-to nil 'local)
(and font-lock-mode (org-restart-font-lock))
)
'org-indent-refresh-subtree nil 'local)
(and font-lock-mode (org-restart-font-lock)))
(t
;; mode was turned off (or we refused to turn it on)
(save-excursion
@ -180,9 +178,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))))))
@ -216,104 +214,116 @@ useful to make it ever so slightly different."
'(line-prefix nil wrap-prefix nil) string)
string)
(defvar org-indent-outline-re org-outline-regexp-bol
"Outline heading regexp.")
(defun org-indent-add-properties (beg end)
"Add indentation properties between BEG and END.
Assumes that BEG is at the beginning of a line."
(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)
(with-silent-modifications
(save-excursion
(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)))))))
"Add indentation properties between BEG and END."
(save-excursion
(goto-char beg)
(beginning-of-line)
;; 1. Initialize prefix at BEG. This is done by storing two
;; variables: INLINE-PF and PF, representing respectively
;; current `line-prefix' when line is inside an inline task or
;; not.
(let* ((inhibit-modification-hooks t)
(case-fold-search t)
(limited-re (org-get-limited-outline-regexp))
(inline-end-re (and (featurep 'org-inlinetask)
(concat (org-inlinetask-outline-regexp)
"end[ \t]*$")))
(pf (org-with-limited-levels
(save-excursion
(and (ignore-errors (org-back-to-heading t))
(looking-at org-outline-regexp)
(aref org-indent-strings
(- (match-end 0) (match-beginning 0)))))))
(pf-inline (and inline-end-re
(org-inlinetask-in-task-p)
(aref org-indent-strings
(1+ (org-inlinetask-get-task-level))))))
;; 2. For each line, `line-prefix' is based on the value of the
;; previous `line-prefix' (stored in PF and INLINE-PF).
;; `wrap-prefix' computation is done with the current
;; `line-prefix' value.
(with-silent-modifications
(while (< (point) end)
(cond
;; Empty line: do nothing.
((eolp) (forward-line 1))
;; List item: `line-prefix' doesn't change, but
;; `wrap-prefix' is set where body starts.
((org-at-item-p)
(let* ((line (or pf-inline pf))
(wrap (aref org-indent-strings
(+ (org-list-item-body-column (point))
(length line)))))
(add-text-properties (point) (point-at-eol)
`(line-prefix ,line wrap-prefix ,wrap))
(forward-line 1)))
;; Normal line: `line-prefix' doesn't change, but
;; `wrap-prefix' also takes into account indentation.
((not (looking-at org-outline-regexp))
(let* ((line (or pf-inline pf))
(wrap (aref org-indent-strings
(+ (length line) (org-get-indentation)))))
(add-text-properties (point) (point-at-eol)
`(line-prefix ,line wrap-prefix ,wrap))
(forward-line 1)))
;; Headline: `line-prefix' is nil, `wrap-prefix' is set
;; where headline starts and its value becomes a reference
;; for following lines.
((looking-at limited-re)
(let ((wrap (aref org-indent-strings
(- (match-end 0) (match-beginning 0)))))
(add-text-properties (point) (point-at-eol)
`(line-prefix nil wrap-prefix ,wrap))
(setq pf wrap)
(forward-line 1)))
;; End of inline task: both `line-prefix' and `wrap-prefix'
;; are nil. PF-INLINE is also nil, as following lines are
;; out of the inline task.
((looking-at inline-end-re)
(add-text-properties (point) (point-at-eol)
'(line-prefix nil wrap-prefix nil))
(setq pf-inline nil)
(forward-line 1))
;; Beginnig of inline task: determine if the tasks contains
;; text (and set PF-INLINE accordingly) or is only one line
;; long by looking the status of the following line. In any
;; case, `line-prefix' is nil and `wrap-prefix' is set
;; where headline starts.
(t
(let ((wrap (progn
(looking-at org-outline-regexp)
(aref org-indent-strings
(- (match-end 0) (match-beginning 0))))))
(add-text-properties (point) (point-at-eol)
`(line-prefix nil wrap-prefix ,wrap))
(forward-line 1)
(setq pf-inline (and (not (eobp))
(org-inlinetask-in-task-p)
wrap))))))))))
(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."
(interactive)
(when org-indent-mode
(let (beg end)
(save-excursion
(when (ignore-errors (let ((org-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))))))
(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."
(interactive)
(when org-indent-mode
(let ((beg (point)) (end limit))
(save-excursion
(and (ignore-errors (let ((org-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)))
(goto-char limit))
(defun org-indent-refresh-subtree ()
"Refresh indentation properties in the current outline subtree.
Point is assumed to be at the beginning of a headline."
(defun org-indent-refresh-view (&rest ignore)
"Refresh indentation properties in the visible portion of buffer.
IGNORE all arguments that might be passed to the function."
(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)
(let ((beg (window-start))
(end (window-end nil t)))
(org-indent-add-properties beg end)))))
(defun org-indent-refresh-subtree ()
"Refresh indentation properties in the current outline subtree.
Point is assumed to be at an headline."
(interactive)
(when org-indent-mode
(save-excursion
(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 whole buffer."
(interactive)
(when org-indent-mode
(org-indent-mode -1)

View File

@ -5837,17 +5837,10 @@ If KWD is a number, get the corresponding match group."
(inhibit-modification-hooks t)
deactivate-mark buffer-file-name buffer-file-truename)
(org-decompose-region beg end)
(remove-text-properties
beg end
(if org-indent-mode
;; also remove line-prefix and wrap-prefix properties
'(mouse-face t keymap t org-linked-text t
invisible t intangible t
line-prefix t wrap-prefix t
org-no-flyspell t org-emphasis t)
'(mouse-face t keymap t org-linked-text t
invisible t intangible t
org-no-flyspell t org-emphasis t)))
(remove-text-properties beg end
'(mouse-face t keymap t org-linked-text t
invisible t intangible t
org-no-flyspell t org-emphasis t))
(org-remove-font-lock-display-properties beg end)))
(defconst org-script-display '(((raise -0.3) (height 0.7))