org-bullets.el 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. ;;; org-bullets.el --- Show bullets in org-mode as UTF-8 characters
  2. ;;; Version: 0.1
  3. ;;; Author: sabof
  4. ;;; URL: https://github.com/sabof/org-bullets
  5. ;; This file is NOT part of GNU Emacs.
  6. ;;
  7. ;; This program is free software; you can redistribute it and/or
  8. ;; modify it under the terms of the GNU General Public License as
  9. ;; published by the Free Software Foundation; either version 3, or (at
  10. ;; your option) any later version.
  11. ;;
  12. ;; This program is distributed in the hope that it will be useful, but
  13. ;; WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. ;; General Public License for more details.
  16. ;;
  17. ;; You should have received a copy of the GNU General Public License
  18. ;; along with this program ; see the file COPYING. If not, write to
  19. ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  20. ;; Boston, MA 02111-1307, USA.
  21. ;;; Commentary:
  22. ;; The project is hosted at https://github.com/sabof/org-bullets
  23. ;; The latest version, and all the relevant information can be found there.
  24. ;;; Code:
  25. (eval-when-compile (require 'cl))
  26. (defgroup org-bullets nil
  27. "Use different background for even and odd lines."
  28. :group 'org-appearance)
  29. ;; A nice collection of unicode bullets:
  30. ;; http://nadeausoftware.com/articles/2007/11/latency_friendly_customized_bullets_using_unicode_characters
  31. (defcustom org-bullets-bullet-list
  32. '(;;; Large
  33. "◉"
  34. "○"
  35. "✸"
  36. "✿"
  37. ;; ♥ ● ◇ ✚ ✜ ☯ ◆ ♠ ♣ ♦ ☢ ❀ ◆ ◖ ▶
  38. ;;; Small
  39. ;; ► • ★ ▸
  40. )
  41. "This variable contains the list of bullets.
  42. It can contain any number of symbols, which will be repeated."
  43. :group 'org-bullets
  44. :type '(repeat (string :tag "Bullet character")))
  45. (defvar org-bullet-overlays nil)
  46. (make-variable-buffer-local 'org-bullet-overlays)
  47. (defvar org-bullets-changes nil)
  48. (make-variable-buffer-local 'org-bullets-changes)
  49. (defun org-bullets-match-length ()
  50. (- (match-end 0) (match-beginning 0)))
  51. (defun org-bullets-make-star (bullet-string counter)
  52. (let* ((map '(keymap
  53. (mouse-1 . org-cycle)
  54. (mouse-2 . (lambda (e)
  55. (interactive "e")
  56. (mouse-set-point e)
  57. (org-cycle)))))
  58. (face (save-excursion
  59. (save-match-data
  60. (beginning-of-line)
  61. (looking-at "\\*+")
  62. (intern (concat "org-level-"
  63. (int-to-string
  64. (1+ (mod (1- (org-bullets-match-length))
  65. 8))))))))
  66. (overlay (make-overlay (point)
  67. (1+ (point)))))
  68. (overlay-put overlay 'display
  69. (if (zerop counter)
  70. (propertize bullet-string
  71. 'face face
  72. 'local-map map)
  73. (propertize " "
  74. 'local-map map)))
  75. (overlay-put overlay 'is-bullet t)
  76. (push overlay org-bullet-overlays)))
  77. (defun org-bullets-clear ()
  78. (mapc 'delete-overlay org-bullet-overlays)
  79. (setq org-bullet-overlays nil))
  80. (defun* org-bullets-redraw (&optional (beginning (point-min)) (end (point-max)))
  81. (save-excursion
  82. (save-match-data
  83. (mapc 'delete-overlay
  84. (remove-if-not
  85. (lambda (overlay) (overlay-get overlay 'is-bullet))
  86. (overlays-in beginning end)))
  87. (goto-char beginning)
  88. (while (and (re-search-forward "^\\*+" nil t)
  89. (<= (point) end))
  90. (let* ((bullet-string (nth (mod (1- (org-bullets-match-length))
  91. (list-length org-bullets-bullet-list))
  92. org-bullets-bullet-list)))
  93. (goto-char (match-beginning 0))
  94. (if (save-match-data (looking-at "^\\*+ "))
  95. (let ((counter (1- (org-bullets-match-length))))
  96. (while (looking-at "[* ]")
  97. (org-bullets-make-star bullet-string counter)
  98. (forward-char)
  99. (decf counter)))
  100. (goto-char (match-end 0)))
  101. )))))
  102. (defun org-bullets-notify-change (&rest args)
  103. (push args org-bullets-changes))
  104. (defun* org-bullets-post-command-hook (&rest ignore)
  105. (unless org-bullets-changes
  106. (return-from org-bullets-post-command-hook))
  107. (let ((min (reduce 'min org-bullets-changes :key 'first))
  108. (max (reduce 'max org-bullets-changes :key 'second)))
  109. (org-bullets-redraw (save-excursion
  110. (goto-char min)
  111. (line-beginning-position))
  112. (save-excursion
  113. (goto-char max)
  114. (forward-line)
  115. (line-end-position))))
  116. (setq org-bullets-changes nil))
  117. ;;; Interface
  118. ;;;###autoload
  119. (define-minor-mode org-bullets-mode
  120. "UTF8 Bullets for org-mode"
  121. nil nil nil
  122. (if org-bullets-mode
  123. (progn
  124. (add-hook 'after-change-functions 'org-bullets-notify-change nil t)
  125. (add-hook 'post-command-hook 'org-bullets-post-command-hook nil t)
  126. (org-bullets-redraw))
  127. (remove-hook 'after-change-functions 'org-bullets-notify-change t)
  128. (remove-hook 'post-command-hook 'org-bullets-post-command-hook t)
  129. (mapc 'delete-overlay org-bullet-overlays)))
  130. (provide 'org-bullets)
  131. ;;; org-bullets.el ends here