1 ;;; org-bullets.el --- Show bullets in org-mode as UTF-8 characters
4 ;;; URL: https://github.com/sabof/org-bullets
6 ;; This file is NOT part of GNU Emacs.
8 ;; This program is free software; you can redistribute it and/or
9 ;; modify it under the terms of the GNU General Public License as
10 ;; published by the Free Software Foundation; either version 3, or (at
11 ;; your option) any later version.
13 ;; This program is distributed in the hope that it will be useful, but
14 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 ;; General Public License for more details.
18 ;; You should have received a copy of the GNU General Public License
19 ;; along with this program ; see the file COPYING. If not, write to
20 ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 ;; Boston, MA 02111-1307, USA.
25 ;; The project is hosted at https://github.com/sabof/org-bullets
26 ;; The latest version, and all the relevant information can be found there.
30 (eval-when-compile (require 'cl
))
32 (defgroup org-bullets nil
33 "Use different background for even and odd lines."
34 :group
'org-appearance
)
36 ;; A nice collection of unicode bullets:
37 ;; http://nadeausoftware.com/articles/2007/11/latency_friendly_customized_bullets_using_unicode_characters
38 (defcustom org-bullets-bullet-list
44 ;; ♥ ● ◇ ✚ ✜ ☯ ◆ ♠ ♣ ♦ ☢ ❀ ◆ ◖ ▶
48 "This variable contains the list of bullets.
49 It can contain any number of symbols, which will be repeated."
51 :type
'(repeat (string :tag
"Bullet character")))
53 (defvar org-bullet-overlays nil
)
54 (make-variable-buffer-local 'org-bullet-overlays
)
56 (defvar org-bullets-changes nil
)
57 (make-variable-buffer-local 'org-bullets-changes
)
59 (defun org-bullets-match-length ()
60 (- (match-end 0) (match-beginning 0)))
62 (defun org-bullets-make-star (bullet-string counter
)
65 (mouse-2 .
(lambda (e)
73 (intern (concat "org-level-"
75 (1+ (mod (1- (org-bullets-match-length))
77 (overlay (make-overlay (point)
79 (overlay-put overlay
'display
81 (propertize bullet-string
86 (overlay-put overlay
'is-bullet t
)
87 (push overlay org-bullet-overlays
)))
89 (defun org-bullets-clear ()
90 (mapc 'delete-overlay org-bullet-overlays
)
91 (setq org-bullet-overlays nil
))
93 (defun* org-bullets-redraw
(&optional
(beginning (point-min)) (end (point-max)))
98 (lambda (overlay) (overlay-get overlay
'is-bullet
))
99 (overlays-in beginning end
)))
100 (goto-char beginning
)
101 (while (and (re-search-forward "^\\*+" nil t
)
103 (let* ((bullet-string (nth (mod (1- (org-bullets-match-length))
104 (list-length org-bullets-bullet-list
))
105 org-bullets-bullet-list
)))
106 (goto-char (match-beginning 0))
107 (if (save-match-data (looking-at "^\\*+ "))
108 (let ((counter (1- (org-bullets-match-length))))
109 (while (looking-at "[* ]")
110 (org-bullets-make-star bullet-string counter
)
113 (goto-char (match-end 0)))
116 (defun org-bullets-notify-change (&rest args
)
117 (push args org-bullets-changes
))
119 (defun* org-bullets-post-command-hook
(&rest ignore
)
120 (unless org-bullets-changes
121 (return-from org-bullets-post-command-hook
))
122 (let ((min (reduce 'min org-bullets-changes
:key
'first
))
123 (max (reduce 'max org-bullets-changes
:key
'second
)))
124 (org-bullets-redraw (save-excursion
126 (line-beginning-position))
130 (line-end-position))))
131 (setq org-bullets-changes nil
))
136 (define-minor-mode org-bullets-mode
137 "UTF8 Bullets for org-mode"
141 (add-hook 'after-change-functions
'org-bullets-notify-change nil t
)
142 (add-hook 'post-command-hook
'org-bullets-post-command-hook nil t
)
143 (org-bullets-redraw))
144 (remove-hook 'after-change-functions
'org-bullets-notify-change t
)
145 (remove-hook 'post-command-hook
'org-bullets-post-command-hook t
)
146 (mapc 'delete-overlay org-bullet-overlays
)))
148 (provide 'org-bullets
)
150 ;;; org-bullets.el ends here