-
Notifications
You must be signed in to change notification settings - Fork 2
/
urgrep-wgrep.el
153 lines (133 loc) · 6.41 KB
/
urgrep-wgrep.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
;;; urgrep-wgrep.el --- Universal recursive grep -*- lexical-binding: t -*-
;; Copyright (C) 2021-2024 Free Software Foundation, Inc.
;; Author: Jim Porter
;; URL: https://github.com/jimporter/urgrep
;; Version: 0.5.2-git
;; Keywords: grep, search
;; This file is NOT part of GNU Emacs.
;; 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:
;; A compatibility layer between urgrep and wgrep.
;;; Code:
(require 'urgrep)
(require 'text-property-search)
(defvar urgrep-wgrep--grouped-result-regexp
(rx bol (or ;; A match or context line.
(seq (group-n 2 urgrep-regular-number) (any ":=-"))
;; A separator line.
(group-n 3 "--" eol)))
"The regexp to use to match results using grouped output.
Group 2 is the line number, and group 3 is the \"--\" separator used when
displaying context. Group 1 is unused.")
(defvar urgrep-wgrep--ungrouped-result-regexp
(rx bol (or ;; A match or context line using a null terminator after the
;; filename.
(seq (group-n 1 (+ (not (any "\0" "\n")))) "\0"
(group-n 2 (+ digit)) (any ":=-"))
;; A match or context line without a null terminator; see also
;; `urgrep-regexp-alist'.
(seq (group-n 1 (+? nonl) (not (any "\n" "/"))) (any ":=-")
(group-n 2 urgrep-regular-number) (any ":=-"))
;; A separator line.
(group-n 3 "--" eol)))
"The regexp to use to match results using ungrouped output.
Group 1 is the filename, group 2 is the line number, and group 3 is the \"--\"
separator used when displaying context.")
(declare-function wgrep-construct-filename-property "wgrep" (filename))
(defun urgrep-wgrep--propertize-lines (begin end &optional file-name)
"Apply wgrep properties to result lines between BEGIN and END.
If END is nil, continue to the end of the (narrowed) buffer.
FILE-NAME, if non-nil is the name of the file for this section of
grouped results; if nil, assume the results are ungrouped."
(let ((line-regexp (if file-name
urgrep-wgrep--grouped-result-regexp
urgrep-wgrep--ungrouped-result-regexp)))
(goto-char begin)
(while (and (zerop (forward-line 1))
(looking-at line-regexp)
(or (not end) (< (point) end)))
(if (match-beginning 3)
;; Ignore the separator line ("--").
(add-text-properties (match-beginning 0) (match-end 0)
'(wgrep-ignore t))
;; If results are ungrouped, mark the filename with
;; `wgrep-construct-filename-property'.
(unless file-name
(add-text-properties
(match-beginning 1) (match-end 1)
(list (wgrep-construct-filename-property file-name) file-name)))
;; Mark the line with the filename and line number.
(add-text-properties
(match-beginning 0) (match-end 0)
(list 'wgrep-line-filename file-name
'wgrep-line-number (string-to-number (match-string 2))))))))
(defun urgrep-wgrep-header/footer-parser ()
"Mark the header and footer of the urgrep results.
This lets wgrep know what to ignore."
(save-excursion
;; Look for the beginning of the results.
(goto-char (point-min))
(if (not (text-property-search-forward 'urgrep-file-name))
;; No results, mark the entire buffer as a header.
(add-text-properties (point-min) (point-max)
'(read-only t wgrep-header t))
;; Found some results, mark the preceding part of the buffer as a header.
(add-text-properties (point-min) (line-beginning-position)
'(read-only t wgrep-header t))
;; Look for the end of the results.
(goto-char (point-max))
(text-property-search-backward 'compilation-handle-exit)
;; If there's a footer, mark it.
(unless (eobp)
(add-text-properties (point) (point-max)
'(read-only t wgrep-footer t))))))
(defun urgrep-wgrep-results-parser ()
"Parse the urgrep results and apply properties for wgrep."
(save-excursion
(let ((this-group)
(next-group (text-property-search-forward 'urgrep-file-name)))
(if (eolp)
;; Grouped results
(while (prog1 (setq this-group next-group)
(setq next-group (text-property-search-forward
'urgrep-file-name)))
(let* ((file-name-begin (prop-match-beginning this-group))
(file-name-end (prop-match-end this-group))
(file-name (buffer-substring-no-properties file-name-begin
file-name-end)))
;; Mark the filename with `wgrep-construct-filename-property'.
(add-text-properties
file-name-begin file-name-end
(list 'wgrep-ignore t
(wgrep-construct-filename-property file-name) file-name))
(urgrep-wgrep--propertize-lines
(prop-match-end this-group)
(when next-group (prop-match-beginning next-group))
file-name)))
;; Ungrouped results
(urgrep-wgrep--propertize-lines (point-min) nil)))))
;;;###autoload
(defun urgrep-wgrep-setup ()
"Set up a urgrep buffer to use wgrep."
(require 'wgrep)
(declare-function wgrep-setup-internal "wgrep" nil)
(defvar wgrep-header/footer-parser)
(defvar wgrep-results-parser)
(setq-local wgrep-header/footer-parser #'urgrep-wgrep-header/footer-parser
wgrep-results-parser #'urgrep-wgrep-results-parser)
(wgrep-setup-internal))
(add-hook 'urgrep-setup-hook #'urgrep-wgrep-setup)
(defun urgrep-wgrep-unload-function ()
"Unload wgrep from urgrep."
(remove-hook 'urgrep-setup-hook #'urgrep-wgrep-setup))
(provide 'urgrep-wgrep)
;;; urgrep-wgrep.el ends here