|
3 | 3 | :lem) |
4 | 4 | (:import-from :lem-vi-mode/core |
5 | 5 | :make-range |
| 6 | + :range-beginning |
| 7 | + :range-end |
6 | 8 | :text-object-abort) |
7 | 9 | (:import-from :lem-vi-mode/visual |
8 | 10 | :visual |
|
19 | 21 | :a-range-of |
20 | 22 | :inner-range-of |
21 | 23 |
|
22 | | - :word-object)) |
| 24 | + :word-object |
| 25 | + :double-quoted-object)) |
23 | 26 | (in-package :lem-vi-mode/text-objects) |
24 | 27 |
|
25 | 28 | (defclass text-object () ()) |
|
52 | 55 | (:method ((object symbol) state count) |
53 | 56 | (inner-range-of (make-instance object) state count))) |
54 | 57 |
|
55 | | -(defun target-region () |
56 | | - (if (visual-p) |
57 | | - (visual-range) |
58 | | - (list (copy-point (current-point)) |
59 | | - (copy-point (current-point))))) |
60 | | - |
61 | 58 | (defmethod slurp-object ((object function-text-object) point direction) |
62 | 59 | (check-type direction (member :forward :backward)) |
63 | 60 | (with-slots (function) object |
|
80 | 77 | p)) |
81 | 78 | (if (eq direction :forward) |
82 | 79 | (move-forward point) |
83 | | - (move-backward point)))))) |
| 80 | + (move-backward point))))) |
| 81 | + point) |
84 | 82 |
|
85 | 83 | (defun a-range-with-direction (object count beg end direction) |
86 | 84 | (check-type direction (member :forward :backward)) |
|
114 | 112 | (when (or (null direction) |
115 | 113 | (eq direction :backward)) |
116 | 114 | (skip-chars-backward beg '(#\Space #\Tab)))) |
117 | | - ((not (member (character-at beg) '(#\Space #\Tab))) |
118 | | - (slurp-object object beg (if (eq direction :backward) |
119 | | - :forward |
120 | | - :backward)))) |
| 115 | + ((and (null direction) |
| 116 | + (not (member (character-at beg) '(#\Space #\Tab)))) |
| 117 | + (slurp-object object beg :backward))) |
121 | 118 | (prog1 |
122 | 119 | (a-range-with-direction object count beg end (or direction :forward)) |
123 | 120 | (unless initial-blank |
|
128 | 125 | (eq direction :forward)) |
129 | 126 | (or (point= end (buffer-end-point (point-buffer end))) |
130 | 127 | (char= (character-at end) #\Newline)))) |
131 | | - (skip-chars-backward beg '(#\Space #\Tab)) |
| 128 | + (unless direction |
| 129 | + (skip-chars-backward beg '(#\Space #\Tab))) |
132 | 130 | (skip-chars-forward end '(#\Space #\Tab)))))))) |
133 | 131 |
|
134 | 132 | (defmethod a-range-of (object state count) |
|
149 | 147 | (skip-chars-backward beg '(#\Space #\Tab)) |
150 | 148 | (skip-chars-forward end '(#\Space #\Tab)))))))) |
151 | 149 |
|
152 | | -(defmethod inner-range-of ((object function-text-object) state count) |
| 150 | +(defmethod inner-range-of (object state count) |
153 | 151 | (declare (ignore state)) |
154 | | - (with-slots (function) object |
155 | | - (destructuring-bind (beg end) |
156 | | - (target-region) |
157 | | - (let* ((direction (cond |
158 | | - ((point< beg end) :forward) |
159 | | - ((point< end beg) :backward))) |
160 | | - (char-type (funcall function (character-at end))) |
161 | | - (check-fn (lambda (c) (eq (funcall function c) char-type))) |
162 | | - (buffer (point-buffer beg))) |
163 | | - (flet ((move-forward (p) |
164 | | - (loop with buffer-end = (buffer-end-point (point-buffer p)) |
165 | | - while (and (point/= p buffer-end) |
166 | | - (char/= (character-at p) #\Newline) |
167 | | - (funcall check-fn (character-at p))) |
168 | | - do (character-offset p 1)) |
169 | | - p) |
170 | | - (move-backward (p) |
171 | | - (loop while (and (< 0 (point-charpos p)) |
172 | | - (funcall check-fn (character-at p -1))) |
173 | | - do (character-offset p -1)) |
174 | | - p)) |
175 | | - (if (or (null direction) |
176 | | - (eq direction :forward)) |
177 | | - (progn |
178 | | - (move-backward beg) |
179 | | - (dotimes (i count) |
180 | | - (when (or (point= end (buffer-end-point buffer)) |
181 | | - (char= (character-at end) #\Newline)) |
182 | | - (error 'text-object-abort |
183 | | - :range (make-range beg end))) |
184 | | - (move-forward end) |
185 | | - (setf char-type (funcall function (character-at end))))) |
186 | | - (progn |
187 | | - (move-forward beg) |
188 | | - (dotimes (i count) |
189 | | - (when (or (point= end (buffer-start-point buffer)) |
190 | | - (char= (character-at end -1) #\Newline)) |
191 | | - (error 'text-object-abort |
192 | | - :range (make-range beg end))) |
193 | | - (move-backward end) |
194 | | - (setf char-type (funcall function (character-at end -1)))))) |
195 | | - (make-range beg end)))))) |
| 152 | + (with-point ((beg (current-point)) |
| 153 | + (end (current-point))) |
| 154 | + (if (member (character-at beg) '(#\Space #\Tab #\Newline)) |
| 155 | + (skip-chars-backward beg '(#\Space #\Tab #\Newline)) |
| 156 | + (slurp-object object beg :backward)) |
| 157 | + (dotimes (i count) |
| 158 | + (when (or (point= end (buffer-end-point (point-buffer end))) |
| 159 | + (char= (character-at end) #\Newline)) |
| 160 | + (error 'text-object-abort |
| 161 | + :range (make-range beg end))) |
| 162 | + (if (member (character-at end) '(#\Space #\Tab #\Newline)) |
| 163 | + (skip-chars-forward end '(#\Space #\Tab)) |
| 164 | + (slurp-object object end :forward))) |
| 165 | + (make-range beg end))) |
196 | 166 |
|
197 | | -(defmethod a-range-of ((object quoted-text-object) state count) |
198 | | - (declare (ignore state count)) |
| 167 | +(defmethod inner-range-of (object (state visual) count) |
| 168 | + (destructuring-bind (beg end) |
| 169 | + (visual-range) |
| 170 | + (let ((direction (cond |
| 171 | + ((point< beg end) :forward) |
| 172 | + ((point< end beg) :backward))) |
| 173 | + (buffer (point-buffer end))) |
| 174 | + (when (null direction) |
| 175 | + (if (member (character-at beg) '(#\Space #\Tab #\Newline)) |
| 176 | + (skip-chars-backward beg '(#\Space #\Tab #\Newline)) |
| 177 | + (slurp-object object beg :backward))) |
| 178 | + (if (or (null direction) |
| 179 | + (eq direction :forward)) |
| 180 | + (progn |
| 181 | + (dotimes (i count) |
| 182 | + (when (or (point= end (buffer-end-point buffer)) |
| 183 | + (char= (character-at end) #\Newline)) |
| 184 | + (error 'text-object-abort |
| 185 | + :range (make-range beg end))) |
| 186 | + (slurp-object object end :forward))) |
| 187 | + (progn |
| 188 | + (slurp-object object beg :forward) |
| 189 | + (dotimes (i count) |
| 190 | + (when (or (point= end (buffer-start-point buffer)) |
| 191 | + (char= (character-at end -1) #\Newline)) |
| 192 | + (error 'text-object-abort |
| 193 | + :range (make-range beg end))) |
| 194 | + (slurp-object object end :backward))))) |
| 195 | + (make-range beg end))) |
| 196 | + |
| 197 | +(defmethod slurp-object ((object quoted-text-object) point direction) |
199 | 198 | (with-slots (quote-char escape-char) object |
200 | | - (destructuring-bind (beg end) |
201 | | - (target-region) |
202 | | - (let ((direction (cond |
203 | | - ((point< beg end) :forward) |
204 | | - ((point< end beg) :backward)))) |
205 | | - (loop |
206 | | - (skip-chars-backward beg (lambda (c) (char/= c quote-char))) |
207 | | - (let ((prev-char (character-at beg -1))) |
208 | | - (cond |
209 | | - ;; No quote-char found |
210 | | - ((null prev-char) |
211 | | - (keyboard-quit)) |
212 | | - ;; Skip escaped quote-char |
213 | | - ((and escape-char |
214 | | - (char= prev-char escape-char))) |
215 | | - ;; Successfully found |
216 | | - (t |
217 | | - (character-offset beg -1) |
218 | | - (return))))) |
219 | | - (loop |
220 | | - (skip-chars-forward end (lambda (c) (char/= c quote-char))) |
221 | | - (let ((next-char (character-at end))) |
222 | | - (cond |
223 | | - ;; No quote-char found |
224 | | - ((null next-char) |
225 | | - (keyboard-quit)) |
226 | | - ;; Skip escaped quote-char |
227 | | - ((and escape-char |
228 | | - (char= (character-at end -1) escape-char))) |
229 | | - ;; Successfully found |
230 | | - (t |
231 | | - (character-offset end 1) |
232 | | - (return))))) |
233 | | - (if (member (character-at end) '(#\Space #\Tab)) |
234 | | - (skip-chars-forward end '(#\Space #\Tab)) |
235 | | - (skip-chars-backward beg '(#\Space #\Tab)))) |
236 | | - (make-range beg end)))) |
| 199 | + (ecase direction |
| 200 | + (:backward |
| 201 | + (when (char= (character-at point) quote-char) |
| 202 | + (character-offset point -1)) |
| 203 | + (loop |
| 204 | + (skip-chars-backward point (lambda (c) (char/= c quote-char))) |
| 205 | + (let ((prev-char (character-at point -1))) |
| 206 | + (cond |
| 207 | + ;; No quote-char found |
| 208 | + ((null prev-char) |
| 209 | + (keyboard-quit)) |
| 210 | + ;; Skip escaped quote-char |
| 211 | + ((and escape-char |
| 212 | + (char= prev-char escape-char))) |
| 213 | + ;; Successfully found |
| 214 | + (t |
| 215 | + (character-offset point -1) |
| 216 | + (return)))))) |
| 217 | + (:forward |
| 218 | + (when (char= (character-at point) quote-char) |
| 219 | + (character-offset point 1)) |
| 220 | + (loop |
| 221 | + (skip-chars-forward point (lambda (c) (char/= c quote-char))) |
| 222 | + (let ((next-char (character-at point))) |
| 223 | + (cond |
| 224 | + ;; No quote-char found |
| 225 | + ((null next-char) |
| 226 | + (keyboard-quit)) |
| 227 | + ;; Skip escaped quote-char |
| 228 | + ((and escape-char |
| 229 | + (char= (character-at point -1) escape-char))) |
| 230 | + ;; Successfully found |
| 231 | + (t |
| 232 | + (character-offset point 1) |
| 233 | + (return))))))))) |
237 | 234 |
|
238 | 235 | (defmethod a-range-of ((object quoted-text-object) (state visual) count) |
239 | | - (declare (ignore count)) |
240 | | - (with-slots (open-char escape-char) object |
| 236 | + (with-slots (quote-char escape-char) object |
241 | 237 | (destructuring-bind (beg end) |
242 | 238 | (visual-range) |
243 | | - (let ((direction (cond |
244 | | - ((point< beg end) :forward) |
245 | | - ((point< end beg) :backward)))) |
246 | | - (loop |
247 | | - (skip-chars-backward beg (lambda (c) (char/= c open-char))) |
248 | | - (unless (char= (character-at beg -1) escape-char) |
249 | | - (character-offset beg -1) |
250 | | - (return))) |
251 | | - (loop |
252 | | - (skip-chars-forward end (lambda (c) (char/= c open-char))) |
253 | | - (unless (char= (character-at end -1) escape-char) |
254 | | - (character-offset end 1) |
255 | | - (return))) |
256 | | - (if (member (character-at end) '(#\Space #\Tab)) |
257 | | - (skip-chars-forward end '(#\Space #\Tab)) |
258 | | - (skip-chars-backward beg '(#\Space #\Tab)))) |
259 | | - (make-range beg end)))) |
| 239 | + (let* ((region-string (points-to-string beg end)) |
| 240 | + (len (length region-string)) |
| 241 | + (quote-count 0) |
| 242 | + (direction (cond |
| 243 | + ((point< beg end) :forward) |
| 244 | + ((point< end beg) :backward)))) |
| 245 | + (when (/= len 0) |
| 246 | + (do ((i 0 (1+ i))) |
| 247 | + ((<= len i)) |
| 248 | + (let ((char (aref region-string i))) |
| 249 | + (cond |
| 250 | + ((char= char quote-char) |
| 251 | + (incf quote-count)) |
| 252 | + ((char= char escape-char) |
| 253 | + (incf i)))))) |
| 254 | + (if (= (mod quote-count 2) 1) |
| 255 | + ;; Incomplete object in selected region |
| 256 | + (progn |
| 257 | + (if (eq direction :backward) |
| 258 | + (progn |
| 259 | + (skip-chars-backward end (lambda (c) (char/= c quote-char))) |
| 260 | + (character-offset end -1) |
| 261 | + (skip-chars-backward end '(#\Space #\Tab))) |
| 262 | + (progn |
| 263 | + (skip-chars-forward end (lambda (c) (char/= c quote-char))) |
| 264 | + (character-offset end 1) |
| 265 | + (skip-chars-forward end '(#\Space #\Tab)))) |
| 266 | + (make-range beg end)) |
| 267 | + (call-next-method)))))) |
| 268 | + |
| 269 | +(defmethod inner-range-of ((object quoted-text-object) state count) |
| 270 | + (declare (ignore state count)) |
| 271 | + (let ((range (call-next-method))) |
| 272 | + (character-offset (range-beginning range) 1) |
| 273 | + (character-offset (range-end range) -1) |
| 274 | + range)) |
260 | 275 |
|
261 | 276 | (defclass word-object (function-text-object) () |
262 | 277 | (:default-initargs |
263 | 278 | :function #'word-char-type)) |
264 | 279 |
|
| 280 | +(defclass double-quoted-object (quoted-text-object) () |
| 281 | + (:default-initargs |
| 282 | + :quote-char #\")) |
| 283 | + |
265 | 284 | (defmethod a-range-of :before ((object word-object) (state visual) count) |
266 | 285 | (unless (visual-char-p) |
267 | 286 | (vi-visual-char))) |
|
0 commit comments