5026cbe9be419c39e0751755424f19ebd7a6320f
[gnu-emacs-elpa] / packages / num3-mode / num3-mode.el
1 ;;; num3-mode.el --- highlight groups of digits in long numbers -*- lexical-binding: t -*-
2
3 ;; Copyright (C) 2012, 2014 Free Software Foundation, Inc.
4
5 ;; Author: Felix Lee <felix8a@gmail.com>, Michal Nazarewicz <mina86@mina86.com>
6 ;; Maintainer: Michal Nazarewicz <mina86@mina86.com>
7 ;; Keywords: faces, minor-mode
8 ;; Version: 1.2
9
10 ;; GNU Emacs is free software: you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation, either version 3 of the License, or
13 ;; (at your option) any later version.
14
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
19
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
22
23 ;;; Commentary:
24
25 ;; Num3 is a minor mode that makes long numbers more readable by
26 ;; highlighting groups of 3 (customisable) decimal digits or 4 hex
27 ;; digits when font-lock is on. Highlighting alternates between two
28 ;; faces that can be customised.
29
30 ;;; Usage:
31
32 ;; M-x num3-mode toggle for current buffer.
33 ;; M-x global-num3-mode toggle for all buffers.
34 ;;
35 ;; Or add the following to your ~/.emacs file:
36 ;; (load "path/to/num3")
37 ;; (global-num3-mode)
38
39 ;;; Code:
40
41 (defgroup num3 nil
42 "Num3 is a minor mode that makes long numbers more readable by
43 highlighting groups of decimal digits or 4 hex digits when
44 font-lock is on."
45 :group 'text)
46
47 (defcustom num3-group-size 3
48 "Number of digits to group in decimal numbers.")
49
50 (defcustom num3-threshold 5
51 "Number must be at least that long to start highlighting.")
52
53 (defface num3-face-odd
54 '((t))
55 "Face to add for odd groups of digits."
56 :group 'num3)
57
58 (defface num3-face-even
59 '((t :underline t :weight bold :background "#eeeeee"))
60 "Face to add for even groups of digits.
61 The default face uses redundant signaling, because this is in
62 addition to any other font-lock highlighting."
63 :group 'num3)
64
65 ;;; Implementation:
66
67 ;;;###autoload
68 (define-minor-mode num3-mode
69 "Toggle num3 minor mode in the current buffer.
70 Num3 minor mode makes long numbers more readable by highlighting
71 groups of digits when font-lock mode is on.
72
73 If a number is longer than `num3-threshold', the mode will split
74 it into a group of `num3-group-size' (if number is decimal) or
75 4 (if number is hexadecimal) digits. Hexadecimal number is
76 detected as one starting with 0x, 0X or #.
77
78 With decimal numbers, fractions are recognised as well and
79 grouped from the beginning rathar then from end. For instance,
80 with group size of 3, a number \"12345.12345\" will be split into
81 groups as follows: \"12|345.123|45\". Fractions without integer
82 part are also recognised, eg. \".12345\".
83
84 The groups are highlighted alternately using `num3-face-odd' and
85 `num3-face-even' faces. `num3-face-odd' face (which is empty by
86 default) is the one used for the group closest to the decimal point,
87 ie. groups are counted starting with one outwards from the (place
88 where) decimal point (would be) is."
89 nil " num3" nil
90 (if num3-mode
91 (unless (assoc 'num3--matcher font-lock-keywords)
92 (font-lock-add-keywords nil '(num3--matcher) 'append))
93 (font-lock-remove-keywords nil '(num3--matcher)))
94 (if (fboundp 'font-lock-flush) (font-lock-flush)
95 (when font-lock-mode (font-lock-fontify-buffer))))
96
97 ;;;###autoload
98 (define-globalized-minor-mode global-num3-mode num3-mode num3-mode)
99
100 (defconst num3--number-re
101 (concat "[0#][xX]\\([[:xdigit:]]+\\)" ; 1 = hexadecimal
102 "\\|\\(?1:\\b\\(?:[0-9]+[a-fA-F]\\|" ; 1 = hexadecimal
103 "[a-fA-F]+[0-9]\\)[[:xdigit:]]*\\b\\)"
104 "\\|\\([0-9]+\\)" ; 2 = decimal
105 "\\|\\.\\([0-9]+\\)")) ; 3 = fraction
106
107 (defun num3--matcher (lim)
108 "Function used as a font-lock-keywoard handler used in `num3-mode'.
109 Performs fontification of numbers from point to LIM."
110 (save-excursion
111 (while (re-search-forward num3--number-re lim t)
112 (num3--int (match-beginning 1) (match-end 1) 4)
113 (num3--int (match-beginning 2) (match-end 2) num3-group-size)
114 (num3--frac (match-beginning 3) (match-end 3) num3-group-size)))
115 nil)
116
117 (defun num3--int (lo hi n)
118 "Highlight groups of digits in a long number.
119 LO and HI arguments specify the range where the number is
120 located. If the length of that region exceeds `num3-threshold',
121 the function will split it into groups of N digits and fontify
122 tham alternately using `num3-face-odd' and `num3-face-even'
123 faces. Grouping is done from the end, eg. (12)(345)."
124 (when (and lo (>= (- hi lo) num3-threshold))
125 (let (even)
126 (while (< lo hi)
127 (num3--put even (max lo (- hi n)) hi)
128 (setq hi (- hi n) even (not even))))))
129
130 (defun num3--frac (lo hi n)
131 "Highlight groups of digits in a long number.
132 LO and HI arguments specify the range where the number is
133 located. If the length of that region exceeds `num3-threshold',
134 the function will split it into groups of N digits and fontify
135 tham alternately using `num3-face-odd' and `num3-face-even'
136 faces. Grouping is done from the beginning, eg. (123)(45)."
137 (when (and lo (>= (- hi lo) num3-threshold))
138 (let (even)
139 (while (< lo hi)
140 (num3--put even lo (min hi (+ lo n)))
141 (setq lo (+ lo n) even (not even))))))
142
143 (defun num3--put (even lo hi)
144 "Add font lock text property to highlight a single group of digit.
145 Use `num3-face-odd' if EVEN is nil and `num3-face-even' if EVEN is
146 non-nil. The region the face is set to is from LO to HI."
147 (font-lock-append-text-property lo hi 'face
148 (if even 'num3-face-even 'num3-face-odd)))
149
150 (provide 'num3-mode)
151 ;;; num3-mode.el ends here