ledger-fontify.el 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. ;;; ledger-fontify.el --- Provide custom fontification for ledger-mode
  2. ;; Copyright (C) 2014 Craig P. Earls (enderw88 at gmail dot com)
  3. ;; This file is not part of GNU Emacs.
  4. ;; This is free software; you can redistribute it and/or modify it under
  5. ;; the terms of the GNU General Public License as published by the Free
  6. ;; Software Foundation; either version 2, or (at your option) any later
  7. ;; version.
  8. ;;
  9. ;; This is distributed in the hope that it will be useful, but WITHOUT
  10. ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11. ;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  12. ;; for more details.
  13. ;;
  14. ;; You should have received a copy of the GNU General Public License
  15. ;; along with GNU Emacs; see the file COPYING. If not, write to the
  16. ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  17. ;; MA 02110-1301 USA.
  18. ;;; Commentary:
  19. ;; Font-lock-mode doesn't handle multiline syntax very well. This
  20. ;; code provides font lock that is sensitive to overall transaction
  21. ;; states
  22. ;;; Code:
  23. (require 'ledger-navigate)
  24. (require 'ledger-regex)
  25. (require 'ledger-state)
  26. (defcustom ledger-fontify-xact-state-overrides nil
  27. "If t the highlight entire xact with state."
  28. :type 'boolean
  29. :group 'ledger)
  30. (defun ledger-fontify-buffer-part (&optional beg end len)
  31. "Fontify buffer from BEG to END, length LEN."
  32. (save-excursion
  33. (unless beg (setq beg (point-min)))
  34. (unless end (setq end (point-max)))
  35. (goto-char beg)
  36. (beginning-of-line)
  37. (while (< (point) end)
  38. (cond ((or (looking-at ledger-xact-start-regex)
  39. (looking-at ledger-posting-regex)
  40. (looking-at ledger-recurring-line-regexp))
  41. (ledger-fontify-xact-at (point)))
  42. ((looking-at ledger-directive-start-regex)
  43. (ledger-fontify-directive-at (point))))
  44. (ledger-navigate-next-xact-or-directive))))
  45. (defun ledger-fontify-xact-at (position)
  46. "Fontify the xact at POSITION."
  47. (interactive "d")
  48. (save-excursion
  49. (goto-char position)
  50. (let ((extents (ledger-navigate-find-element-extents position))
  51. (state (ledger-transaction-state)))
  52. (if (and ledger-fontify-xact-state-overrides state)
  53. (cond ((eq state 'cleared)
  54. (ledger-fontify-set-face extents 'ledger-font-xact-cleared-face))
  55. ((eq state 'pending)
  56. (ledger-fontify-set-face extents 'ledger-font-xact-pending-face)))
  57. (ledger-fontify-xact-by-line extents)))))
  58. (defun ledger-fontify-xact-by-line (extents)
  59. "Do line-by-line detailed fontification of xact in EXTENTS."
  60. (save-excursion
  61. (ledger-fontify-xact-start (car extents))
  62. (while (< (point) (cadr extents))
  63. (if (looking-at "[ \t]+;")
  64. (ledger-fontify-set-face (list (point) (progn
  65. (end-of-line)
  66. (point))) 'ledger-font-comment-face)
  67. (ledger-fontify-posting (point)))
  68. (forward-line))))
  69. (defun ledger-fontify-xact-start (pos)
  70. "POS should be at the beginning of a line starting an xact.
  71. Fontify the first line of an xact"
  72. (goto-char pos)
  73. (let ((line-start (line-beginning-position)))
  74. (goto-char line-start)
  75. (re-search-forward "[ \t]")
  76. (ledger-fontify-set-face (list line-start (match-beginning 0)) 'ledger-font-posting-date-face)
  77. (goto-char line-start)
  78. (re-search-forward ledger-xact-after-date-regex)
  79. (let ((state (save-match-data (ledger-state-from-string (match-string 1)))))
  80. (ledger-fontify-set-face (list (match-beginning 3) (match-end 3))
  81. (cond ((eq state 'pending)
  82. 'ledger-font-payee-pending-face)
  83. ((eq state 'cleared)
  84. 'ledger-font-payee-cleared-face)
  85. (t
  86. 'ledger-font-payee-uncleared-face))))
  87. (when (match-beginning 4)
  88. (ledger-fontify-set-face (list (match-beginning 4)
  89. (match-end 4)) 'ledger-font-comment-face))
  90. (forward-line)))
  91. (defun ledger-fontify-posting (pos)
  92. "Fontify the posting at POS."
  93. (let* ((state nil)
  94. (end-of-line-comment nil)
  95. (end (progn (end-of-line)
  96. (point)))
  97. (start (progn (beginning-of-line)
  98. (point))))
  99. ;; Look for a posting status flag
  100. (set-match-data nil 'reseat)
  101. (re-search-forward " \\([*!]\\) " end t)
  102. (if (match-string 1)
  103. (setq state (ledger-state-from-string (match-string 1))))
  104. (beginning-of-line)
  105. (re-search-forward "[[:graph:]]\\([ \t][ \t]\\)" end 'end) ;; find the end of the account, or end of line
  106. (when (<= (point) end) ;; we are still on the line
  107. (ledger-fontify-set-face (list start (point))
  108. (cond ((eq state 'cleared)
  109. 'ledger-font-posting-account-cleared-face)
  110. ((eq state 'pending)
  111. 'ledger-font-posting-account-pending-face)
  112. (t
  113. 'ledger-font-posting-account-face)))
  114. (when (< (point) end) ;; there is still more to fontify
  115. (setq start (point)) ;; update start of next font region
  116. (setq end-of-line-comment (re-search-forward ";" end 'end)) ;; find the end of the line, or start of a comment
  117. (ledger-fontify-set-face (list start (point) )
  118. (cond ((eq state 'cleared)
  119. 'ledger-font-posting-amount-cleared-face)
  120. ((eq state 'pending)
  121. 'ledger-font-posting-amount-pending-face)
  122. (t
  123. 'ledger-font-posting-amount-face)))
  124. (when end-of-line-comment
  125. (setq start (point))
  126. (end-of-line)
  127. (ledger-fontify-set-face (list (- start 1) (point)) ;; subtract 1 from start because we passed the semi-colon
  128. 'ledger-font-comment-face))))))
  129. (defun ledger-fontify-directive-at (pos)
  130. "Fontify the directive at POS."
  131. (let ((extents (ledger-navigate-find-element-extents pos))
  132. (face 'ledger-font-default-face))
  133. (cond ((looking-at "=")
  134. (setq face 'ledger-font-auto-xact-face))
  135. ((looking-at "~")
  136. (setq face 'ledger-font-periodic-xact-face))
  137. ((looking-at "[;#%|\\*]")
  138. (setq face 'ledger-font-comment-face))
  139. ((looking-at "\\(year\\)\\|Y")
  140. (setq face 'ledger-font-year-directive-face))
  141. ((looking-at "account")
  142. (setq face 'ledger-font-account-directive-face))
  143. ((looking-at "apply")
  144. (setq face 'ledger-font-apply-directive-face))
  145. ((looking-at "alias")
  146. (setq face 'ledger-font-alias-directive-face))
  147. ((looking-at "assert")
  148. (setq face 'ledger-font-assert-directive-face))
  149. ((looking-at "\\(bucket\\)\\|A")
  150. (setq face 'ledger-font-bucket-directive-face))
  151. ((looking-at "capture")
  152. (setq face 'ledger-font-capture-directive-face))
  153. ((looking-at "check")
  154. (setq face 'ledger-font-check-directive-face))
  155. ((looking-at "commodity")
  156. (setq face 'ledger-font-commodity-directive-face))
  157. ((looking-at "define")
  158. (setq face 'ledger-font-define-directive-face))
  159. ((looking-at "end")
  160. (setq face 'ledger-font-end-directive-face))
  161. ((looking-at "expr")
  162. (setq face 'ledger-font-expr-directive-face))
  163. ((looking-at "fixed")
  164. (setq face 'ledger-font-fixed-directive-face))
  165. ((looking-at "include")
  166. (setq face 'ledger-font-include-directive-face))
  167. ((looking-at "payee")
  168. (setq face 'ledger-font-payee-directive-face))
  169. ((looking-at "P")
  170. (setq face 'ledger-font-price-directive-face))
  171. ((looking-at "tag")
  172. (setq face 'ledger-font-tag-directive-face)))
  173. (ledger-fontify-set-face extents face)))
  174. (defun ledger-fontify-set-face (extents face)
  175. "Set the text in EXTENTS to FACE."
  176. (put-text-property (car extents) (cadr extents) 'face face))
  177. (provide 'ledger-fontify)
  178. ;;; ledger-fontify.el ends here