-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathenumerate.el
executable file
·130 lines (110 loc) · 5.12 KB
/
enumerate.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
;;; enumerate.el --- Number lines in the region -*- lexical-binding: t; -*-
;; Copyright (C) 2016 Aaron Harris
;; Author: Aaron Harris <[email protected]>
;; Keywords: convenience
;; Dependencies: `dash', `trinket'
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;; This module contains commands that number the lines in the region
;; in various ways. These functions are similar to, but not directly
;; extensions of, `rectangle-number-line'.
;;
;; The basic command is `enumerate-lines'. This adds line numbers to
;; each line in the region. With a prefix argument, it can start the
;; numbering at a number other than 1.
;;
;; There is also `enumerate-alpha'. This adds line numbers to each
;; line in the region, but according to how they would be sorted
;; alphabetically, instead of their current position.
;;
;; Both commands are autoloaded.
;;; Code:
(require 'dash)
(require 'trinket)
;;;###autoload
(defun enumerate-lines (beg end &optional offset eol sep format-str)
"Insert a number for each line in the region.
Non-interactively, act on the text between BEG and END.
If the region is not active, act on the entire buffer.
If the region to be acted on starts or ends in the middle of a
line, a line number will still be inserted for that line.
If OFFSET is supplied (interactively, as a numeric prefix
argument), it is used as a starting point for the numbering;
otherwise, it defaults to 1.
If EOL is non-nil, the numbers will be appended to the end of
each line instead of being prepended to the beginning.
The SEP argument is the string separating the line number from
the rest of the line; i.e., it will ordinarily follow the number
but precedes it if EOL is supplied. This defaults to a single
space.
The FORMAT-STR argument can be used to configure how the
numbers are displayed. This is a string similar to those used in
the `format' function, but all ordinary format specifiers should
be double-escaped (e.g., \"%%d\"), and the special escape \"%n\"
will be replaced with the maximum number of digits of any line
number before the other escapes are interpreted. The default
value for FORMAT-STR is \"%%%nd\"."
(interactive "r\np")
(let* ((beg (if (use-region-p) (trinket-bol beg) (point-min)))
(end (if (use-region-p) (trinket-eol end) (point-max)))
(offset (1- (or offset 1)))
(sep (or sep " "))
(format-str (or format-str "%%%nd"))
(regexp (if eol "$" "^"))
(pad (->> (count-lines beg end)
(max 1)
(+ offset 1)
(format "%d")
length))
(formatter (format-spec format-str (format-spec-make ?n pad))))
(save-excursion
(save-restriction
(goto-char beg)
(narrow-to-region beg end)
(while (progn
(if eol (end-of-line) (beginning-of-line))
(insert (concat (when eol sep)
(format formatter
(+ (line-number-at-pos) offset))
(unless eol sep)))
(end-of-line)
(= (forward-line) 0)))))))
;;;###autoload
(defun enumerate-alpha (beg end &optional offset sep format-string)
"Number lines in region according to alphabetic order.
As `enumerate-lines', except lines are numbered according to
their alphabetic order instead of their position, and the option
to put the number at the end of the line is unavailable."
(interactive "r\np")
(let* ((beg (if (use-region-p) (trinket-bol beg) (point-min)))
(end (if (use-region-p) (trinket-eol end) (point-max))))
(save-excursion
(save-restriction
(narrow-to-region beg end)
;; Append ordinary line numbers to eol, sort, then add the
;; numbers we want to bol.
(enumerate-lines (point-min) (point-max) 1 :eol " " "%%0%nd")
(sort-lines nil (point-min) (point-max))
(enumerate-lines (point-min) (point-max) offset nil sep format-string)
;; Move the eol line numbers to bol and sort again to recover
;; original order.
(goto-char (point-min))
(while (re-search-forward "^\\(.*\\) \\([0-9]+\\)$" nil :noerr)
(replace-match "\\2 \\1"))
(sort-lines nil (point-min) (point-max))
;; Remove extraneous numbers.
(goto-char (point-min))
(while (re-search-forward "^\\([0-9]+\\) " nil :noerr)
(replace-match "")
(end-of-line))))))
(provide 'enumerate)
;;; enumerate.el ends here