-
Notifications
You must be signed in to change notification settings - Fork 13
/
matcher.lisp
100 lines (85 loc) · 3.26 KB
/
matcher.lisp
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
;;;; Copyright (c) 2003, 2004 Nikodemus Siivola, Julian Squires
;;;;
;;;; Permission is hereby granted, free of charge, to any person obtaining
;;;; a copy of this software and associated documentation files (the
;;;; "Software"), to deal in the Software without restriction, including
;;;; without limitation the rights to use, copy, modify, merge, publish,
;;;; distribute, sublicense, and/or sell copies of the Software, and to
;;;; permit persons to whom the Software is furnished to do so, subject to
;;;; the following conditions:
;;;;
;;;; The above copyright notice and this permission notice shall be included
;;;; in all copies or substantial portions of the Software.
;;;;
;;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
;;;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
;;;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
;;;; IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
;;;; CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
;;;; TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
;;;; SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
(in-package :linedit)
;;;; QUOTES
;; FIXME: should checking for #\", "\"", et cetera.
(defun quoted-p (string index)
(let ((quoted-p nil))
(dotimes (n (min index (length string)) quoted-p)
(when (eql (schar string n) #\")
(setf quoted-p (not quoted-p))))))
(defun find-open-quote (string index)
(when (quoted-p string index)
(loop for n from (1- index) downto 0
when (eql (schar string n) #\") return n)))
(defun find-close-quote (string index)
(when (quoted-p string index)
(loop for n from (1+ index) below (length string)
when (eql (schar string n) #\") return n)))
;;;; PARENS
;; FIXME: This is not the Right Way to do paren matching.
;; * use stack, not counting
;; * don't count #\( #\) &co
(defun after-close-p (string index)
(and (array-in-bounds-p string (1- index))
(find (schar string (1- index)) ")]}")))
(defun at-open-p (string index)
(and (array-in-bounds-p string index)
(find (schar string index) "([{")))
(defun paren-count-delta (char)
(case char
((#\( #\[ #\{) -1)
((#\) #\] #\}) 1)
(t 0)))
(defun find-open-paren (string index)
(loop with count = 1
for n from (1- index) downto 0
do (incf count (paren-count-delta (schar string n)))
when (zerop count) return n))
(defun find-close-paren (string index)
(loop with count = -1
for n from (1+ index) below (length string)
do (incf count (paren-count-delta (schar string n)))
when (zerop count) return n))
(defun dwim-match-parens (string index)
(cond ((after-close-p string index)
(values (find-open-paren string (1- index)) (1- index)))
((at-open-p string index)
(values index (find-close-paren string index)))
(t
(values nil nil))))
(defun dwim-mark-parens (string index &key pre-mark post-mark)
(multiple-value-bind (open close) (dwim-match-parens string index)
(values
(if (and open close)
(concat (subseq string 0 open)
pre-mark
(string (schar string open))
post-mark
(subseq string (1+ open) close)
pre-mark
(string (schar string close))
post-mark
(if (> (length string) (1+ close))
(subseq string (1+ close))
""))
string)
open)))