Klimi's new dotfiles with stow.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

313 line
14 KiB

5 年之前
  1. ;;; highlight-indentation.el --- Minor modes for highlighting indentation
  2. ;; Author: Anton Johansson <anton.johansson@gmail.com> - http://antonj.se
  3. ;; Created: Dec 15 23:42:04 2010
  4. ;; Version: 0.7.0
  5. ;; Package-Version: 20181204.839
  6. ;; URL: https://github.com/antonj/Highlight-Indentation-for-Emacs
  7. ;;
  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 2 of
  11. ;; the License, or (at your option) any later version.
  12. ;;
  13. ;; This program is distributed in the hope that it will be
  14. ;; useful, but WITHOUT ANY WARRANTY; without even the implied
  15. ;; warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  16. ;; PURPOSE. See the GNU General Public License for more details.
  17. ;;
  18. ;;; Commentary:
  19. ;; Customize `highlight-indentation-face', and
  20. ;; `highlight-indentation-current-column-face' to suit your theme.
  21. ;;; Code:
  22. (defgroup highlight-indentation nil
  23. "Highlight Indentation"
  24. :prefix "highlight-indentation-"
  25. :group 'basic-faces)
  26. (defface highlight-indentation-face
  27. ;; Fringe has non intrusive color in most color-themes
  28. '((t :inherit fringe))
  29. "Basic face for highlighting indentation guides."
  30. :group 'highlight-indentation)
  31. (defcustom highlight-indentation-offset
  32. (if (and (boundp 'standard-indent) standard-indent) standard-indent 2)
  33. "Default indentation offset, used if no other can be found from
  34. major mode. This value is always used by
  35. `highlight-indentation-mode' if set buffer local. Set buffer
  36. local with `highlight-indentation-set-offset'"
  37. :type 'integer
  38. :group 'highlight-indentation)
  39. (defcustom highlight-indentation-blank-lines nil
  40. "Show indentation guides on blank lines. Experimental.
  41. Known issues:
  42. - Doesn't work well with completion popups that use overlays
  43. - Overlays on blank lines sometimes aren't cleaned up or updated perfectly
  44. Can be refershed by scrolling
  45. - Not yet implemented for highlight-indentation-current-column-mode
  46. - May not work perfectly near the bottom of the screen
  47. - Point appears after indent guides on blank lines"
  48. :group 'highlight-indentation)
  49. (defvar highlight-indentation-overlay-priority 1)
  50. (defvar highlight-indentation-current-column-overlay-priority 2)
  51. (defconst highlight-indentation-hooks
  52. '((after-change-functions (lambda (start end length)
  53. (highlight-indentation-redraw-region
  54. start end
  55. 'highlight-indentation-overlay
  56. 'highlight-indentation-put-overlays-region))
  57. t t)
  58. (window-scroll-functions (lambda (win start)
  59. (highlight-indentation-redraw-window
  60. win
  61. 'highlight-indentation-overlay
  62. 'highlight-indentation-put-overlays-region
  63. start))
  64. nil t)))
  65. (defun highlight-indentation-get-buffer-windows (&optional all-frames)
  66. "Return a list of windows displaying the current buffer."
  67. (get-buffer-window-list (current-buffer) 'no-minibuf all-frames))
  68. (defun highlight-indentation-delete-overlays-buffer (overlay)
  69. "Delete all overlays in the current buffer."
  70. (save-restriction
  71. (widen)
  72. (highlight-indentation-delete-overlays-region (point-min) (point-max) overlay)))
  73. (defun highlight-indentation-delete-overlays-region (start end overlay)
  74. "Delete overlays between START and END."
  75. (mapc #'(lambda (o)
  76. (if (overlay-get o overlay) (delete-overlay o)))
  77. (overlays-in start end)))
  78. (defun highlight-indentation-redraw-window (win overlay func &optional start)
  79. "Redraw win starting from START."
  80. (highlight-indentation-redraw-region (or start (window-start win)) (window-end win t) overlay func))
  81. (defun highlight-indentation-redraw-region (start end overlay func)
  82. "Erease and read overlays between START and END."
  83. (save-match-data
  84. (save-excursion
  85. (let ((inhibit-point-motion-hooks t)
  86. (start (save-excursion (goto-char start) (beginning-of-line) (point)))
  87. (end (save-excursion (goto-char end) (line-beginning-position 2))))
  88. (highlight-indentation-delete-overlays-region start end overlay)
  89. (funcall func start end overlay)))))
  90. (defun highlight-indentation-redraw-all-windows (overlay func &optional all-frames)
  91. "Redraw the all windows showing the current buffer."
  92. (dolist (win (highlight-indentation-get-buffer-windows all-frames))
  93. (highlight-indentation-redraw-window win overlay func)))
  94. (defun highlight-indentation-put-overlays-region (start end overlay)
  95. "Place overlays between START and END."
  96. (goto-char end)
  97. (let (o ;; overlay
  98. (last-indent 0)
  99. (last-char 0)
  100. (pos (point))
  101. (loop t))
  102. (while (and loop
  103. (>= pos start))
  104. (save-excursion
  105. (beginning-of-line)
  106. (let ((c 0)
  107. (cur-column (current-column)))
  108. (while (and (setq c (char-after))
  109. (integerp c)
  110. (not (= 10 c)) ;; newline
  111. (= 32 c)) ;; space
  112. (when (= 0 (% cur-column highlight-indentation-offset))
  113. (let ((p (point)))
  114. (setq o (make-overlay p (+ p 1))))
  115. (overlay-put o overlay t)
  116. (overlay-put o 'priority highlight-indentation-overlay-priority)
  117. (overlay-put o 'face 'highlight-indentation-face))
  118. (forward-char)
  119. (setq cur-column (current-column)))
  120. (when (and highlight-indentation-blank-lines
  121. (integerp c)
  122. (or (= 10 c)
  123. (= 13 c)))
  124. (when (< cur-column last-indent)
  125. (let ((column cur-column)
  126. (s nil)
  127. (show t)
  128. num-spaces)
  129. (while (< column last-indent)
  130. (if (>= 0
  131. (setq num-spaces
  132. (%
  133. (- last-indent column)
  134. highlight-indentation-offset)))
  135. (progn
  136. (setq num-spaces (1- highlight-indentation-offset))
  137. (setq show t))
  138. (setq show nil))
  139. (setq s (cons (concat
  140. (if show
  141. (propertize " "
  142. 'face
  143. 'highlight-indentation-face)
  144. "")
  145. (make-string num-spaces 32))
  146. s))
  147. (setq column (+ column num-spaces (if show 1 0))))
  148. (setq s (apply 'concat (reverse s)))
  149. (let ((p (point)))
  150. (setq o (make-overlay p p)))
  151. (overlay-put o overlay t)
  152. (overlay-put o 'priority highlight-indentation-overlay-priority)
  153. (overlay-put o 'after-string s))
  154. (setq cur-column last-indent)))
  155. (setq last-indent (* highlight-indentation-offset
  156. (ceiling (/ (float cur-column)
  157. highlight-indentation-offset))))))
  158. (when (= pos start)
  159. (setq loop nil))
  160. (forward-line -1) ;; previous line
  161. (setq pos (point)))))
  162. (defun highlight-indentation-guess-offset ()
  163. "Get indentation offset of current buffer."
  164. (cond ((and (eq major-mode 'python-mode) (boundp 'python-indent))
  165. python-indent)
  166. ((and (eq major-mode 'python-mode) (boundp 'py-indent-offset))
  167. py-indent-offset)
  168. ((and (eq major-mode 'python-mode) (boundp 'python-indent-offset))
  169. python-indent-offset)
  170. ((and (eq major-mode 'ruby-mode) (boundp 'ruby-indent-level))
  171. ruby-indent-level)
  172. ((and (eq major-mode 'scala-mode) (boundp 'scala-indent:step))
  173. scala-indent:step)
  174. ((and (eq major-mode 'scala-mode) (boundp 'scala-mode-indent:step))
  175. scala-mode-indent:step)
  176. ((and (or (eq major-mode 'scss-mode) (eq major-mode 'css-mode)) (boundp 'css-indent-offset))
  177. css-indent-offset)
  178. ((and (eq major-mode 'nxml-mode) (boundp 'nxml-child-indent))
  179. nxml-child-indent)
  180. ((and (eq major-mode 'coffee-mode) (boundp 'coffee-tab-width))
  181. coffee-tab-width)
  182. ((and (eq major-mode 'js-mode) (boundp 'js-indent-level))
  183. js-indent-level)
  184. ((and (eq major-mode 'js2-mode) (boundp 'js2-basic-offset))
  185. js2-basic-offset)
  186. ((and (fboundp 'derived-mode-class) (eq (derived-mode-class major-mode) 'sws-mode) (boundp 'sws-tab-width))
  187. sws-tab-width)
  188. ((and (eq major-mode 'web-mode) (boundp 'web-mode-markup-indent-offset))
  189. web-mode-markup-indent-offset) ; other similar vars: web-mode-{css-indent,scripts}-offset
  190. ((and (eq major-mode 'web-mode) (boundp 'web-mode-html-offset)) ; old var
  191. web-mode-html-offset)
  192. ((and (local-variable-p 'c-basic-offset) (boundp 'c-basic-offset))
  193. c-basic-offset)
  194. ((and (eq major-mode 'yaml-mode) (boundp 'yaml-indent-offset))
  195. yaml-indent-offset)
  196. ((and (eq major-mode 'elixir-mode) (boundp 'elixir-smie-indent-basic))
  197. elixir-smie-indent-basic)
  198. (t
  199. (default-value 'highlight-indentation-offset))))
  200. ;;;###autoload
  201. (define-minor-mode highlight-indentation-mode
  202. "Highlight indentation minor mode highlights indentation based on spaces"
  203. :lighter " ||"
  204. (when (not highlight-indentation-mode) ;; OFF
  205. (highlight-indentation-delete-overlays-buffer 'highlight-indentation-overlay)
  206. (dolist (hook highlight-indentation-hooks)
  207. (remove-hook (car hook) (nth 1 hook) (nth 3 hook))))
  208. (when highlight-indentation-mode ;; ON
  209. (when (not (local-variable-p 'highlight-indentation-offset))
  210. (set (make-local-variable 'highlight-indentation-offset)
  211. (highlight-indentation-guess-offset)))
  212. ;; Setup hooks
  213. (dolist (hook highlight-indentation-hooks)
  214. (apply 'add-hook hook))
  215. (highlight-indentation-redraw-all-windows 'highlight-indentation-overlay
  216. 'highlight-indentation-put-overlays-region)))
  217. ;;;###autoload
  218. (defun highlight-indentation-set-offset (offset)
  219. "Set indentation offset localy in buffer, will prevent
  220. highlight-indentation from trying to guess indentation offset
  221. from major mode"
  222. (interactive
  223. (if (and current-prefix-arg (not (consp current-prefix-arg)))
  224. (list (prefix-numeric-value current-prefix-arg))
  225. (list (read-number "Indentation offset: "))))
  226. (set (make-local-variable 'highlight-indentation-offset) offset)
  227. (when highlight-indentation-mode
  228. (highlight-indentation-mode)))
  229. ;;; This minor mode will highlight the indentation of the current line
  230. ;;; as a vertical bar (grey background color) aligned with the column of the
  231. ;;; first character of the current line.
  232. (defface highlight-indentation-current-column-face
  233. ;; Fringe has non intrusive color in most color-themes
  234. '((t (:background "black")))
  235. "Basic face for highlighting indentation guides."
  236. :group 'highlight-indentation)
  237. (defconst highlight-indentation-current-column-hooks
  238. '((post-command-hook (lambda ()
  239. (highlight-indentation-redraw-all-windows 'highlight-indentation-current-column-overlay
  240. 'highlight-indentation-current-column-put-overlays-region)) nil t)))
  241. (defun highlight-indentation-current-column-put-overlays-region (start end overlay)
  242. "Place overlays between START and END."
  243. (let (o ;; overlay
  244. (last-indent 0)
  245. (indent (save-excursion (back-to-indentation) (current-column)))
  246. (pos start))
  247. (goto-char start)
  248. ;; (message "doing it %d" indent)
  249. (while (< pos end)
  250. (beginning-of-line)
  251. (while (and (integerp (char-after))
  252. (not (= 10 (char-after))) ;; newline
  253. (= 32 (char-after))) ;; space
  254. (when (= (current-column) indent)
  255. (setq pos (point)
  256. last-indent pos
  257. o (make-overlay pos (+ pos 1)))
  258. (overlay-put o overlay t)
  259. (overlay-put o 'priority highlight-indentation-current-column-overlay-priority)
  260. (overlay-put o 'face 'highlight-indentation-current-column-face))
  261. (forward-char))
  262. (forward-line) ;; Next line
  263. (setq pos (point)))))
  264. ;;;###autoload
  265. (define-minor-mode highlight-indentation-current-column-mode
  266. "Hilight Indentation minor mode displays a vertical bar
  267. corresponding to the indentation of the current line"
  268. :lighter " |"
  269. (when (not highlight-indentation-current-column-mode) ;; OFF
  270. (highlight-indentation-delete-overlays-buffer 'highlight-indentation-current-column-overlay)
  271. (dolist (hook highlight-indentation-current-column-hooks)
  272. (remove-hook (car hook) (nth 1 hook) (nth 3 hook))))
  273. (when highlight-indentation-current-column-mode ;; ON
  274. (when (not (local-variable-p 'highlight-indentation-offset))
  275. (set (make-local-variable 'highlight-indentation-offset)
  276. (highlight-indentation-guess-offset)))
  277. ;; Setup hooks
  278. (dolist (hook highlight-indentation-current-column-hooks)
  279. (apply 'add-hook hook))
  280. (highlight-indentation-redraw-all-windows 'highlight-indentation-current-column-overlay
  281. 'highlight-indentation-current-column-put-overlays-region)))
  282. (provide 'highlight-indentation)
  283. ;;; highlight-indentation.el ends here