PageRenderTime 51ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/site-lisp/common/fold/qtmstr-outline.el

https://github.com/fanhongtao/_emacs.d
Emacs Lisp | 263 lines | 211 code | 42 blank | 10 comment | 3 complexity | ea574730b9cb631681e15afebcd375ed MD5 | raw file
  1. (require 'foldout)
  2. (eval-when-compile
  3. (require 'cl))
  4. (defun qtmstr-outline-newline ()
  5. (interactive)
  6. (if (outline-on-heading-p)
  7. (outline-insert-heading)
  8. (newline-and-indent)))
  9. (defun qtmstr-outline-demote ()
  10. (interactive)
  11. (save-excursion
  12. (outline-back-to-heading)
  13. (outline-demote)))
  14. (defun qtmstr-outline-promote ()
  15. (interactive)
  16. (save-excursion
  17. (outline-back-to-heading)
  18. (outline-promote)))
  19. (defun qtmstr-outline-up-heading ()
  20. (interactive)
  21. (outline-up-heading (if (outline-on-heading-p) 1 0)))
  22. (defun qtmstr-outline-reveal-point ()
  23. "Ensure the point is visible"
  24. (save-excursion
  25. (when (ignore-errors (outline-back-to-heading t) t)
  26. (show-entry)
  27. (while (and (ignore-errors (outline-up-heading 1 t))
  28. (outline-on-heading-p))
  29. (show-children)))))
  30. (defun qtmstr-outline-toggle-children ()
  31. (interactive)
  32. (let ((saved-point (point)))
  33. (outline-back-to-heading)
  34. (outline-toggle-children)
  35. (when (<= saved-point (line-end-position))
  36. (goto-char saved-point))))
  37. (defun qtmstr-outline-show-top ()
  38. (interactive)
  39. (widen)
  40. (save-excursion
  41. (goto-char (point-min))
  42. (show-all)
  43. (outline-next-heading)
  44. (beginning-of-line)
  45. (hide-sublevels (funcall outline-level)))
  46. (when (outline-invisible-p)
  47. (goto-char (previous-single-char-property-change
  48. (point) 'invisible nil (point-min)))))
  49. (defun qtmstr-outline-post-command-hook ()
  50. (when (and (eq (get-char-property (point) 'invisible) 'outline)
  51. (not (bobp))
  52. (eq (get-char-property (1- (point)) 'invisible) 'outline)
  53. ;; Emacs called post-command-hook before adjusting the
  54. ;; point to be outside any "intangible" areas, including
  55. ;; invisible regions. If the last command was a movement,
  56. ;; we probably got moved into this area, and we'll be
  57. ;; moved out as soon as the post-command hooks finish.
  58. (not (and (symbolp this-command)
  59. (eq (get this-command 'CUA) 'move)))
  60. (not disable-point-adjustment)
  61. (not global-disable-point-adjustment))
  62. (qtmstr-outline-reveal-point)))
  63. (defun qtmstr-outline-define-keys ()
  64. (interactive)
  65. (define-key outline-mode-map "\r" #'qtmstr-outline-newline)
  66. (define-key outline-mode-map [(tab)] #'qtmstr-outline-demote)
  67. (define-key outline-mode-map [(backtab)] #'qtmstr-outline-promote)
  68. (setq minor-mode-map-alist
  69. (assq-delete-all 'outline-minor-mode minor-mode-map-alist))
  70. (setq outline-minor-mode-map (make-sparse-keymap))
  71. (define-key outline-minor-mode-map [menu-bar] outline-minor-mode-menu-bar-map)
  72. (define-key outline-minor-mode-map [left-fringe mouse-1] #'qtmstr-outline-fringe-click)
  73. (mapc #'(lambda (ent)
  74. (define-key outline-minor-mode-map
  75. (vector '(control ?c) ?f (car ent))
  76. (cdr ent)))
  77. '((?> . foldout-zoom-subtree)
  78. (?\r . foldout-zoom-subtree)
  79. (?< . foldout-exit-fold)
  80. (?a . show-all)
  81. (?u . qtmstr-outline-up-heading)
  82. (?s . show-subtree)
  83. (?w . qtmstr-outline-show-top)
  84. ((shift ?\t) . outline-previous-visible-heading)
  85. (?v . outline-previous-visible-heading)
  86. (?f . qtmstr-outline-toggle-children)
  87. (?\t . outline-next-visible-heading)
  88. (backtab . outline-previous-visible-heading)
  89. (left . foldout-exit-fold)
  90. (right . foldout-zoom-subtree)))
  91. (push (cons 'outline-minor-mode outline-minor-mode-map) minor-mode-map-alist))
  92. (eval-after-load "outline"
  93. '(progn
  94. (qtmstr-outline-define-keys)))
  95. (defvar qtmstr-outline-major-modes
  96. '(espresso-mode))
  97. (defun qtmstr-outline-find-file-hook ()
  98. (when (memq major-mode qtmstr-outline-major-modes)
  99. (outline-minor-mode 1)))
  100. (add-hook 'find-file-hooks #'qtmstr-outline-find-file-hook)
  101. (defun qtmstr-outline-on-header-click (e)
  102. (interactive "e")
  103. (let* ((position (nth 1 e))
  104. (window (nth 0 position))
  105. (pos (nth 1 position)))
  106. (with-selected-window window
  107. (goto-char pos)
  108. (qtmstr-outline-on-header-return)
  109. (goto-char pos))))
  110. (defun qtmstr-outline-fringe-click (e)
  111. (interactive "e")
  112. (mouse-set-point e)
  113. (let* ((position (nth 1 e))
  114. (window (nth 0 position))
  115. (text-pos (nth 5 position)))
  116. (with-selected-window window
  117. (goto-char text-pos)
  118. (when (outline-on-heading-p)
  119. (qtmstr-outline-on-header-return))
  120. ))
  121. )
  122. (defun qtmstr-outline-on-header-return ()
  123. (interactive)
  124. (save-excursion
  125. (outline-back-to-heading)
  126. (outline-toggle-children)))
  127. (defvar qtmstr-outline-header-map
  128. (progn (let ((km (make-sparse-keymap)))
  129. (define-key km [mouse-2] #'qtmstr-outline-on-header-click)
  130. (define-key km "\r" #'qtmstr-outline-on-header-return)
  131. km)))
  132. (fset 'qtmstr-outline-header-map qtmstr-outline-header-map)
  133. (defvar qtmstr-outline-overlay-open
  134. (propertize "▼"
  135. 'display '(when window-system left-fringe filled-square))
  136. "String displayed before a header line when it is open")
  137. (defvar qtmstr-outline-overlay-closed
  138. (propertize "▶"
  139. 'display '(when window-system left-fringe right-triangle))
  140. "String displayed before a header line when it is closed")
  141. (defun qtmstr-outline-fixup-overlay (o)
  142. "Set overlay style and behavior correctly depending on whether
  143. its children are shown or hidden. Overlay's bounds must be
  144. correct. Shoud not be called when buffer is narrowed."
  145. (assert (save-excursion (goto-char (overlay-start o))
  146. (outline-on-heading-p t)))
  147. (let ((end (overlay-end o)))
  148. (cond ((outline-invisible-p end)
  149. (overlay-put o 'help-echo "mouse-2: open this outline node")
  150. (overlay-put o 'before-string qtmstr-outline-overlay-closed))
  151. (t
  152. (overlay-put o 'help-echo "mouse-2: close this outline node")
  153. (overlay-put o 'before-string qtmstr-outline-overlay-open)))))
  154. (defface qtmstr-outline-header-face
  155. '((t :slant italic))
  156. "Face used for outline headings")
  157. (defun qtmstr-outline-add-overlay-at-point ()
  158. "Assuming point is at the beginning of an outline heading,
  159. add an overlay for this heading."
  160. (assert (outline-on-heading-p t))
  161. (let ((o (make-overlay (point) (point-at-eol) nil t)))
  162. (overlay-put o 'qtmstr-outline t)
  163. (overlay-put o 'evaporate t)
  164. (overlay-put o 'face 'qtmstr-outline-header-face)
  165. (overlay-put o 'mouse-face '(qtmstr-outline-header-face highlight))
  166. (overlay-put o 'pointer 'hand)
  167. (overlay-put o 'keymap 'qtmstr-outline-header-map)
  168. (overlay-put o 'follow-link t)
  169. (qtmstr-outline-fixup-overlay o)))
  170. (defun qtmstr-outline-after-change (beg end len)
  171. (save-match-data
  172. (save-excursion
  173. (save-restriction
  174. (widen)
  175. (goto-char end)
  176. (end-of-line)
  177. (setq end (point))
  178. (goto-char beg)
  179. (forward-line 0)
  180. (while (< (point) end)
  181. (remove-overlays (point) (point-at-eol) 'qtmstr-outline t)
  182. (when (looking-at outline-regexp)
  183. (qtmstr-outline-add-overlay-at-point))
  184. (forward-line 1))))))
  185. (defun qtmstr-outline-view-change ()
  186. (save-restriction
  187. (widen)
  188. (dolist (o (overlays-in (point-min) (point-max)))
  189. (when (overlay-get o 'qtmstr-outline)
  190. (qtmstr-outline-fixup-overlay o)))))
  191. (defun qtmstr-outline-add-overlays ()
  192. "Add overlays for outline headings"
  193. (add-hook 'after-change-functions #'qtmstr-outline-after-change t t)
  194. (add-hook 'post-command-hook #'qtmstr-outline-post-command-hook t t)
  195. (add-hook 'outline-view-change-hook #'qtmstr-outline-view-change t t)
  196. (let (overlay (re (concat "^\\(" outline-regexp ".*\\)$")))
  197. (save-excursion
  198. (save-restriction
  199. (widen)
  200. (goto-char (point-min))
  201. (while (re-search-forward re nil t)
  202. (save-excursion
  203. (goto-char (match-beginning 0))
  204. (qtmstr-outline-add-overlay-at-point)))))))
  205. (defun qtmstr-outline-remove-overlays ()
  206. (remove-hook 'after-change-functions #'qtmstr-outline-after-change t)
  207. (remove-hook 'post-command-hook #'qtmstr-outline-post-command-hook t)
  208. (save-restriction
  209. (widen)
  210. (remove-overlays nil nil 'qtmstr-outline t)))
  211. (defun qtmstr-outline-mode-hook ()
  212. (if outline-minor-mode
  213. (progn
  214. (qtmstr-outline-add-overlays))
  215. (qtmstr-outline-remove-overlays)))
  216. (add-hook 'outline-minor-mode-hook #'qtmstr-outline-mode-hook)
  217. ;;; Emacs
  218. ;; Local Variables:
  219. ;; outline-regexp: ";;; "
  220. ;; coding: utf-8
  221. ;; End: