-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathsniem-object-catch.el
456 lines (411 loc) · 17.5 KB
/
sniem-object-catch.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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
;;; sniem-object-catch.el --- Hands-eased united editing method -*- lexical-binding: t -*-
;; Author: SpringHan
;; Maintainer: SpringHan
;; 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 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.
;; For a full copy of the GNU General Public License
;; see <http://www.gnu.org/licenses/>.
;;; Commentary:
;; Hands-eased united editing method
;;; Code:
(require 'sniem-var)
(require 'sniem-common)
(require 'sniem-macro)
(defgroup sniem-object-catch nil
"The group of `sniem-object-catch'."
:group 'sniem)
(defcustom sniem-object-catch-last-points nil
"The last point cons."
:type 'cons
:group 'sniem-object-catch)
(defcustom sniem-object-catch-action nil
"The action info for the last catch."
:type 'cons
:group 'sniem-object-catch)
(defcustom sniem-object-catch-forward-p nil
"The direction for catch."
:type 'symbol
:group 'sniem-object-catch)
(defcustom sniem-object-catch-prefix-string-p nil
"If the prefix is string."
:type 'boolean
:group 'sniem-object-catch)
(defcustom sniem-object-catch-expand-p nil
"If to expand the region from current selecetion."
:type 'boolean
:group 'sniem-object-catch)
(defcustom sniem-object-catch-last-expand nil
"The last expand points."
:type 'cons
:group 'sniem-object-catch)
(defcustom sniem-object-catch-auto-backward nil
"If this variable is non-nil.
When you exit expand-mode, the direction'll be set to backward."
:type 'boolean
:group 'sniem-object-catch)
(sniem-define-motion sniem-object-catch (&optional char parent)
"Catch region."
(interactive)
(let ((point (point)))
(when (and parent sniem-object-catch-forward-p)
(setq-local sniem-object-catch-forward-p nil))
(while (not (eq 'no (ignore-errors (sniem-object-catch--get char parent))))
(if (bobp)
(progn
(goto-char point)
(when sniem-object-catch-last-points
(push-mark (cdr sniem-object-catch-last-points) t t))
(user-error "[Sniem-Object-Catch]: Can't get more item!"))
(backward-char)))
(when sniem-object-catch-prefix-string-p
(setq-local sniem-object-catch-prefix-string-p nil))))
(defun sniem-object-catch--get (char parent)
"Get the object.
Argument CHAR is the prefix of pair.
Argument PARENT means get the parent pair of the content selected."
(let ((move (if sniem-object-catch-forward-p
'forward-char
'backward-char))
prefix-point second-char second-point tmp go-on)
(save-mark-and-excursion
(when (region-active-p)
(funcall move))
;; Get the `prefix-point'
(if char
(setq prefix-point
(catch 'point-stop
(while t
(if (and (string=
char
(setq tmp
(buffer-substring-no-properties (point) (1+ (point)))))
(not (sniem-object-catch-backslash-p)))
(throw 'point-stop (point))
(if (or (bobp) (eobp))
(throw 'point-stop nil)
(funcall move))))))
(setq prefix-point
(catch 'point-stop
(while t
(if (and (sniem-object-catch--get-second-char
(setq tmp (buffer-substring-no-properties (point) (1+ (point)))))
(not (sniem-object-catch-backslash-p)))
(progn
(setq char tmp)
(throw 'point-stop (point)))
(if (or (bobp) (eobp))
(throw 'point-stop nil)
(funcall move)))))))
(cond ((and (nth 3 (syntax-ppss prefix-point))
(/= (following-char) 34))
(setq-local sniem-object-catch-prefix-string-p t))
((and sniem-object-catch-prefix-string-p
(null (nth 3 (syntax-ppss prefix-point))))
(setq-local sniem-object-catch-prefix-string-p nil)))
(if (not char)
(message "[Sniem-Object-Catch]: Can not find a symbol in alist.")
(setq second-char (sniem-object-catch--get-second-char char))
(if (and (not (string= char second-char))
(if (and (bobp)
(= (point) prefix-point))
(ignore-errors (= (char-before) 92))
(= (char-before) 92)))
(setq go-on t)
(setq second-point (if (string= char second-char)
(if (or (and (not (nth 3 (syntax-ppss)))
(nth 8 (syntax-ppss)))
(sniem-object-catch--face-around-eq))
(sniem-object-catch-format-pointc char)
(sniem-object-catch-format-point2 char prefix-point))
(sniem-object-catch-format-point char second-char))))
(when (consp second-point)
(setq prefix-point (car second-point)
second-point (cdr second-point)))
(if (and parent sniem-object-catch-last-points
(> (cdr sniem-object-catch-last-points) second-point)
(< prefix-point (car sniem-object-catch-last-points)))
(setq go-on t)
(setq-local sniem-object-catch-last-points (cons prefix-point second-point)))))
(when sniem-object-catch-expand-p
(when sniem-object-catch-last-expand
(when (< (car sniem-object-catch-last-expand) prefix-point)
(setq prefix-point (car sniem-object-catch-last-expand)))
(when (> (cdr sniem-object-catch-last-expand) second-point)
(setq second-point (cdr sniem-object-catch-last-expand))))
(setq-local sniem-object-catch-last-expand (cons prefix-point second-point)))
(goto-char prefix-point)
(push-mark second-point t t)
(setq-local sniem-object-catch-action `(,char . ,parent))
(unless go-on
(setq go-on 'no))
go-on))
(defun sniem-object-catch-by-char (char)
"Catch region by CHAR."
(interactive (list (char-to-string (read-char))))
(if (sniem-object-catch--get-second-char char)
(sniem-object-catch char)
(message "[Sniem-Object-Catch]: %s is not defined in the symbol alist." char)))
(defun sniem-object-catch-char ()
"Catch region by the last char."
(interactive)
(let ((pair (sniem-object-catch--get-last-char)))
(sniem-object-catch pair nil)))
(defun sniem-object-catch-parent ()
"Catch region for its parent."
(interactive)
(let ((pair (sniem-object-catch--get-last-char)))
(sniem-object-catch pair t)))
(defun sniem-object-catch-expand ()
"Open/close expand option."
(interactive)
(setq-local sniem-object-catch-last-expand nil)
(if sniem-object-catch-expand-p
(progn
(setq-local sniem-object-catch-expand-p nil)
(message "[Sniem]: Expand closed."))
(when sniem-object-catch-forward-p
(setq-local sniem-object-catch-forward-p nil))
(setq-local sniem-object-catch-expand-p t)
(when (region-active-p)
(setq-local sniem-object-catch-last-expand sniem-object-catch-last-points))
(message "[Sniem]: Expand opened.")))
(defun sniem-object-catch--get-last-char ()
"Get the last char."
(pcase last-input-event
((or 41 79 111) "(")
((or 83 93 115) "[")
((or 67 125 99) "{")
((or 39 113 81) "'")
((or 34 100 68) "\"")
((or 60 97 65) "<")
(_ nil)))
(defun sniem-object-catch-parent-by-char (char)
"Catch region for its parent by CHAR."
(interactive (list (char-to-string (read-char))))
(if (sniem-object-catch--get-second-char char)
(sniem-object-catch char t)
(message "[Sniem-Object-Catch]: %s is not defined in the symbol alist." char)))
(defun sniem-object-catch-repeat ()
"Repeat the last catch."
(interactive)
(when sniem-object-catch-action
(sniem-object-catch (car sniem-object-catch-action) (cdr sniem-object-catch-action))))
(defun sniem-object-catch-direction-reverse (&optional forward)
"Reverse the catch direction.
Optional argument FORWARD means change the direction to forward."
(interactive)
(setq-local sniem-object-catch-forward-p
(if (or forward (null sniem-object-catch-forward-p))
t
nil))
(message "[Sniem]: The object-catch-direction now is %s."
(if sniem-object-catch-forward-p
"forward"
"backward")))
(defun sniem-object-catch-format-point (prefix second-char)
"Format point with the PREFIX.
Argument SECOND-CHAR is the end char of the pair."
(let ((times 1)
tmp)
(forward-char)
(while (/= times 0)
(setq tmp (buffer-substring-no-properties (point) (1+ (point))))
(cond ((and (string= tmp prefix) (not (string= prefix second-char))
(or (and sniem-object-catch-prefix-string-p
(nth 3 (syntax-ppss)))
(and (null sniem-object-catch-prefix-string-p)
(null (nth 3 (syntax-ppss)))))
(not (= (char-before) 92)))
(setq times (1+ times)))
((and (string= tmp second-char) (> times 0)
(not (= (char-before) 92))
(or (and sniem-object-catch-prefix-string-p
(nth 3 (syntax-ppss)))
(and (null sniem-object-catch-prefix-string-p)
(null (nth 3 (syntax-ppss))))))
(setq times (1- times))))
(forward-char))
(point)))
(defun sniem-object-catch-format-point2 (pair prefix-point)
"Format point for the PAIR with same char.
Argument PREFIX-POINT is the prefix point."
(let ((region-forward-p (when (and (region-active-p) sniem-object-catch-forward-p)
(prog1 (cons (region-beginning) (region-end))
(deactivate-mark))))
(face-eq-p (lambda (face1)
(let ((face2 (get-text-property (point) 'face)))
(when face2
(ignore-errors
(or (eq face1 face2)
(memq face1 face2)
(memq face2 face1)))))))
prefix-face second-point tmp)
(save-mark-and-excursion
(goto-char prefix-point)
(setq prefix-face (face-at-point))
(cond ((or (progn ;Check if the faces of current char and the before one are same.
(backward-char)
(funcall face-eq-p prefix-face))
(progn ;Check if the faces between current char and the previous one are same.
(setq tmp (face-at-point))
(when (search-backward pair nil t)
(forward-char)
(funcall face-eq-p tmp))))
(setq second-point (sniem-object-catch-format-point1 pair prefix-point)
prefix-point (sniem-object-catch-format-point1 pair prefix-point t t)))
((or (progn ;Check if the faces of current char and the after one are same.
(goto-char prefix-point)
(forward-char)
(funcall face-eq-p prefix-face))
(progn ;Check if the faces between current char and the next one are same.
(setq tmp (face-at-point))
(when (search-forward pair nil t)
(backward-char 2)
(funcall face-eq-p tmp))))
(setq prefix-point (sniem-object-catch-format-point1 pair prefix-point nil t)
second-point (sniem-object-catch-format-point1 pair (point) t))))
(when region-forward-p
(goto-char (car region-forward-p))
(push-mark (cdr region-forward-p))))
(cons prefix-point (1+ second-point))))
(defun sniem-object-catch-format-point1 (pair point &optional search prefix)
"Format the POINT for char.
Argument PAIR is the pair."
(save-mark-and-excursion
(goto-char point)
(let ((search-command (if prefix
'search-backward
'search-forward)))
(when search
(setq point (progn
(funcall search-command pair)
(unless prefix (backward-char))
(point))))
(when (sniem-object-catch-backslash-p)
(setq point (progn
(forward-char)
(point)))
(while (progn
(setq point (funcall search-command pair))
(sniem-object-catch-backslash-p)))))
point))
(defun sniem-object-catch-format-pointc (char)
"Format the CHAR has same char in comment."
(let (balone falone)
(setq balone (sniem-object-catch--while-check-format char))
(setq falone (sniem-object-catch--while-check-format char t))
(if balone
(cons balone (1+ (point)))
(1+ falone))))
(defun sniem-object-catch--while-check-format (char &optional forward)
"Check the pair which has same CHAR in a while with the direction.
When the FORWARD is non-nil, the direction is forward.
Otherwise it's backward."
(let ((command (if forward
'forward-char
'backward-char))
current-char alone another-point)
(save-mark-and-excursion
(while (and (not (sniem-object-catch--border forward))
(or (funcall command) t)
(or (nth 8 (syntax-ppss))
(ignore-errors
(= (char-before) 10))
(sniem-object-catch--face-around-eq)))
(when (and (not (sniem-object-catch-backslash-p))
(ignore-errors
(setq current-char
(buffer-substring-no-properties (point) (1+ (point)))))
(string= char current-char))
(cond ((null another-point)
(setq another-point (point)))
(alone (setq alone nil))
(t (setq alone t))))))
(unless alone
another-point)))
(defun sniem-object-catch--border (forward)
"Check if it's border now.
FORWARD means now it's forward direction."
(if forward
(eobp)
(bobp)))
(defun sniem-object-catch--face-around-eq ()
"Check if the faces around the point are equal."
(let ((face (face-at-point))
lface rface)
(save-mark-and-excursion
(setq lface (progn
(ignore-errors (backward-char))
(face-at-point))
rface (progn
(ignore-errors (forward-char))
(face-at-point))))
(and (eq face lface)
(eq face rface))))
(defun sniem-object-catch--symbol-exists-p (symbol)
"Check if the SYMBOL is exists."
(catch 'exists
(let ((index 0))
(dolist (symbol-cons sniem-object-catch-global-symbol-alist)
(when (string= symbol (car symbol-cons))
(throw 'exists index))
(setq index (1+ index))))))
(defun sniem-object-catch--get-second-char (prefix)
"Get the second char by the PREFIX."
(let ((current-pairs (alist-get major-mode sniem-object-catch-global-symbol-alist))
(default (alist-get prefix sniem-object-catch-global-symbol-alist
nil nil 'equal))
local)
(cond ((and current-pairs
(setq local (alist-get prefix current-pairs nil nil 'equal)))
(if (string= local "")
nil
local))
(t default))))
(defun sniem-object-catch-backslash-p ()
"Check if the char before current point is \\."
(unless (bobp)
(and (= 92 (char-before))
(not (save-mark-and-excursion
(backward-char)
(if (bobp)
t
(= 92 (char-before))))))))
(defun sniem-object-catch--index (ele list)
"Get the index of LIST whose first item is equal to ELE."
(catch 'index
(let ((index 0))
(dolist (item list)
(when (equal ele (car item))
(throw 'index index))
(setq index (1+ index))))))
(defun sniem-object-catch--append (ele list)
"Like `add-to-list', but it will replace the origin, then return it.
ELE is the element to add.
LIST is the list for operating."
(let (prefix tmp)
(dotimes (n (length list))
(setq prefix (car (nth n list)))
(when (setq tmp (alist-get prefix ele nil nil 'string-equal))
(setf (nth n list) (cons prefix tmp))
(setq ele (delete (nth (sniem-object-catch--index prefix ele) ele) ele))))
(append ele list)))
(defmacro sniem-object-catch-mode-defalist (modename &rest alist)
"Define ALIST for major mode.
Argument MODENAME if the mode name."
(declare (indent 1))
`(let ((index (sniem-object-catch--index ',modename sniem-object-catch-global-symbol-alist)))
(if index
(setf (nth index sniem-object-catch-global-symbol-alist)
(cons ',modename ',alist))
(setq sniem-object-catch-global-symbol-alist
(append (list (cons ',modename ',alist)) sniem-object-catch-global-symbol-alist)))))
(provide 'sniem-object-catch)
;;; sniem-object-catch.el ends here