123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- ;;; org-indent.el --- Dynamic indentation for Org-mode
- ;; Copyright (C) 2008 Free Software Foundation, Inc.
- ;;
- ;; Author: Carsten Dominik <carsten at orgmode dot org>
- ;; Keywords: outlines, hypermedia, calendar, wp
- ;; Homepage: http://orgmode.org
- ;; Version: 0.07
- ;;
- ;; This file is not part of GNU Emacs.
- ;;
- ;; This file is free software; you can redistribute it and/or modify
- ;; it under the terms of the GNU General Public License as published by
- ;; the Free Software Foundation; either version 3, or (at your option)
- ;; any later version.
- ;; GNU Emacs is distributed in the hope that it will be useful,
- ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
- ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ;; GNU General Public License for more details.
- ;; You should have received a copy of the GNU General Public License
- ;; along with GNU Emacs; see the file COPYING. If not, write to the
- ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- ;; Boston, MA 02110-1301, USA.
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;
- ;;; Commentary:
- ;; This is an experimental implementation of dynamic virtual indentation.
- ;; It works by adding overlays to a buffer to make sure lines are
- ;; indented according to outline structure. While this works, there are
- ;; problems with the implementation: It uses overlays, which use markers,
- ;; and for large files, this is using too much resources. It might be
- ;; possible to com up with an implementation using text properties,
- ;; I believe this is less resource intensive. However, it does not work
- ;; to put the text property onto the newline, because that interferes with
- ;; outline visibility. Maybe this is a bug in outline?
- ;;; Indentation
- (defcustom org-startup-indented nil
- "Non-nil means, turn on `org-indent-mode' on startup.
- This can also be configured on a per-file basis by adding one of
- the following lines anywhere in the buffer:
- #+STARTUP: localindent
- #+STARTUP: indent
- #+STARTUP: noindent"
- :group 'org-structure
- :type '(choice
- (const :tag "Not" nil)
- (const :tag "Locally" local)
- (const :tag "Globally (slow on startup in large files)" t)))
- (defconst org-indent-max 80
- "Maximum indentation in characters")
- (defconst org-indent-strings nil
- "Vector with all indentation strings.
- It is a const because it will be set only once in `org-indent-initialize'.")
- (defvar org-indent-inhibit-after-change nil
- "Inhibit the action of the indentation after-change-hook.
- This variable should be scoped dynamically.")
- (defcustom org-indent-boundary-char ?\ ; comment to protect space char
- "The end of the virtual indentation strings, a single-character string.
- The default is just a space, but if you wish, you can use \"|\" or so."
- :group 'org-structure
- :set (lambda (var val)
- (set var val)
- (and org-indent-strings (org-indent-initialize)))
- :type 'character)
- (defun org-indent-initialize ()
- "Initialize the indentation strings and set the idle times."
- (unless org-indent-strings
- ; (run-with-idle-timer 10 t 'org-indent-indent-buffer)
- (run-with-idle-timer 0.5 t 'org-indent-refresh-section)
- )
- (setq org-indent-strings (make-vector (1+ org-indent-max) nil))
- ;; Initialize the indentation strings
- (aset org-indent-strings 0 "")
- (loop for i from 1 to org-indent-max do
- (aset org-indent-strings i
- (org-add-props
- (concat (make-string (1- i) ?\ )
- (char-to-string org-indent-boundary-char))
- nil 'face 'org-indent))))
- (define-minor-mode org-indent-mode
- "Toggle the minor more `org-indent-mode'."
- nil " Ind" nil
- (if (org-bound-and-true-p org-inhibit-startup)
- (setq org-indent-mode nil)
- (if org-indent-mode
- (progn
- (or org-indent-strings (org-indent-initialize))
- (org-set-local 'org-adapt-indentation nil)
- (org-add-hook 'after-change-functions
- 'org-indent-after-change-function nil t)
- (org-restart-font-lock)
- (org-indent-indent-buffer))
- (save-excursion
- (save-restriction
- (org-indent-remove-overlays (point-min) (point-max))
- (remove-hook 'after-change-functions
- 'org-indent-after-change-function 'local)
- (kill-local-variable 'org-adapt-indentation))))))
- (defface org-indent
- (org-compatible-face nil
- '((((class color) (min-colors 16) (background dark)
- (:underline nil :strike-through nil :foreground "grey10")))
- (((class color) (min-colors 16) (background light))
- (:underline nil :strike-through nil :foreground "grey90"))
- (t (:underline nil :strike-through nil))))
- "Face for outline indentation.
- The default is to make it look like whitespace. But you may find it
- useful to make it, for example, look like the fringes."
- :group 'org-faces)
- (defun org-indent-indent-buffer ()
- "Add indentation overlays for the whole buffer."
- (interactive)
- (when org-indent-mode
- (save-excursion
- (save-restriction
- (org-indent-remove-overlays (point-min) (point-max))
- (org-indent-add-overlays (point-min) (point-max))))))
- (defun org-indent-remove-overlays (beg end)
- "Remove indentations between BEG and END."
- (mapc (lambda (o)
- (and (org-overlay-get o 'org-indent)
- (org-delete-overlay o)))
- (org-overlays-in beg end)))
- (defun org-indent-add-overlays (beg end &optional n)
- "Add indentation overlays between BEG and END.
- Assumes that BEG is at the beginning of a line."
- (when org-indent-mode
- (let (o)
- (save-excursion
- (goto-char beg)
- (while (and (<= (point) end) (not (eobp)))
- (cond
- ((not (bolp)))
- ((looking-at outline-regexp)
- (setq n (- (match-end 0) (match-beginning 0)))
- (org-indent-remove-overlays (max (point-min) (1- (point))) (point)))
- (n
- (org-indent-indent-line n)))
- (beginning-of-line 2))))))
- (defun org-indent-indent-line (n)
- "Add an indentation overlay with width N to the current line.
- Point is assumed to be at the beginning of the line for this."
- (let (ov)
- (setq ov (org-make-overlay (1- (point)) (point)))
- (org-overlay-put ov 'after-string (aref org-indent-strings n))
- (org-overlay-put ov 'evaporate t)
- (org-overlay-put ov 'org-indent n)
- (org-unmodified
- (put-text-property (max (point-min) (1- (point)))
- (point-at-eol) 'org-indent-level n))))
- (defun org-indent-after-change-function (beg end ndel)
- (if (or (not org-indent-mode) (= beg end)
- org-indent-inhibit-after-change)
- () ; not in the mood to do anything here....
- (let ((inhibit-quit t) n)
- (save-match-data
- (save-excursion
- (save-restriction
- (widen)
- (goto-char beg)
- (when (search-forward "\n" end t)
- ;; a newline was inserted
- (setq n (or (get-text-property beg 'org-indent-level)
- (get-text-property
- (or (save-excursion (previous-single-property-change
- beg 'org-indent-level))
- (point-min))
- 'org-indent-level)
- 0))
- (org-indent-local-refresh beg end n))))))))
- (defun org-indent-local-refresh (beg end n)
- "Refresh indentation locally from BEG to END, starting with indentation N."
- (goto-char end)
- (setq end (min (point-max) (1+ (point-at-eol))))
- (goto-char beg)
- (beginning-of-line 0)
- (org-indent-remove-overlays (max (point-min) (1- (point))) end)
- (org-indent-add-overlays (point) end n))
- (defun org-indent-refresh-section ()
- "Refresh indentation overlays in the current outline subtree."
- (when org-indent-mode
- (save-excursion
- (let ((org-indent-inhibit-after-change t)
- beg end)
- (condition-case nil
- (progn
- (outline-back-to-heading t)
- (setq beg (point)))
- (error (progn
- (goto-char (point-min))
- (setq beg (point)))))
- (outline-next-heading)
- (setq end (point))
- (org-indent-remove-overlays beg end)
- (org-indent-add-overlays beg end)))))
- (defun org-indent-refresh-subtree ()
- "Refresh indentation overlays in the current outline subtree."
- (when org-indent-mode
- (save-excursion
- (let ((org-indent-inhibit-after-change t)
- beg end)
- (setq beg (point))
- (setq end (save-excursion (org-end-of-subtree t t)))
- (org-indent-remove-overlays beg end)
- (org-indent-add-overlays beg end)))))
- (provide 'org-indent)
- ;;; org-indent.el ends here
|