(propertized-buffer-identification): Use face
[bpt/emacs.git] / lisp / progmodes / cc-subword.el
CommitLineData
0386b551
AM
1;;; cc-subword.el --- Handling capitalized subwords in a nomenclature
2
3;; Copyright (C) 2004, 2005 Free Software Foundation, Inc.
4
5;; Author: Masatake YAMATO
6
7;; This program is free software; you can redistribute it and/or modify
8;; it under the terms of the GNU General Public License as published by
9;; the Free Software Foundation; either version 2, or (at your option)
10;; any later version.
11
12;; This program is distributed in the hope that it will be useful,
13;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15;; GNU General Public License for more details.
16
17;; You should have received a copy of the GNU General Public License
18;; along with this program; see the file COPYING. If not, write to
19;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20;; Boston, MA 02110-1301, USA.
21
22;;; Commentary:
23
24;; This package provides `subword' oriented commands and a minor mode
25;; (`c-subword-mode') that substitutes the common word handling
26;; functions with them.
27
28;; In spite of GNU Coding Standards, it is popular to name a symbol by
29;; mixing uppercase and lowercase letters, e.g. "GtkWidget",
30;; "EmacsFrameClass", "NSGraphicsContext", etc. Here we call these
31;; mixed case symbols `nomenclatures'. Also, each capitalized (or
32;; completely uppercase) part of a nomenclature is called a `subword'.
33;; Here are some examples:
34
35;; Nomenclature Subwords
36;; ===========================================================
37;; GtkWindow => "Gtk" and "Window"
38;; EmacsFrameClass => "Emacs", "Frame" and "Class"
39;; NSGraphicsContext => "NS", "Graphics" and "Context"
40
41;; The subword oriented commands defined in this package recognize
42;; subwords in a nomenclature to move between them and to edit them as
43;; words.
44
45;; In the minor mode, all common key bindings for word oriented
46;; commands are overridden by the subword oriented commands:
47
48;; Key Word oriented command Subword oriented command
49;; ============================================================
50;; M-f `forward-word' `c-forward-subword'
51;; M-b `backward-word' `c-backward-subword'
52;; M-@ `mark-word' `c-mark-subword'
53;; M-d `kill-word' `c-kill-subword'
54;; M-DEL `backward-kill-word' `c-backward-kill-subword'
55;; M-t `transpose-words' `c-transpose-subwords'
56;; M-c `capitalize-word' `c-capitalize-subword'
57;; M-u `upcase-word' `c-upcase-subword'
58;; M-l `downcase-word' `c-downcase-subword'
59;;
60;; Note: If you have changed the key bindings for the word oriented
61;; commands in your .emacs or a similar place, the keys you've changed
62;; to are also used for the corresponding subword oriented commands.
63
64;; To make the mode turn on automatically, put the following code in
65;; your .emacs:
66;;
67;; (add-hook 'c-mode-common-hook
68;; (lambda () (c-subword-mode 1)))
69;;
70
71;; Acknowledgment:
72;; The regular expressions to detect subwords are mostly based on
73;; the old `c-forward-into-nomenclature' originally contributed by
74;; Terry_Glanfield dot Southern at rxuk dot xerox dot com.
75
76;; TODO: ispell-word and subword oriented C-w in isearch.
77
78;;; Code:
79
80(eval-when-compile
81 (let ((load-path
82 (if (and (boundp 'byte-compile-dest-file)
83 (stringp byte-compile-dest-file))
84 (cons (file-name-directory byte-compile-dest-file) load-path)
85 load-path)))
86 (load "cc-bytecomp" nil t)))
87
88(cc-require 'cc-defs)
89(cc-require 'cc-cmds)
90
91;; Don't complain about the `define-minor-mode' form if it isn't defined.
92(cc-bytecomp-defvar c-subword-mode)
93
94;;; Autoload directives must be on the top level, so we construct an
95;;; autoload form instead.
96;;;###autoload (autoload 'c-subword-mode "cc-subword" "Mode enabling subword movement and editing keys." t)
97
98(if (not (fboundp 'define-minor-mode))
99 (defun c-subword-mode ()
100 "(Missing) mode enabling subword movement and editing keys.
101This mode is not (yet) available in this version of (X)Emacs. Sorry! If
102you really want it, please send a request to <bug-gnu-emacs@gnu.org>,
103telling us which (X)Emacs version you're using."
104 (interactive)
105 (error
106 "c-subword-mode is not (yet) available in this version of (X)Emacs. Sorry!"))
107
108 (defvar c-subword-mode-map
109 (let ((map (make-sparse-keymap)))
110 (substitute-key-definition 'forward-word
111 'c-forward-subword
112 map global-map)
113 (substitute-key-definition 'backward-word
114 'c-backward-subword
115 map global-map)
116 (substitute-key-definition 'mark-word
117 'c-mark-subword
118 map global-map)
119
120 (substitute-key-definition 'kill-word
121 'c-kill-subword
122 map global-map)
123 (substitute-key-definition 'backward-kill-word
124 'c-backward-kill-subword
125 map global-map)
126
127 (substitute-key-definition 'transpose-words
128 'c-transpose-subwords
129 map global-map)
130
131 (substitute-key-definition 'capitalize-word
132 'c-capitalize-subword
133 map global-map)
134 (substitute-key-definition 'upcase-word
135 'c-upcase-subword
136 map global-map)
137 (substitute-key-definition 'downcase-word
138 'c-downcase-subword
139 map global-map)
140 map)
141 "Keymap used in command `c-subword-mode' minor mode.")
142
143 (define-minor-mode c-subword-mode
144 "Mode enabling subword movement and editing keys.
145In spite of GNU Coding Standards, it is popular to name a symbol by
146mixing uppercase and lowercase letters, e.g. \"GtkWidget\",
147\"EmacsFrameClass\", \"NSGraphicsContext\", etc. Here we call these
148mixed case symbols `nomenclatures'. Also, each capitalized (or
149completely uppercase) part of a nomenclature is called a `subword'.
150Here are some examples:
151
152 Nomenclature Subwords
153 ===========================================================
154 GtkWindow => \"Gtk\" and \"Window\"
155 EmacsFrameClass => \"Emacs\", \"Frame\" and \"Class\"
156 NSGraphicsContext => \"NS\", \"Graphics\" and \"Context\"
157
158The subword oriented commands activated in this minor mode recognize
159subwords in a nomenclature to move between subwords and to edit them
160as words.
161
162\\{c-subword-mode-map}"
163 nil
164 nil
165 c-subword-mode-map
166 (c-update-modeline))
167
168 )
169
170(defun c-forward-subword (&optional arg)
171 "Do the same as `forward-word' but on subwords.
172See the command `c-subword-mode' for a description of subwords.
173Optional argument ARG is the same as for `forward-word'."
174 (interactive "p")
175 (unless arg (setq arg 1))
176 (c-keep-region-active)
177 (cond
178 ((< 0 arg)
179 (dotimes (i arg (point))
180 (c-forward-subword-internal)))
181 ((> 0 arg)
182 (dotimes (i (- arg) (point))
183 (c-backward-subword-internal)))
184 (t
185 (point))))
186
187(defun c-backward-subword (&optional arg)
188 "Do the same as `backward-word' but on subwords.
189See the command `c-subword-mode' for a description of subwords.
190Optional argument ARG is the same as for `backward-word'."
191 (interactive "p")
192 (c-forward-subword (- (or arg 1))))
193
194(defun c-mark-subword (arg)
195 "Do the same as `mark-word' but on subwords.
196See the command `c-subword-mode' for a description of subwords.
197Optional argument ARG is the same as for `mark-word'."
198 ;; This code is almost copied from `mark-word' in GNU Emacs.
199 (interactive "p")
200 (cond ((and (eq last-command this-command) (mark t))
201 (set-mark
202 (save-excursion
203 (goto-char (mark))
204 (c-forward-subword arg)
205 (point))))
206 (t
207 (push-mark
208 (save-excursion
209 (c-forward-subword arg)
210 (point))
211 nil t))))
212
213(defun c-kill-subword (arg)
214 "Do the same as `kill-word' but on subwords.
215See the command `c-subword-mode' for a description of subwords.
216Optional argument ARG is the same as for `kill-word'."
217 (interactive "p")
218 (kill-region (point) (c-forward-subword arg)))
219
220(defun c-backward-kill-subword (arg)
221 "Do the same as `backward-kill-word' but on subwords.
222See the command `c-subword-mode' for a description of subwords.
223Optional argument ARG is the same as for `backward-kill-word'."
224 (interactive "p")
225 (c-kill-subword (- arg)))
226
227(defun c-transpose-subwords (arg)
228 "Do the same as `transpose-words' but on subwords.
229See the command `c-subword-mode' for a description of subwords.
230Optional argument ARG is the same as for `transpose-words'."
231 (interactive "*p")
232 (transpose-subr 'c-forward-subword arg))
233
234(defun c-capitalize-subword (arg)
235 "Do the same as `capitalize-word' but on subwords.
236See the command `c-subword-mode' for a description of subwords.
237Optional argument ARG is the same as for `capitalize-word'."
238 (interactive "p")
239 (let ((count (abs arg))
240 (direction (if (< 0 arg) 1 -1)))
241 (dotimes (i count)
242 (when (re-search-forward
243 (concat "[" c-alpha "]")
244 nil t)
245 (goto-char (match-beginning 0)))
246 (let* ((p (point))
247 (pp (1+ p))
248 (np (c-forward-subword direction)))
249 (upcase-region p pp)
250 (downcase-region pp np)
251 (goto-char np)))))
252
253(defun c-downcase-subword (arg)
254 "Do the same as `downcase-word' but on subwords.
255See the command `c-subword-mode' for a description of subwords.
256Optional argument ARG is the same as for `downcase-word'."
257 (interactive "p")
258 (downcase-region (point) (c-forward-subword arg)))
259
260(defun c-upcase-subword (arg)
261 "Do the same as `upcase-word' but on subwords.
262See the command `c-subword-mode' for a description of subwords.
263Optional argument ARG is the same as for `upcase-word'."
264 (interactive "p")
265 (upcase-region (point) (c-forward-subword arg)))
266
267\f
268;;
269;; Internal functions
270;;
271(defun c-forward-subword-internal ()
272 (if (and
273 (save-excursion
274 (let ((case-fold-search nil))
275 (re-search-forward
276 (concat "\\W*\\(\\([" c-upper "]*\\W?\\)[" c-lower c-digit "]*\\)")
277 nil t)))
278 (> (match-end 0) (point))) ; So we don't get stuck at a
279 ; "word-constituent" which isn't c-upper,
280 ; c-lower or c-digit
281 (goto-char
282 (cond
283 ((< 1 (- (match-end 2) (match-beginning 2)))
284 (1- (match-end 2)))
285 (t
286 (match-end 0))))
287 (forward-word 1)))
288
289
290(defun c-backward-subword-internal ()
291 (if (save-excursion
292 (let ((case-fold-search nil))
293 (re-search-backward
294 (concat
295 "\\(\\(\\W\\|[" c-lower c-digit "]\\)\\([" c-upper "]+\\W*\\)"
296 "\\|\\W\\w+\\)")
297 nil t)))
298 (goto-char
299 (cond
300 ((and (match-end 3)
301 (< 1 (- (match-end 3) (match-beginning 3)))
302 (not (eq (point) (match-end 3))))
303 (1- (match-end 3)))
304 (t
305 (1+ (match-beginning 0)))))
306 (backward-word 1)))
307
308\f
309(cc-provide 'cc-subword)
310
311;;; arch-tag: 2be9d294-7f30-4626-95e6-9964bb93c7a3
312;;; cc-subword.el ends here