Merge from emacs-24; up to 2012-12-22T19:09:52Z!rgm@gnu.org
[bpt/emacs.git] / lisp / progmodes / subword.el
CommitLineData
653d1554 1;;; subword.el --- Handling capitalized subwords in a nomenclature
0386b551 2
ab422c4d 3;; Copyright (C) 2004-2013 Free Software Foundation, Inc.
0386b551
AM
4
5;; Author: Masatake YAMATO
6
b1fc2b50
GM
7;; This file is part of GNU Emacs.
8
9;; GNU Emacs is free software: you can redistribute it and/or modify
0386b551 10;; it under the terms of the GNU General Public License as published by
b1fc2b50
GM
11;; the Free Software Foundation, either version 3 of the License, or
12;; (at your option) any later version.
0386b551 13
b1fc2b50 14;; GNU Emacs is distributed in the hope that it will be useful,
0386b551
AM
15;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17;; GNU General Public License for more details.
18
19;; You should have received a copy of the GNU General Public License
b1fc2b50 20;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
0386b551
AM
21
22;;; Commentary:
23
653d1554
TH
24;; This package was cc-submode.el before it was recognized being
25;; useful in general and not tied to C and c-mode at all.
26
0386b551 27;; This package provides `subword' oriented commands and a minor mode
653d1554 28;; (`subword-mode') that substitutes the common word handling
0386b551
AM
29;; functions with them.
30
31;; In spite of GNU Coding Standards, it is popular to name a symbol by
32;; mixing uppercase and lowercase letters, e.g. "GtkWidget",
33;; "EmacsFrameClass", "NSGraphicsContext", etc. Here we call these
34;; mixed case symbols `nomenclatures'. Also, each capitalized (or
35;; completely uppercase) part of a nomenclature is called a `subword'.
36;; Here are some examples:
37
38;; Nomenclature Subwords
39;; ===========================================================
40;; GtkWindow => "Gtk" and "Window"
41;; EmacsFrameClass => "Emacs", "Frame" and "Class"
42;; NSGraphicsContext => "NS", "Graphics" and "Context"
43
44;; The subword oriented commands defined in this package recognize
45;; subwords in a nomenclature to move between them and to edit them as
46;; words.
47
48;; In the minor mode, all common key bindings for word oriented
49;; commands are overridden by the subword oriented commands:
50
51;; Key Word oriented command Subword oriented command
52;; ============================================================
a9b76eec
TH
53;; M-f `forward-word' `subword-forward'
54;; M-b `backward-word' `subword-backward'
55;; M-@ `mark-word' `subword-mark'
56;; M-d `kill-word' `subword-kill'
57;; M-DEL `backward-kill-word' `subword-backward-kill'
58;; M-t `transpose-words' `subword-transpose'
59;; M-c `capitalize-word' `subword-capitalize'
60;; M-u `upcase-word' `subword-upcase'
61;; M-l `downcase-word' `subword-downcase'
0386b551
AM
62;;
63;; Note: If you have changed the key bindings for the word oriented
64;; commands in your .emacs or a similar place, the keys you've changed
65;; to are also used for the corresponding subword oriented commands.
66
67;; To make the mode turn on automatically, put the following code in
68;; your .emacs:
69;;
70;; (add-hook 'c-mode-common-hook
653d1554 71;; (lambda () (subword-mode 1)))
0386b551
AM
72;;
73
74;; Acknowledgment:
75;; The regular expressions to detect subwords are mostly based on
76;; the old `c-forward-into-nomenclature' originally contributed by
77;; Terry_Glanfield dot Southern at rxuk dot xerox dot com.
78
1ddb2ea0 79;; TODO: ispell-word.
0386b551
AM
80
81;;; Code:
82
1c308380
PS
83(defvar subword-forward-function 'subword-forward-internal
84 "Function to call for forward subword movement.")
85
86(defvar subword-backward-function 'subword-backward-internal
87 "Function to call for backward subword movement.")
88
89(defvar subword-forward-regexp
90 "\\W*\\(\\([[:upper:]]*\\W?\\)[[:lower:][:digit:]]*\\)"
91 "Regexp used by `subword-forward-internal'.")
92
93(defvar subword-backward-regexp
94 "\\(\\(\\W\\|[[:lower:][:digit:]]\\)\\([[:upper:]]+\\W*\\)\\|\\W\\w+\\)"
95 "Regexp used by `subword-backward-internal'.")
96
653d1554 97(defvar subword-mode-map
27558c0d 98 (let ((map (make-sparse-keymap)))
653d1554
TH
99 (dolist (cmd '(forward-word backward-word mark-word kill-word
100 backward-kill-word transpose-words
27558c0d
GM
101 capitalize-word upcase-word downcase-word))
102 (let ((othercmd (let ((name (symbol-name cmd)))
9ee12eee
TH
103 (string-match "\\([[:alpha:]-]+\\)-word[s]?" name)
104 (intern (concat "subword-" (match-string 1 name))))))
653d1554 105 (define-key map (vector 'remap cmd) othercmd)))
27558c0d 106 map)
653d1554 107 "Keymap used in `subword-mode' minor mode.")
27558c0d
GM
108
109;;;###autoload
653d1554 110(define-minor-mode subword-mode
ac6c8639
CY
111 "Toggle subword movement and editing (Subword mode).
112With a prefix argument ARG, enable Subword mode if ARG is
113positive, and disable it otherwise. If called from Lisp, enable
114the mode if ARG is omitted or nil.
115
116Subword mode is a buffer-local minor mode. Enabling it remaps
117word-based editing commands to subword-based commands that handle
118symbols with mixed uppercase and lowercase letters,
119e.g. \"GtkWidget\", \"EmacsFrameClass\", \"NSGraphicsContext\".
120
121Here we call these mixed case symbols `nomenclatures'. Each
122capitalized (or completely uppercase) part of a nomenclature is
123called a `subword'. Here are some examples:
0386b551
AM
124
125 Nomenclature Subwords
126 ===========================================================
127 GtkWindow => \"Gtk\" and \"Window\"
128 EmacsFrameClass => \"Emacs\", \"Frame\" and \"Class\"
129 NSGraphicsContext => \"NS\", \"Graphics\" and \"Context\"
130
131The subword oriented commands activated in this minor mode recognize
132subwords in a nomenclature to move between subwords and to edit them
133as words.
134
653d1554 135\\{subword-mode-map}"
0386b551
AM
136 nil
137 nil
653d1554
TH
138 subword-mode-map)
139
140(define-obsolete-function-alias 'c-subword-mode 'subword-mode "23.2")
0386b551 141
653d1554
TH
142;;;###autoload
143(define-global-minor-mode global-subword-mode subword-mode
144 (lambda () (subword-mode 1)))
145
a9b76eec 146(defun subword-forward (&optional arg)
0386b551 147 "Do the same as `forward-word' but on subwords.
653d1554 148See the command `subword-mode' for a description of subwords.
0386b551
AM
149Optional argument ARG is the same as for `forward-word'."
150 (interactive "p")
151 (unless arg (setq arg 1))
0386b551
AM
152 (cond
153 ((< 0 arg)
154 (dotimes (i arg (point))
1c308380 155 (funcall subword-forward-function)))
0386b551
AM
156 ((> 0 arg)
157 (dotimes (i (- arg) (point))
1c308380 158 (funcall subword-backward-function)))
0386b551
AM
159 (t
160 (point))))
161
a9b76eec 162(put 'subword-forward 'CUA 'move)
5e8c9892 163
a9b76eec 164(defun subword-backward (&optional arg)
0386b551 165 "Do the same as `backward-word' but on subwords.
653d1554 166See the command `subword-mode' for a description of subwords.
0386b551
AM
167Optional argument ARG is the same as for `backward-word'."
168 (interactive "p")
a9b76eec 169 (subword-forward (- (or arg 1))))
0386b551 170
a9b76eec 171(defun subword-mark (arg)
0386b551 172 "Do the same as `mark-word' but on subwords.
653d1554 173See the command `subword-mode' for a description of subwords.
0386b551
AM
174Optional argument ARG is the same as for `mark-word'."
175 ;; This code is almost copied from `mark-word' in GNU Emacs.
176 (interactive "p")
177 (cond ((and (eq last-command this-command) (mark t))
178 (set-mark
179 (save-excursion
180 (goto-char (mark))
a9b76eec 181 (subword-forward arg)
0386b551
AM
182 (point))))
183 (t
184 (push-mark
185 (save-excursion
a9b76eec 186 (subword-forward arg)
0386b551
AM
187 (point))
188 nil t))))
189
a9b76eec 190(put 'subword-backward 'CUA 'move)
5e8c9892 191
a9b76eec 192(defun subword-kill (arg)
0386b551 193 "Do the same as `kill-word' but on subwords.
653d1554 194See the command `subword-mode' for a description of subwords.
0386b551
AM
195Optional argument ARG is the same as for `kill-word'."
196 (interactive "p")
a9b76eec 197 (kill-region (point) (subword-forward arg)))
0386b551 198
a9b76eec 199(defun subword-backward-kill (arg)
0386b551 200 "Do the same as `backward-kill-word' but on subwords.
653d1554 201See the command `subword-mode' for a description of subwords.
0386b551
AM
202Optional argument ARG is the same as for `backward-kill-word'."
203 (interactive "p")
a9b76eec 204 (subword-kill (- arg)))
0386b551 205
a9b76eec 206(defun subword-transpose (arg)
0386b551 207 "Do the same as `transpose-words' but on subwords.
653d1554 208See the command `subword-mode' for a description of subwords.
0386b551
AM
209Optional argument ARG is the same as for `transpose-words'."
210 (interactive "*p")
a9b76eec 211 (transpose-subr 'subword-forward arg))
287787ee 212
a9b76eec 213(defun subword-downcase (arg)
287787ee 214 "Do the same as `downcase-word' but on subwords.
653d1554 215See the command `subword-mode' for a description of subwords.
287787ee
MY
216Optional argument ARG is the same as for `downcase-word'."
217 (interactive "p")
218 (let ((start (point)))
a9b76eec 219 (downcase-region (point) (subword-forward arg))
653d1554 220 (when (< arg 0)
287787ee
MY
221 (goto-char start))))
222
a9b76eec 223(defun subword-upcase (arg)
287787ee 224 "Do the same as `upcase-word' but on subwords.
653d1554 225See the command `subword-mode' for a description of subwords.
287787ee
MY
226Optional argument ARG is the same as for `upcase-word'."
227 (interactive "p")
228 (let ((start (point)))
a9b76eec 229 (upcase-region (point) (subword-forward arg))
653d1554 230 (when (< arg 0)
287787ee
MY
231 (goto-char start))))
232
a9b76eec 233(defun subword-capitalize (arg)
0386b551 234 "Do the same as `capitalize-word' but on subwords.
653d1554 235See the command `subword-mode' for a description of subwords.
0386b551
AM
236Optional argument ARG is the same as for `capitalize-word'."
237 (interactive "p")
238 (let ((count (abs arg))
11d13e96
MY
239 (start (point))
240 (advance (if (< arg 0) nil t)))
0386b551 241 (dotimes (i count)
11d13e96
MY
242 (if advance
243 (progn (re-search-forward
653d1554 244 (concat "[[:alpha:]]")
11d13e96
MY
245 nil t)
246 (goto-char (match-beginning 0)))
a9b76eec 247 (subword-backward))
0386b551
AM
248 (let* ((p (point))
249 (pp (1+ p))
a9b76eec 250 (np (subword-forward)))
0386b551
AM
251 (upcase-region p pp)
252 (downcase-region pp np)
11d13e96
MY
253 (goto-char (if advance np p))))
254 (unless advance
255 (goto-char start))))
0386b551 256
0386b551
AM
257
258\f
259;;
260;; Internal functions
261;;
a9b76eec 262(defun subword-forward-internal ()
0386b551 263 (if (and
5e8c9892 264 (save-excursion
0386b551 265 (let ((case-fold-search nil))
1c308380 266 (re-search-forward subword-forward-regexp nil t)))
653d1554 267 (> (match-end 0) (point)))
5e8c9892 268 (goto-char
0386b551
AM
269 (cond
270 ((< 1 (- (match-end 2) (match-beginning 2)))
271 (1- (match-end 2)))
272 (t
273 (match-end 0))))
274 (forward-word 1)))
275
276
a9b76eec 277(defun subword-backward-internal ()
5e8c9892
KS
278 (if (save-excursion
279 (let ((case-fold-search nil))
1c308380 280 (re-search-backward subword-backward-regexp nil t)))
5e8c9892
KS
281 (goto-char
282 (cond
0386b551
AM
283 ((and (match-end 3)
284 (< 1 (- (match-end 3) (match-beginning 3)))
285 (not (eq (point) (match-end 3))))
286 (1- (match-end 3)))
287 (t
288 (1+ (match-beginning 0)))))
289 (backward-word 1)))
290
291\f
653d1554 292(provide 'subword)
0386b551 293
653d1554 294;;; subword.el ends here