-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcamelCase-mode.el
302 lines (272 loc) · 12.3 KB
/
camelCase-mode.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
;;
;; http://www.cs.ucf.edu/~leavens/emacs/camelCase/camelCase-mode.el
;;
;;; camelCase-mode.el --- minor mode for editing with camelCase words
;; Copyright (C) 2001 C.R.Manning
;;
;; 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 2 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, write to the Free Software
;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
;;; History:
;; Author: C.R.Manning [email protected]
;; at http://www.ai.mit.edu/people/caroma/tools/
;; Created: 19 May 2001
;; last update: 20 May 2001
;; Keywords: camelCase camel case word mode
;; Tested on: Gnu Emacs 20.7, XEmacs 21.4
;;; Installation
;; Suggested GNU Emacs .emacs (or XEmacs .xemacs/init.el) initialization:
;; (autoload 'camelCase-mode "camelCase-mode" nil t)
;; (add-hook 'java-mode-hook '(lambda () (camelCase-mode 1)))
;; more global hooks: find-file-hooks, post-command-hook
;;; Description:
;; camelCase-mode is a Gnu Emacs minor mode which modifies the Emacs
;; forward-word, backward-word, delete-word, etc. keystroke-commands
;; so they also work on words within a <i>camelCase</i> identifier.
;; As a minor mode, camelCase-mode can be used within any other
;; editing mode --- Java-mode, text mode, etc. No functionality is
;; lost, since the forward s-expression, backward s-expression,
;; delete s-expression, etc. commands are still available to navigate
;; over entire camelCase names.
;;
;; Word boundaries in a camelCase name are marked only by letter case.
;; For example lowerCapitalUPPERCase has four words. A word may be
;; lowercase, Capitalized, UPPERCASE, or a sequence of digits. Besides
;; non-letter to letter and letter to non-letter word boundaries,
;; word boundaries in the middle of a sequence of letters are located at
;; lowercaseCapital, CapitalCapital, lowercaseUPPERCASE,
;; CapitalUPPERCASE, and UPPERCASECapital boundaries.
;;
;; Rebound keys:
;; M-f, M-right, C-right camelCase-forward-word
;; M-b, M-left, C-left camelCase-backward-word
;; M-d, camelCase-forward-kill-word
;; M-backspace, C-delete camelCase-backward-kill-word
;; M-t camelCase-transpose-words
;; M-c camelCase-capitalize-word
;; M-u camelCase-upcase-word
;; M-l camelCase-downcase-word
;;
;; camelCase-mode prefix arg: 0 turns off, 1 turns on, nil toggles mode.
;;; Subtleties
;; Handles uppercase acronyms within camelCase words. For example
;; "URLConnection" is like "URL-Connection", not "URLC-onnection"
;;; Limitations
;; Does not affect other Emacs functions which operate on words,
;; such as dabbrev-mode
;; M-t transpose-words does not change case of words. For example:
;; - transposing "fooBar" produces "Barfoo", not "barFoo".
;; - transposing "fooBAR" produces "BARfoo", not "BARFoo".
;; - transposing "fooBar baz" at space produces "foobaz Bar" not "fooBaz bar"
;; When this is an issue, capitalize words before transposing them,
;; e.g., M-b M-c M-t for the first two examples, or M-c M-b M-t for
;; the last one.
;;; Code:
;;; MODE:
(defvar camelCase-modeline-indicator " camelCase"
"call (camelCase-install-mode) again if this is changed")
(defvar camelCase-mode nil)
(make-variable-buffer-local 'camelCase-mode)
(put 'camelCase-mode 'permanent-local t)
(defun camelCase-mode (&optional arg)
"Minor mode which overrides word command keys for editing camelCase words.
Word boundaries in a camelCase name are marked only by letter case.
For example lowerCapitalUPPERCase has four words. A word may be
lowercase, Capitalized, UPPERCASE, or a sequence of digits. Besides
non-letter to letter and letter to non-letter word boundaries,
word boundaries in the middle of a sequence of letters are located at
lowercaseCapital, CapitalCapital, lowercaseUPPERCASE,
CapitalUPPERCASE, and UPPERCASECapital boundaries.
Rebound keys:
M-f, M-right*, C-right camelCase-forward-word
M-b, M-left*, C-left camelCase-backward-word
M-d, M-delete*, C-delete* camelCase-forward-kill-word
M-backspace, C-backspace* camelCase-backward-kill-word
M-t camelCase-transpose-words
M-c camelCase-capitalize-word
M-u camelCase-upcase-word
M-l camelCase-downcase-word
(* means only in Gnu Emacs, not in XEMacs; the original binding is not
to the word command in XEmacs, so it is not overridden)
camelCase-mode prefix ARG: 0 turns off, 1 turns on, nil toggles mode."
(interactive "P")
(setq camelCase-mode
(if (null arg) (not camelCase-mode)
(> (prefix-numeric-value arg) 0)))
(force-mode-line-update))
(defconst camelCase-keybindings-list
(cond ((memq 'xemacs features) ;; xemacs uses different key syntax
'(
("\M-f" camelCase-forward-word)
("\M-b" camelCase-backward-word)
("\M-d" camelCase-forward-kill-word)
("\M-DEL" camelCase-backward-kill-word)
("\M-t" camelCase-transpose-words)
("\M-c" camelCase-capitalize-word)
("\M-u" camelCase-upcase-word)
("\M-l" camelCase-downcase-word)
;((meta right) camelCase-forward-word)
;((meta left) camelCase-backward-word)
;((meta delete) camelCase-forward-kill-word)
;((meta backspace) camelCase-backward-kill-word)
;((control right) camelCase-forward-word)
;((control left) camelCase-backward-word)
;((control delete) camelCase-forward-kill-word)
;((control backspace) camelCase-backward-kill-word)
))
(t ;; assume recent gnu emacs (e.g., 20.7)
'(
("\M-f" camelCase-forward-word)
("\M-b" camelCase-backward-word)
("\M-d" camelCase-forward-kill-word)
("\M-DEL" camelCase-backward-kill-word)
("\M-t" camelCase-transpose-words)
("\M-c" camelCase-capitalize-word)
("\M-u" camelCase-upcase-word)
("\M-l" camelCase-downcase-word)
([\M-right] camelCase-forward-word)
([\M-left] camelCase-backward-word)
([\M-backspace] camelCase-backward-kill-word)
;([\M-delete] camelCase-forward-kill-word)
([\C-right] camelCase-forward-word)
([\C-left] camelCase-backward-word)
;; ([\C-delete] camelCase-forward-kill-word)
([\C-backspace] camelCase-backward-kill-word)
))
))
(defconst camelCase-mode-map
(let ((map (make-sparse-keymap)))
(mapcar (lambda (binding)
(define-key map (first binding) (second binding)))
camelCase-keybindings-list)
(fset 'camelCase-mode-map map)
map)
"keymap for camelCase minor mode.")
;; install the minor mode
(defun camelCase-add-minor-mode (mode-toggle-variable-name
modeline-indicator-string mode-map)
(let ((old-mode-entry (assq mode-toggle-variable-name minor-mode-alist)))
(setq minor-mode-alist
(cons (list mode-toggle-variable-name modeline-indicator-string)
(delq old-mode-entry minor-mode-alist))))
(let ((old-map-entry (assq mode-toggle-variable-name
minor-mode-map-alist)))
(setq minor-mode-map-alist
(cons (cons mode-toggle-variable-name mode-map)
(delq old-map-entry minor-mode-map-alist)))))
(defun camelCase-install-mode ()
;; call function without causing byte-compiler warning if other not defined
(let ((add-minor-mode-fn (if (and (memq 'xemacs features)
(fboundp 'add-minor-mode))
'add-minor-mode
'camelCase-add-minor-mode)))
(funcall add-minor-mode-fn
'camelCase-mode
camelCase-modeline-indicator
camelCase-mode-map)))
(camelCase-install-mode)
;;; COMMANDS:
(defconst camelCase-regexp "\\([A-Z]?[a-z]+\\|[A-Z]+\\|[0-9]+\\)"
;; capital must be before uppercase
"regular expression that matches a camelCase word, defined as
Capitalized, lowercase, or UPPERCASE sequence of letters,
or sequence of digits.")
(defun camelCase-forward-word (count)
"move point foward COUNT camelCase words"
(interactive "p")
;; search forward increments point until some match occurs;
;; extent of match is as large as possible at that point.
;; point is left at END of match.
(if (< count 0)
(camelCase-backward-word (- count))
(let ((old-case-fold-search case-fold-search)
(case-fold-search nil)) ;; search case sensitively
(unwind-protect
(when (re-search-forward camelCase-regexp nil t count)
;; something matched, just check for special case.
;; If uppercase acronym is in camelCase word as in "URLNext",
;; search will leave point after N rather than after L.
;; So if match starting back one char doesn't end same place,
;; then back-up one char.
(when (save-excursion
(let ((search-end (point)))
(forward-char -1)
(and (looking-at camelCase-regexp)
(not (= search-end (match-end 0))))))
(forward-char -1))
(point))
(setq case-fold-search old-case-fold-search)))))
(defun camelCase-backward-word (count)
"move point backward COUNT camelCase words"
(interactive "p")
;; search backward decrements point until some match occurs;
;; extent of match is as large as possible at that point.
;; So once point is found, have to keep decrementing point until we cross
;; into another word, which changes the match end.
;; for multiple words, have to do whole thing COUNT times.
(if (< count 0)
(camelCase-forward-word (- count))
(let ((start-position (point))
(old-case-fold-search case-fold-search)
(case-fold-search nil)) ;; search case-sensitively
(unwind-protect
(while (< 0 count)
(setq count (1- count))
(let ((start (point)))
(when (re-search-backward camelCase-regexp nil t)
(let ((end-word (match-end 0)))
(forward-char -1)
(while (save-excursion
;;like looking-at, but stop match at start
(let ((position (point)))
(re-search-forward camelCase-regexp start t)
(and (= position (match-beginning 0))
(= end-word (match-end 0)))))
(forward-char -1))
(forward-char 1)))))
(setq case-fold-search old-case-fold-search))
(if (= start-position (point)) nil (point)))))
(defun camelCase-forward-kill-word (count)
"kill text between current point and end of next camelCase word"
(interactive "*p")
(kill-region (point) (progn (camelCase-forward-word count) (point))))
(defun camelCase-backward-kill-word (count)
"kill text between current point and end of previous camelCase word"
(interactive "*p")
(kill-region (point) (progn (camelCase-backward-word count) (point))))
(defun camelCase-transpose-words (count)
"transpose camelCase words around point, leaving point afterward.
With prefix arg COUNT, moves word before point past COUNT words
forward or backward. If COUNT is 0, exchanges word around pont
with word around mark."
(interactive "*p")
(transpose-subr 'camelCase-forward-word count))
(defun camelCase-capitalize-word (count)
"Capitalize word starting at point, leaving point after word."
(interactive "*p")
(let ((start (point)))
(camelCase-forward-word count)
(capitalize-region start (point))))
(defun camelCase-upcase-word (count)
"Make word starting at point UPPERCASE, leaving point after word."
(interactive "*p")
(let ((start (point)))
(camelCase-forward-word count)
(upcase-region start (point))))
(defun camelCase-downcase-word (count)
"Make word starting at point lowercase, leaving point after word."
(interactive "*p")
(let ((start (point)))
(camelCase-forward-word count)
(downcase-region start (point))))
(provide 'camelCase)