25
25
26
26
; ;; Commentary:
27
27
28
- ; ; beginning-of-defun and end-of-defun
28
+ ; ; `beginning-of-defun' and `end-of-defun'
29
+ ; ;
30
+ ; ; The end of a defun is just after the close curly brace.
31
+ ; ;
32
+ ; ; The beginning of a defun is the beginning of:
33
+ ; ; - "func" keyword,
34
+ ; ; - its modifiers or attributes,
35
+ ; ; - comments on the same line.
36
+ ; ;
37
+ ; ; `swift-mode:beginning-of-defun' moves the point to the beginning of a defun
38
+ ; ; that precedes (if the arg is positive) or follows (if the arg is negative)
39
+ ; ; the original point and has the same or less nesting level.
40
+ ; ;
41
+ ; ; `swift-mode:end-of-defun' moves the point to the end of a defun
42
+ ; ; that follows (if the arg is positive) or precedes (if the arg is negative)
43
+ ; ; the original point and has the same or less nesting level.
29
44
30
45
; ;; Code:
31
46
32
47
(require 'swift-mode-lexer )
33
48
(require 'swift-mode-indent )
34
49
50
+ ;;;### autoload
51
+ (defcustom swift-mode:mark-defun-preference 'containing
52
+ " Preference for `swift-mode:mark-defun' for nested declarations.
53
+
54
+ Suppose the following code with the point located at A:
55
+
56
+ func outer() {
57
+ func inner1() {
58
+ }
59
+
60
+ // A
61
+
62
+ func inner2() {
63
+ }
64
+ }
65
+
66
+ If `swift-mode:mark-defun-preference' is `containing' , `swift-mode:mark-defun'
67
+ marks the `outer' function. Likewise, it marks `inner1' if the preference is
68
+ `preceding' and `inner2' if the preference is `following' ."
69
+ :type '(choice (const :tag " Containing" containing)
70
+ (const :tag " Preceding" preceding)
71
+ (const :tag " Following" following))
72
+ :group 'swift
73
+ :safe 'symbolp )
74
+
35
75
(defun swift-mode:beginning-of-defun (&optional arg )
36
76
" Move backward to the beginning of a defun.
37
77
38
- See `beginning-of-defun' for ARG."
39
- (interactive )
78
+ See `beginning-of-defun' for ARG.
79
+
80
+ Return t if a defun is found. Return nil otherwise.
81
+
82
+ Push mark at previous position if this is called as a command, not repeatedly,
83
+ and the region is not active."
84
+ (interactive " p" )
40
85
(setq arg (or arg 1 ))
41
- (let (result
42
- pos)
43
- (if (<= 0 arg)
86
+ (let ((result t )
87
+ (pos (point )))
88
+ (if (< 0 arg)
89
+ ; ; Moving backward
44
90
(progn
45
- (setq pos (point ))
46
- ; ; Special handling for the case that the cursor is between the
47
- ; ; beginning of the defun and the open curly brace of the defun.
48
- (when (< (save-excursion
49
- (swift-mode:beginning-of-statement)
50
- (point ))
51
- (point ))
52
- ; ; Searches forward { or end of a statement.
53
- (while (not
54
- (memq
55
- (swift-mode:token:type (swift-mode:forward-token-or-list))
56
- '({} implicit-\; \; } outside-of-buffer))))
57
- (when (eq (char-before ) ?} )
58
- (backward-list ))
59
- ; ; Skips implicit ;
60
- (forward-comment (point-max ))
61
- (if (swift-mode:is-point-before-body-of-defun)
62
- (progn
63
- (swift-mode:beginning-of-statement)
64
- (setq result t )
65
- (setq arg (1- arg)))
66
- (goto-char pos)))
67
- (while (< 0 arg)
68
- (setq result (swift-mode:beginning-of-defun-1
69
- #'swift-mode:backward-token-or-list ))
70
- (setq arg (1- arg))))
71
- (while (< arg 0 )
72
- ; ; If the cursor is on a defun, ensure the cursor is after the open
73
- ; ; curly brace of defun.
74
- (setq pos (point ))
75
- (swift-mode:beginning-of-statement)
76
- ; ; swift-mode:beginning-of-statement may forward the cursor if the
77
- ; ; cursor is on a comment or whitespace. In that case, does not skip
78
- ; ; the defun.
79
- (when (<= (point ) pos)
91
+ ; ; `swift-mode:beginning-of-defun-1' assumes the point is after
92
+ ; ; the open curly brace of defun. So moving the point to just after
93
+ ; ; the open curly brace if the current statement has one.
80
94
(while (not
81
95
(memq
82
- (swift-mode:token:type (swift-mode:forward-token-or-list))
83
- '({} } outside-of-buffer)))))
96
+ (swift-mode:token:type (swift-mode:forward-token))
97
+ '({ implicit-\; \; } outside-of-buffer))))
98
+ (backward-char )
99
+ ; ; Skips implicit-;
100
+ (forward-comment (point-max ))
101
+ (when (eq (char-after ) ?{ )
102
+ (forward-char ))
103
+
104
+ (setq result (swift-mode:beginning-of-defun-1
105
+ #'swift-mode:backward-token-or-list ))
106
+ (when (and result (< (point ) pos))
107
+ (setq arg (1- arg)))
84
108
109
+ (while (and result (< 0 arg))
110
+ (setq result (swift-mode:beginning-of-defun-1
111
+ #'swift-mode:backward-token-or-list ))
112
+ (setq arg (1- arg))))
113
+ ; ; Moving forward
114
+ (setq result (swift-mode:beginning-of-defun-1
115
+ (lambda ()
116
+ (prog1 (swift-mode:forward-token-or-list)
117
+ (forward-comment (point-max ))))))
118
+ (when (and result (< pos (point )))
119
+ (setq arg (1+ arg)))
120
+ (while (and result (< arg 0 ))
121
+ ; ; Skips the current statement
122
+ (while (not
123
+ (memq
124
+ (swift-mode:token:type (swift-mode:forward-token-or-list))
125
+ '({} implicit-\; \; } outside-of-buffer))))
85
126
(setq result (swift-mode:beginning-of-defun-1
86
127
(lambda ()
87
128
(prog1 (swift-mode:forward-token-or-list)
88
129
(forward-comment (point-max ))))))
89
130
(setq arg (1+ arg))))
131
+ (and result
132
+ (eq this-command 'swift-mode:beginning-of-defun )
133
+ (not (eq last-command 'swift-mode:beginning-of-defun ))
134
+ (not (region-active-p ))
135
+ (push-mark pos))
90
136
result))
91
137
92
138
(defun swift-mode:beginning-of-defun-1 (next-token-function )
@@ -101,7 +147,6 @@ NEXT-TOKEN-FUNCTION skips the preceding/following token."
101
147
(throw 'swift-mode:found-defun t )))
102
148
nil ))
103
149
104
-
105
150
(defun swift-mode:is-point-before-body-of-defun ()
106
151
" Return t it the point is just before the body of a defun.
107
152
@@ -132,8 +177,6 @@ Return nil otherwise."
132
177
(setq previous-token (swift-mode:backward-token-or-list))
133
178
(setq previous-type (swift-mode:token:type previous-token))
134
179
(setq previous-text (swift-mode:token:text previous-token)))
135
- (unless (bobp )
136
- (swift-mode:forward-token-simple))
137
180
(or (equal previous-text " init" )
138
181
(member previous-text defun-keywords))))))
139
182
@@ -153,7 +196,9 @@ Intended for internal use."
153
196
(progn
154
197
(forward-comment (- (point )))
155
198
(swift-mode:beginning-of-statement))
199
+ ; ; Excludes comments on previous lines.
156
200
(goto-char (swift-mode:token:end parent))
201
+ (forward-comment (- (point )))
157
202
(setq parent (save-excursion (swift-mode:backward-token)))
158
203
(forward-comment (point-max ))
159
204
(swift-mode:goto-non-comment-bol)
@@ -164,22 +209,32 @@ Intended for internal use."
164
209
(defun swift-mode:end-of-defun (&optional arg )
165
210
" Move forward to the end of a defun.
166
211
167
- See `end-of-defun' for ARG."
168
- (interactive )
212
+ See `end-of-defun' for ARG.
213
+
214
+ Return t if a defun is found. Return nil otherwise.
215
+
216
+ Push mark at previous position if this is called as a command, not repeatedly,
217
+ and the region is not active."
218
+ (interactive " p" )
169
219
(setq arg (or arg 1 ))
170
- (let (result)
220
+ (let (result
221
+ (pos (point )))
171
222
(if (<= 0 arg)
172
223
(while (< 0 arg)
173
224
(setq result (swift-mode:end-of-defun-1
174
- #'swift-mode:forward-token-or-list
175
- ))
225
+ #'swift-mode:forward-token-or-list ))
176
226
(setq arg (1- arg)))
177
227
(while (< arg 0 )
178
228
(setq result (swift-mode:end-of-defun-1
179
229
(lambda ()
180
230
(prog1 (swift-mode:backward-token-or-list)
181
231
(forward-comment (- (point )))))))
182
232
(setq arg (1+ arg))))
233
+ (and result
234
+ (eq this-command 'swift-mode:end-of-defun )
235
+ (not (eq last-command 'swift-mode:end-of-defun ))
236
+ (not (region-active-p ))
237
+ (push-mark pos))
183
238
result))
184
239
185
240
(defun swift-mode:end-of-defun-1 (next-token-function )
@@ -196,6 +251,156 @@ NEXT-TOKEN-FUNCTION skips the preceding/following token."
196
251
(throw 'swift-mode:found-defun t )))
197
252
nil ))
198
253
254
+ (defun swift-mode:mark-defun (&optional allow-extend )
255
+ " Put mark at the end of defun, point at the beginning of defun.
256
+
257
+ If the point is between defuns, mark depend on
258
+ `swift-mode:mark-defun-preference' .
259
+
260
+ If ALLOW-EXTEND is non-nil or called interactively, and the command is repeated
261
+ or the region is active, mark the following (if the point is before the mark)
262
+ or preceding (if the point is after the mark) defun. If that defun has lesser
263
+ nesting level, mark the whole outer defun."
264
+ (interactive (list t ))
265
+ (if (and allow-extend
266
+ (or
267
+ (and (eq last-command this-command) (mark t ))
268
+ (region-active-p )))
269
+ ; ; Extends region.
270
+ (let ((forward-p (<= (point ) (mark ))))
271
+ (set-mark
272
+ (save-excursion
273
+ (goto-char (mark ))
274
+ (if forward-p
275
+ (swift-mode:end-of-defun)
276
+ (swift-mode:beginning-of-defun))
277
+ (point )))
278
+ ; ; Marks the whole outer defun if it has lesser nesting level.
279
+ (if forward-p
280
+ (goto-char (min (point )
281
+ (save-excursion
282
+ (goto-char (mark ))
283
+ (swift-mode:beginning-of-defun)
284
+ (point ))))
285
+ (goto-char (max (point )
286
+ (save-excursion
287
+ (goto-char (mark ))
288
+ (swift-mode:end-of-defun)
289
+ (point ))))))
290
+ ; ; Marks new region.
291
+ (let ((region
292
+ (cond
293
+ ((eq swift-mode:mark-defun-preference 'containing )
294
+ (swift-mode:containing-defun-region))
295
+ ((eq swift-mode:mark-defun-preference 'preceding )
296
+ (swift-mode:preceding-defun-region))
297
+ ((eq swift-mode:mark-defun-preference 'following )
298
+ (swift-mode:following-defun-region)))))
299
+ (if region
300
+ (progn (push-mark (cdr region ) nil t )
301
+ (goto-char (car region ))
302
+ region )
303
+ (when (called-interactively-p 'interactive )
304
+ (message " No defun found " ))
305
+ nil ))))
306
+
307
+ (defun swift-mode:following-defun-region ()
308
+ " Return cons representing a region of following defun."
309
+ (save-excursion
310
+ (let* ((end (and (swift-mode:end-of-defun) (point )))
311
+ (beginning (and end (swift-mode:beginning-of-defun) (point ))))
312
+ (and beginning (cons beginning end)))))
313
+
314
+ (defun swift-mode:preceding-defun-region ()
315
+ " Return cons representing a region of preceding defun."
316
+ (save-excursion
317
+ (let* ((beginning (and (swift-mode:beginning-of-defun) (point )))
318
+ (end (and beginning (swift-mode:end-of-defun) (point ))))
319
+ (and end (cons beginning end)))))
320
+
321
+ (defun swift-mode:containing-defun-region ()
322
+ " Return cons representing a region of containing defun."
323
+ (let* ((pos (point ))
324
+ (region (swift-mode:following-defun-region))
325
+ (extended (and region
326
+ (swift-mode:extend-defun-region-with-spaces region ))))
327
+ (cond
328
+ ((and extended (<= (car extended) pos (cdr extended)))
329
+ region )
330
+
331
+ ((progn
332
+ (setq region (swift-mode:preceding-defun-region))
333
+ (setq extended (swift-mode:extend-defun-region-with-spaces region ))
334
+ (and extended (<= (car extended) pos (cdr extended))))
335
+ region )
336
+
337
+ (t
338
+ (catch 'swift-mode:found-defun
339
+ (while (swift-mode:end-of-defun)
340
+ (let ((end (point )))
341
+ (save-excursion
342
+ (swift-mode:beginning-of-defun)
343
+ (when (<= (point ) pos end)
344
+ (throw 'swift-mode:found-defun (cons (point ) end))))))
345
+ (cons (point-min ) (point-max )))))))
346
+
347
+ (defun swift-mode:extend-defun-region-with-spaces (region )
348
+ " Return REGION extended with surrounding spaces."
349
+ (let ((beginning (car region ))
350
+ (end (cdr region )))
351
+ (save-excursion
352
+ (goto-char beginning)
353
+ (skip-syntax-backward " " )
354
+ (setq beginning (point )))
355
+ (save-excursion
356
+ (goto-char end)
357
+ (skip-syntax-forward " " )
358
+ (setq end (point )))
359
+ (cons beginning end)))
360
+
361
+ (defun swift-mode:narrow-to-defun (&optional include-comments )
362
+ " Make text outside current defun invisible.
363
+
364
+ If the point is between defuns, mark depend on
365
+ `swift-mode:mark-defun-preference' .
366
+
367
+ Preceding comments are included if INCLUDE-COMMENTS is non-nil.
368
+ Interactively, the behavior depends on ‘narrow-to-defun-include-comments’."
369
+ (interactive (list narrow-to-defun-include-comments))
370
+ (let ((restriction (cons (point-min ) (point-max )))
371
+ region
372
+ extended)
373
+ (save-excursion
374
+ (widen )
375
+
376
+ (setq region
377
+ (cond
378
+ ((eq swift-mode:mark-defun-preference 'containing )
379
+ (swift-mode:containing-defun-region))
380
+ ((eq swift-mode:mark-defun-preference 'preceding )
381
+ (swift-mode:preceding-defun-region))
382
+ ((eq swift-mode:mark-defun-preference 'following )
383
+ (swift-mode:following-defun-region))))
384
+
385
+ (setq extended
386
+ (and region (swift-mode:extend-defun-region-with-spaces region )))
387
+
388
+ (when (and extended include-comments)
389
+ (save-excursion
390
+ (goto-char (car extended))
391
+ ; ; Includes comments.
392
+ (forward-comment (- (point )))
393
+ ; ; Excludes spaces and line breaks.
394
+ (skip-syntax-forward " >" )
395
+ ; ; Includes indentation.
396
+ (skip-syntax-backward " " )
397
+ (setcar extended (point ))))
398
+
399
+ (if extended
400
+ (narrow-to-region (car extended) (cdr extended))
401
+ (when (called-interactively-p 'interactive )
402
+ (message " No defun found " ))
403
+ (narrow-to-region (car restriction) (cdr restriction))))))
199
404
200
405
(provide 'swift-mode-beginning-of-defun )
201
406
0 commit comments