-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
map-regexp.el
135 lines (102 loc) · 5.11 KB
/
map-regexp.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
131
132
133
134
135
;;; map-regexp.el --- map over matches of a regular expression
;; Copyright (C) 2013, 2019 Jonas Bernoulli
;; Author: Jonas Bernoulli <[email protected]>
;; Keywords: convenience
;; Homepage: https://github.com/tarsius/map-regexp
;; Package-Requires: ((cl-lib "0.6.1"))
;; This file is not part of GNU Emacs.
;; This file 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, or (at your option)
;; any later version.
;; This file 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.
;; For a full copy of the GNU General Public License
;; see <http://www.gnu.org/licenses/>.
;;; Commentary:
;; This library defines several forms that search forward from
;; point for a regular expression and call a function for each
;; match to do something with the match data.
;; Equivalents of `mapc', `mapcar', and `cl-mapcan' are defined.
;; Anaphoric variants that expect an expression instead of a function
;; are also available. Instead an expression `mr-amapcar-regexp'
;; also accepts an integer (or list of integers); it then returns a
;; list of match strings (resp. a list of lists of match strings).
;; If that isn't enough use `mr-loop-regexp' which supports all of
;; `cl-loop's accumulation clauses.
;;; Code:
(require 'cl-lib)
;;; Loop
(defmacro mr-loop-regexp (regexp bound clause form)
"Search forward from point for REGEXP evaluating FORM for each match.
For each match evaluate FORM, which has access to the match data.
Use the `cl-loop' accumulation CLAUSE to collect the results.
BOUND, if non-nil, bounds the search; it is a buffer position.
The match found must not extend after that position.
Also see `cl-loop', `re-search-forward', and `match-...'."
(declare (indent defun))
`(save-excursion
(cl-loop while (re-search-forward ,regexp ,bound t)
,clause ,form)))
;;; Function Map
(defmacro mr-mapc-regexp (function regexp &optional bound)
"Search forward from point for REGEXP calling FUNCTION for each match.
For each match call FUNCTION, which has access to the match data,
with no arguments.
Optional BOUND, if non-nil, bounds the search; it is a buffer
position. The match found must not extend after that position."
`(mr-loop-regexp ,regexp ,bound do (funcall ,function)))
(defmacro mr-mapcar-regexp (function regexp &optional bound)
"Search forward from point for REGEXP calling FUNCTION for each match.
For each match call FUNCTION, which has access to the match data,
with no arguments, and make a list of the results.
Optional BOUND, if non-nil, bounds the search; it is a buffer
position. The match found must not extend after that position."
`(mr-loop-regexp ,regexp ,bound collect (funcall ,function)))
(defmacro mr-mapcan-regexp (function regexp &optional bound)
"Search forward from point for REGEXP calling FUNCTION for each match.
For each match call FUNCTION, which has access to the match data,
with no arguments, and nconc together the results.
Optional BOUND, if non-nil, bounds the search; it is a buffer
position. The match found must not extend after that position."
`(mr-loop-regexp ,regexp ,bound nconc (funcall ,function)))
;;; Anaphoric Map
(defmacro mr-amapc-regexp (form regexp &optional bound)
"Search forward from point for REGEXP evaluating FORM for each match.
For each match evaluate FORM using the current match data.
Optional BOUND, if non-nil, bounds the search; it is a buffer
position. The match found must not extend after that position."
`(mr-loop-regexp ,regexp ,bound do ,form))
(defmacro mr-amapcar-regexp (form regexp &optional bound)
"Search forward from point for REGEXP evaluating FORM for each match.
For each match evaluate FORM using the current match data, and
collecting the results.
FORM may also be an integer in which case the respective match
strings (sans properties) are collected. FORM my also be a list
of integers in which case a list of lists of strings is returned.
Optional BOUND, if non-nil, bounds the search; it is a buffer
position. The match found must not extend after that position."
`(mr-loop-regexp ,regexp ,bound collect
,(cond ((integerp form)
`(match-string-no-properties ,form))
((and (listp form)
(integerp (car form)))
`(list ,@(mapcar (lambda (i)
`(match-string-no-properties ,i))
form)))
(t
form))))
(defmacro mr-amapcan-regexp (form regexp &optional bound)
"Search forward from point for REGEXP evaluating FORM for each match.
For each match evaluate FORM using the current match data, and
nconc together the results.
Optional BOUND, if non-nil, bounds the search; it is a buffer
position. The match found must not extend after that position."
`(mr-loop-regexp ,regexp ,bound nconc ,form))
(provide 'map-regexp)
;; Local Variables:
;; indent-tabs-mode: nil
;; End:
;;; map-regexp.el ends here