diff options
| author | Kim F. Storm | 2002-04-28 21:48:39 +0000 |
|---|---|---|
| committer | Kim F. Storm | 2002-04-28 21:48:39 +0000 |
| commit | 72cc582e6971d28f6c9110433578ced2d46ace46 (patch) | |
| tree | eade6543f791354de7428fbb2d3d06c66546a1bd | |
| parent | b098e7532377c75bc79e03212de2890cb08d145f (diff) | |
| download | emacs-72cc582e6971d28f6c9110433578ced2d46ace46.tar.gz emacs-72cc582e6971d28f6c9110433578ced2d46ace46.zip | |
Added cua-mode based files [split from original cua.el]:
cua-base.el, cua-rect.el, cua-gmrk.el, and keypad.el
| -rw-r--r-- | lisp/emulation/cua-base.el | 1133 | ||||
| -rw-r--r-- | lisp/emulation/cua-gmrk.el | 385 | ||||
| -rw-r--r-- | lisp/emulation/cua-rect.el | 1375 | ||||
| -rw-r--r-- | lisp/emulation/keypad.el | 185 |
4 files changed, 3078 insertions, 0 deletions
diff --git a/lisp/emulation/cua-base.el b/lisp/emulation/cua-base.el new file mode 100644 index 00000000000..c60ccacbb48 --- /dev/null +++ b/lisp/emulation/cua-base.el | |||
| @@ -0,0 +1,1133 @@ | |||
| 1 | ;;; cua-base.el --- emulate CUA key bindings | ||
| 2 | |||
| 3 | ;; Copyright (C) 1997-2002 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | ;; Author: Kim F. Storm <storm@cua.dk> | ||
| 6 | ;; Keywords: keyboard emulation convenience cua | ||
| 7 | |||
| 8 | ;; This file is part of GNU Emacs. | ||
| 9 | |||
| 10 | ;; GNU Emacs is free software; you can redistribute it and/or modify | ||
| 11 | ;; it under the terms of the GNU General Public License as published by | ||
| 12 | ;; the Free Software Foundation; either version 2, or (at your option) | ||
| 13 | ;; any later version. | ||
| 14 | |||
| 15 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 18 | ;; GNU General Public License for more details. | ||
| 19 | |||
| 20 | ;; You should have received a copy of the GNU General Public License | ||
| 21 | ;; along with GNU Emacs; see the file COPYING. If not, write to the | ||
| 22 | ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
| 23 | ;; Boston, MA 02111-1307, USA. | ||
| 24 | |||
| 25 | |||
| 26 | ;;; Commentary: | ||
| 27 | |||
| 28 | ;; This is the CUA package which provides a complete emulation of the | ||
| 29 | ;; standard CUA key bindings (Motif/Windows/Mac GUI) for selecting and | ||
| 30 | ;; manipulating the region where S-<movement> is used to highlight & | ||
| 31 | ;; extend the region. | ||
| 32 | |||
| 33 | ;; This package allow the C-z, C-x, C-c, and C-v keys to be | ||
| 34 | ;; bound appropriately according to the Motif/Windows GUI, i.e. | ||
| 35 | ;; C-z -> undo | ||
| 36 | ;; C-x -> cut | ||
| 37 | ;; C-c -> copy | ||
| 38 | ;; C-v -> paste | ||
| 39 | ;; | ||
| 40 | ;; The tricky part is the handling of the C-x and C-c keys which | ||
| 41 | ;; are normally used as prefix keys for most of emacs' built-in | ||
| 42 | ;; commands. With CUA they still do!!! | ||
| 43 | ;; | ||
| 44 | ;; Only when the region is currently active (and highlighted since | ||
| 45 | ;; transient-mark-mode is used), the C-x and C-c keys will work as CUA | ||
| 46 | ;; keys | ||
| 47 | ;; C-x -> cut | ||
| 48 | ;; C-c -> copy | ||
| 49 | ;; When the region is not active, C-x and C-c works as prefix keys! | ||
| 50 | ;; | ||
| 51 | ;; This probably sounds strange and difficult to get used to - but | ||
| 52 | ;; based on my own experience and the feedback from many users of | ||
| 53 | ;; this package, it actually works very well and users adapt to it | ||
| 54 | ;; instantly - or at least very quickly. So give it a try! | ||
| 55 | ;; ... and in the few cases where you make a mistake and accidentally | ||
| 56 | ;; delete the region - you just undo the mistake (with C-z). | ||
| 57 | ;; | ||
| 58 | ;; If you really need to perform a command which starts with one of | ||
| 59 | ;; the prefix keys even when the region is active, you have three options: | ||
| 60 | ;; - press the prefix key twice very quickly (within 0.2 seconds), | ||
| 61 | ;; - press the prefix key and the following key within 0.2 seconds), or | ||
| 62 | ;; - use the SHIFT key with the prefix key, i.e. C-X or C-C | ||
| 63 | ;; | ||
| 64 | ;; This behaviour can be customized via the | ||
| 65 | ;; cua-prefix-override-inhibit-delay variable. | ||
| 66 | |||
| 67 | ;; In addition to using the shifted movement keys, you can also use | ||
| 68 | ;; [C-space] to start the region and use unshifted movement keys to extend | ||
| 69 | ;; it. To cancel the region, use [C-space] or [C-g]. | ||
| 70 | |||
| 71 | ;; If you prefer to use the standard emacs cut, copy, paste, and undo | ||
| 72 | ;; bindings, customize cua-enable-cua-keys to nil. | ||
| 73 | |||
| 74 | ;; CUA mode indications | ||
| 75 | ;; -------------------- | ||
| 76 | ;; You can choose to let CUA use different cursor colors to indicate | ||
| 77 | ;; overwrite mode and read-only buffers. For example, the following | ||
| 78 | ;; setting will use a RED cursor in normal (insertion) mode in | ||
| 79 | ;; read-write buffers, a YELLOW cursor in overwrite mode in read-write | ||
| 80 | ;; buffers, and a GREEN cursor read-only buffers: | ||
| 81 | ;; | ||
| 82 | ;; (setq cua-normal-cursor-color "red") | ||
| 83 | ;; (setq cua-overwrite-cursor-color "yellow") | ||
| 84 | ;; (setq cua-read-only-cursor-color "green") | ||
| 85 | ;; | ||
| 86 | |||
| 87 | ;; CUA register support | ||
| 88 | ;; -------------------- | ||
| 89 | ;; Emacs' standard register support is also based on a separate set of | ||
| 90 | ;; "register commands". | ||
| 91 | ;; | ||
| 92 | ;; CUA's register support is activated by providing a numeric | ||
| 93 | ;; prefix argument to the C-x, C-c, and C-v commands. For example, | ||
| 94 | ;; to copy the selected region to register 2, enter [M-2 C-c]. | ||
| 95 | ;; Or if you have activated the keypad prefix mode, enter [kp-2 C-c]. | ||
| 96 | ;; | ||
| 97 | ;; And CUA will copy and paste normal region as well as rectangles | ||
| 98 | ;; into the registers, i.e. you use exactly the same command for both. | ||
| 99 | ;; | ||
| 100 | ;; In addition, the last highlighted text that is deleted (not | ||
| 101 | ;; copied), e.g. by [delete] or by typing text over a highlighted | ||
| 102 | ;; region, is automatically saved in register 0, so you can insert it | ||
| 103 | ;; using [M-0 C-v]. | ||
| 104 | |||
| 105 | ;; CUA rectangle support | ||
| 106 | ;; --------------------- | ||
| 107 | ;; Emacs' normal rectangle support is based on interpreting the region | ||
| 108 | ;; between the mark and point as a "virtual rectangle", and using a | ||
| 109 | ;; completely separate set of "rectangle commands" [C-x r ...] on the | ||
| 110 | ;; region to copy, kill, fill a.s.o. the virtual rectangle. | ||
| 111 | ;; | ||
| 112 | ;; cua-mode's superior rectangle support is based on using a true visual | ||
| 113 | ;; representation of the selected rectangle. To start a rectangle, use | ||
| 114 | ;; [S-return] and extend it using the normal movement keys (up, down, | ||
| 115 | ;; left, right, home, end, C-home, C-end). Once the rectangle has the | ||
| 116 | ;; desired size, you can cut or copy it using C-x and C-c (or C-w and M-w), | ||
| 117 | ;; and you can subsequently insert it - as a rectangle - using C-v (or | ||
| 118 | ;; C-y). So the only new command you need to know to work with | ||
| 119 | ;; cua-mode rectangles is S-return! | ||
| 120 | ;; | ||
| 121 | ;; Normally, when you paste a rectangle using C-v (C-y), each line of | ||
| 122 | ;; the rectangle is inserted into the existing lines in the buffer. | ||
| 123 | ;; If overwrite-mode is active when you paste a rectangle, it is | ||
| 124 | ;; inserted as normal (multi-line) text. | ||
| 125 | ;; | ||
| 126 | ;; Furthermore, cua-mode's rectangles are not limited to the actual | ||
| 127 | ;; contents of the buffer, so if the cursor is currently at the end of a | ||
| 128 | ;; short line, you can still extend the rectangle to include more columns | ||
| 129 | ;; of longer lines in the same rectangle. Sounds strange? Try it! | ||
| 130 | ;; | ||
| 131 | ;; You can enable padding for just this rectangle by pressing [M-p]; | ||
| 132 | ;; this works like entering `picture-mode' where the tabs and spaces | ||
| 133 | ;; are automatically converted/inserted to make the rectangle truly | ||
| 134 | ;; rectangular. Or you can do it for all rectangles by setting the | ||
| 135 | ;; `cua-auto-expand-rectangles' variable. | ||
| 136 | |||
| 137 | ;; And there's more: If you want to extend or reduce the size of the | ||
| 138 | ;; rectangle in one of the other corners of the rectangle, just use | ||
| 139 | ;; [return] to move the cursor to the "next" corner. Or you can use | ||
| 140 | ;; the [M-up], [M-down], [M-left], and [M-right] keys to move the | ||
| 141 | ;; entire rectangle overlay (but not the contents) in the given | ||
| 142 | ;; direction. | ||
| 143 | ;; | ||
| 144 | ;; [S-return] cancels the rectangle | ||
| 145 | ;; [C-space] activates the region bounded by the rectangle | ||
| 146 | |||
| 147 | ;; If you type a normal (self-inserting) character when the rectangle is | ||
| 148 | ;; active, the character is inserted on the "current side" of every line | ||
| 149 | ;; of the rectangle. The "current side" is the side on which the cursor | ||
| 150 | ;; is currently located. If the rectangle is only 1 column wide, | ||
| 151 | ;; insertion will be performed to the left when the cursor is at the | ||
| 152 | ;; bottom of the rectangle. So, for example, to comment out an entire | ||
| 153 | ;; paragraph like this one, just place the cursor on the first character | ||
| 154 | ;; of the first line, and enter the following: | ||
| 155 | ;; S-return M-} ; ; <space> S-return | ||
| 156 | |||
| 157 | ;; cua-mode's rectangle support also includes all the normal rectangle | ||
| 158 | ;; functions with easy access: | ||
| 159 | ;; | ||
| 160 | ;; [M-a] aligns all words at the left edge of the rectangle | ||
| 161 | ;; [M-b] fills the rectangle with blanks (tabs and spaces) | ||
| 162 | ;; [M-c] closes the rectangle by removing all blanks at the left edge | ||
| 163 | ;; of the rectangle | ||
| 164 | ;; [M-f] fills the rectangle with a single character (prompt) | ||
| 165 | ;; [M-i] increases the first number found on each line of the rectangle | ||
| 166 | ;; by the amount given by the numeric prefix argument (default 1) | ||
| 167 | ;; It recognizes 0x... as hexadecimal numbers | ||
| 168 | ;; [M-k] kills the rectangle as normal multi-line text (for paste) | ||
| 169 | ;; [M-l] downcases the rectangle | ||
| 170 | ;; [M-m] copies the rectangle as normal multi-line text (for paste) | ||
| 171 | ;; [M-n] fills each line of the rectangle with increasing numbers using | ||
| 172 | ;; a supplied format string (prompt) | ||
| 173 | ;; [M-o] opens the rectangle by moving the highlighted text to the | ||
| 174 | ;; right of the rectangle and filling the rectangle with blanks. | ||
| 175 | ;; [M-p] toggles rectangle padding, i.e. insert tabs and spaces to | ||
| 176 | ;; make rectangles truly rectangular | ||
| 177 | ;; [M-q] performs text filling on the rectangle | ||
| 178 | ;; [M-r] replaces REGEXP (prompt) by STRING (prompt) in rectangle | ||
| 179 | ;; [M-R] reverse the lines in the rectangle | ||
| 180 | ;; [M-s] fills each line of the rectangle with the same STRING (prompt) | ||
| 181 | ;; [M-t] performs text fill of the rectangle with TEXT (prompt) | ||
| 182 | ;; [M-u] upcases the rectangle | ||
| 183 | ;; [M-|] runs shell command on rectangle | ||
| 184 | ;; [M-'] restricts rectangle to lines with CHAR (prompt) at left column | ||
| 185 | ;; [M-/] restricts rectangle to lines matching REGEXP (prompt) | ||
| 186 | ;; [C-?] Shows a brief list of the above commands. | ||
| 187 | |||
| 188 | ;; [M-C-up] and [M-C-down] scrolls the lines INSIDE the rectangle up | ||
| 189 | ;; and down; lines scrolled outside the top or bottom of the rectangle | ||
| 190 | ;; are lost, but can be recovered using [C-z]. | ||
| 191 | |||
| 192 | ;; CUA Global Mark | ||
| 193 | ;; --------------- | ||
| 194 | ;; The final feature provided by CUA is the "global mark", which | ||
| 195 | ;; makes it very easy to copy bits and pieces from the same and other | ||
| 196 | ;; files into the current text. To enable and cancel the global mark, | ||
| 197 | ;; use [S-C-space]. The cursor will blink when the global mark | ||
| 198 | ;; is active. The following commands behave differently when the global | ||
| 199 | ;; mark is set: | ||
| 200 | ;; <ch> All characters (including newlines) you type are inserted | ||
| 201 | ;; at the global mark! | ||
| 202 | ;; [C-x] If you cut a region or rectangle, it is automatically inserted | ||
| 203 | ;; at the global mark, and the global mark is advanced. | ||
| 204 | ;; [C-c] If you copy a region or rectangle, it is immediately inserted | ||
| 205 | ;; at the global mark, and the global mark is advanced. | ||
| 206 | ;; [C-v] Copies a single character to the global mark. | ||
| 207 | ;; [C-d] Moves (i.e. deletes and inserts) a single character to the | ||
| 208 | ;; global mark. | ||
| 209 | ;; [backspace] deletes the character before the global mark, while | ||
| 210 | ;; [delete] deltes the character after the global mark. | ||
| 211 | |||
| 212 | ;; [S-C-space] Jumps to and cancels the global mark. | ||
| 213 | ;; [C-u S-C-space] Cancels the global mark (stays in current buffer). | ||
| 214 | |||
| 215 | ;; [TAB] Indents the current line or rectangle to the column of the | ||
| 216 | ;; global mark. | ||
| 217 | |||
| 218 | ;;; Code: | ||
| 219 | |||
| 220 | ;;; Customization | ||
| 221 | |||
| 222 | (defgroup cua nil | ||
| 223 | "Emulate CUA key bindings including C-x and C-c." | ||
| 224 | :prefix "cua" | ||
| 225 | :group 'editing-basics | ||
| 226 | :group 'convenience | ||
| 227 | :group 'emulations | ||
| 228 | :link '(emacs-commentary-link :tag "Commentary" "cua-base.el") | ||
| 229 | :link '(emacs-library-link :tag "Lisp File" "cua-base.el")) | ||
| 230 | |||
| 231 | ;;;###autoload | ||
| 232 | (defcustom cua-mode nil | ||
| 233 | "Non-nil means that CUA emulation mode is enabled. | ||
| 234 | In CUA mode, shifted movement keys highlight and extend the region. | ||
| 235 | When a region is highlighted, the binding of the C-x and C-c keys are | ||
| 236 | temporarily changed to work as Motif, MAC or MS-Windows cut and paste. | ||
| 237 | Also, insertion commands first delete the region and then insert. | ||
| 238 | This mode enables Transient Mark mode and it provides a superset of the | ||
| 239 | PC Selection Mode and Delete Selection Modes. | ||
| 240 | |||
| 241 | Setting this variable directly does not take effect; | ||
| 242 | use either \\[customize] or the function `cua-mode'." | ||
| 243 | :set (lambda (symbol value) | ||
| 244 | (cua-mode (or value 0))) | ||
| 245 | :initialize 'custom-initialize-default | ||
| 246 | :set-after '(cua-enable-modeline-indications cua-use-hyper-key) | ||
| 247 | :require 'cua | ||
| 248 | :link '(emacs-commentary-link "cua-base.el") | ||
| 249 | :version "21.4" | ||
| 250 | :type 'boolean | ||
| 251 | :group 'cua) | ||
| 252 | |||
| 253 | |||
| 254 | (defcustom cua-enable-cua-keys t | ||
| 255 | "*Enable using C-z, C-x, C-c, and C-v for undo, cut, copy, and paste. | ||
| 256 | If the value is t, these mappings are always enabled. If the value is | ||
| 257 | 'shift, these keys are only enabled if the last region was marked with | ||
| 258 | a shifted movement key. If the value is nil, these keys are never | ||
| 259 | enabled." | ||
| 260 | :type '(choice (const :tag "Disabled" nil) | ||
| 261 | (const :tag "Shift region only" shift) | ||
| 262 | (other :tag "Enabled")) | ||
| 263 | :group 'cua) | ||
| 264 | |||
| 265 | (defcustom cua-highlight-region-shift-only nil | ||
| 266 | "*If non-nil, only highlight region if marked with S-<move>. | ||
| 267 | When this is non-nil, CUA toggles `transient-mark-mode' on when the region | ||
| 268 | is marked using shifted movement keys, and off when the mark is cleared. | ||
| 269 | But when the mark was set using \\[cua-set-mark], transient-mark-mode | ||
| 270 | is not turned on." | ||
| 271 | :type 'boolean | ||
| 272 | :group 'cua) | ||
| 273 | |||
| 274 | (defcustom cua-prefix-override-inhibit-delay | ||
| 275 | (if (featurep 'lisp-float-type) (/ (float 1) (float 5)) nil) | ||
| 276 | "*If non-nil, time in seconds to delay before overriding prefix key. | ||
| 277 | If there is additional input within this time, the prefix key is | ||
| 278 | used as a normal prefix key. So typing a key sequence quickly will | ||
| 279 | inhibit overriding the prefix key. | ||
| 280 | As a special case, if the prefix keys repeated within this time, the | ||
| 281 | first prefix key is discarded, so typing a prefix key twice in quick | ||
| 282 | succession will also inhibit overriding the prefix key. | ||
| 283 | If the value is nil, use a shifted prefix key to inhibit the override." | ||
| 284 | :type '(choice (number :tag "Inhibit delay") | ||
| 285 | (const :tag "No delay" nil)) | ||
| 286 | :group 'cua) | ||
| 287 | |||
| 288 | (defcustom cua-keep-region-after-copy nil | ||
| 289 | "If non-nil, don't deselect the region after copying." | ||
| 290 | :type 'boolean | ||
| 291 | :group 'cua) | ||
| 292 | |||
| 293 | (defcustom cua-enable-register-prefix 'not-ctrl-u | ||
| 294 | "*If non-nil, registers are supported via numeric prefix arg. | ||
| 295 | If the value is t, any numeric prefix arg in the range 0 to 9 will be | ||
| 296 | interpreted as a register number. | ||
| 297 | If the value is not-ctrl-u, using C-u to enter a numeric prefix is not | ||
| 298 | interpreted as a register number. | ||
| 299 | If the value is ctrl-u-only, only numeric prefix entered with C-u is | ||
| 300 | interpreted as a register number." | ||
| 301 | :type '(choice (const :tag "Disabled" nil) | ||
| 302 | (const :tag "Enabled, but C-u arg is not a register" not-ctrl-u) | ||
| 303 | (const :tag "Enabled, but only for C-u arg" ctrl-u-only) | ||
| 304 | (other :tag "Enabled")) | ||
| 305 | :group 'cua) | ||
| 306 | |||
| 307 | (defcustom cua-delete-copy-to-register-0 t | ||
| 308 | "*If non-nil, save last deleted region or rectangle to register 0." | ||
| 309 | :type 'boolean | ||
| 310 | :group 'cua) | ||
| 311 | |||
| 312 | (defcustom cua-use-hyper-key nil | ||
| 313 | "*If non-nil, bind rectangle commands to H-? instead of M-?. | ||
| 314 | If set to 'also, toggle region command is also on S-return. | ||
| 315 | Must be set prior to enabling CUA." | ||
| 316 | :type '(choice (const :tag "Meta key and S-return" nil) | ||
| 317 | (const :tag "Hyper key only" only) | ||
| 318 | (const :tag "Hyper key and S-return" also)) | ||
| 319 | :group 'cua) | ||
| 320 | |||
| 321 | (defcustom cua-enable-region-auto-help nil | ||
| 322 | "*If non-nil, automatically show help for active region." | ||
| 323 | :type 'boolean | ||
| 324 | :group 'cua) | ||
| 325 | |||
| 326 | (defcustom cua-enable-modeline-indications nil | ||
| 327 | "*If non-nil, use minor-mode hook to show status in mode line." | ||
| 328 | :type 'boolean | ||
| 329 | :group 'cua) | ||
| 330 | |||
| 331 | (defcustom cua-check-pending-input t | ||
| 332 | "*If non-nil, don't override prefix key if input pending. | ||
| 333 | It is rumoured that input-pending-p is unreliable under some window | ||
| 334 | managers, so try setting this to nil, if prefix override doesn't work." | ||
| 335 | :type 'boolean | ||
| 336 | :group 'cua) | ||
| 337 | |||
| 338 | |||
| 339 | ;;; Rectangle Customization | ||
| 340 | |||
| 341 | (defcustom cua-auto-expand-rectangles nil | ||
| 342 | "*If non-nil, rectangles are padded with spaces to make straight edges. | ||
| 343 | This implies modifying buffer contents by expanding tabs and inserting spaces. | ||
| 344 | Consequently, this is inhibited in read-only buffers. | ||
| 345 | Can be toggled by [M-p] while the rectangle is active," | ||
| 346 | :type 'boolean | ||
| 347 | :group 'cua) | ||
| 348 | |||
| 349 | (defcustom cua-enable-rectangle-auto-help t | ||
| 350 | "*If non-nil, automatically show help for region, rectangle and global mark." | ||
| 351 | :type 'boolean | ||
| 352 | :group 'cua) | ||
| 353 | |||
| 354 | (defface cua-rectangle-face 'nil | ||
| 355 | "*Font used by CUA for highlighting the rectangle." | ||
| 356 | :group 'cua) | ||
| 357 | |||
| 358 | (defface cua-rectangle-noselect-face 'nil | ||
| 359 | "*Font used by CUA for highlighting the non-selected rectangle lines." | ||
| 360 | :group 'cua) | ||
| 361 | |||
| 362 | (defcustom cua-undo-max 64 | ||
| 363 | "*Max no of undoable CUA rectangle changes (including undo)." | ||
| 364 | :type 'integer | ||
| 365 | :group 'cua) | ||
| 366 | |||
| 367 | |||
| 368 | ;;; Global Mark Customization | ||
| 369 | |||
| 370 | (defcustom cua-global-mark-keep-visible t | ||
| 371 | "*If non-nil, always keep global mark visible in other window." | ||
| 372 | :type 'boolean | ||
| 373 | :group 'cua) | ||
| 374 | |||
| 375 | (defface cua-global-mark-face '((((class color)) | ||
| 376 | (:foreground "black") | ||
| 377 | (:background "yellow")) | ||
| 378 | (t (:bold t))) | ||
| 379 | "*Font used by CUA for highlighting the global mark." | ||
| 380 | :group 'cua) | ||
| 381 | |||
| 382 | (defcustom cua-global-mark-blink-cursor-interval 0.20 | ||
| 383 | "*Blink cursor at this interval when global mark is active." | ||
| 384 | :type '(choice (number :tag "Blink interval") | ||
| 385 | (const :tag "No blink" nil)) | ||
| 386 | :group 'cua) | ||
| 387 | |||
| 388 | |||
| 389 | ;;; Cursor Indication Customization | ||
| 390 | |||
| 391 | (defcustom cua-enable-cursor-indications t | ||
| 392 | "*If non-nil, use different cursor colors for indications." | ||
| 393 | :type 'boolean | ||
| 394 | :group 'cua) | ||
| 395 | |||
| 396 | (defcustom cua-normal-cursor-color nil | ||
| 397 | "Normal (non-overwrite) cursor color. | ||
| 398 | Also used to indicate that rectangle padding is not in effect. | ||
| 399 | Automatically loaded from frame parameters, if nil." | ||
| 400 | :initialize (lambda (symbol value) | ||
| 401 | (set symbol (or value | ||
| 402 | (and (boundp 'initial-cursor-color) initial-cursor-color) | ||
| 403 | (and (boundp 'initial-frame-alist) | ||
| 404 | (assoc 'cursor-color initial-frame-alist) | ||
| 405 | (cdr (assoc 'cursor-color initial-frame-alist))) | ||
| 406 | (and (boundp 'default-frame-alist) | ||
| 407 | (assoc 'cursor-color default-frame-alist) | ||
| 408 | (cdr (assoc 'cursor-color default-frame-alist))) | ||
| 409 | (frame-parameter nil 'cursor-color)))) | ||
| 410 | :type 'color | ||
| 411 | :group 'cua) | ||
| 412 | |||
| 413 | (defcustom cua-read-only-cursor-color "darkgreen" | ||
| 414 | "*Cursor color used in read-only buffers, if non-nil." | ||
| 415 | :type 'color | ||
| 416 | :group 'cua) | ||
| 417 | |||
| 418 | (defcustom cua-overwrite-cursor-color "yellow" | ||
| 419 | "*Cursor color used when overwrite mode is set, if non-nil. | ||
| 420 | Also used to indicate that rectangle padding is in effect." | ||
| 421 | :type 'color | ||
| 422 | :group 'cua) | ||
| 423 | |||
| 424 | (defcustom cua-global-mark-cursor-color "cyan" | ||
| 425 | "*Indication for active global mark. | ||
| 426 | Will change cursor color to specified color if string." | ||
| 427 | :type 'color | ||
| 428 | :group 'cua) | ||
| 429 | |||
| 430 | |||
| 431 | ;;; Rectangle support is in cua-rect.el | ||
| 432 | |||
| 433 | (autoload 'cua-set-rectangle-mark "cua-rect" nil t nil) | ||
| 434 | |||
| 435 | ;; Stub definitions until it is loaded | ||
| 436 | |||
| 437 | (when (not (featurep 'cua-rect)) | ||
| 438 | (defvar cua--rectangle) | ||
| 439 | (setq cua--rectangle nil) | ||
| 440 | (defvar cua--last-killed-rectangle) | ||
| 441 | (setq cua--last-killed-rectangle nil)) | ||
| 442 | |||
| 443 | |||
| 444 | |||
| 445 | ;;; Global Mark support is in cua-gmrk.el | ||
| 446 | |||
| 447 | (autoload 'cua-toggle-global-mark "cua-gmrk.el" nil t nil) | ||
| 448 | |||
| 449 | ;; Stub definitions until cua-gmrk.el is loaded | ||
| 450 | |||
| 451 | (when (not (featurep 'cua-gmrk)) | ||
| 452 | (defvar cua--global-mark-active) | ||
| 453 | (setq cua--global-mark-active nil)) | ||
| 454 | |||
| 455 | |||
| 456 | (provide 'cua-base) | ||
| 457 | |||
| 458 | (eval-when-compile | ||
| 459 | (require 'cua-rect) | ||
| 460 | (require 'cua-gmrk) | ||
| 461 | ) | ||
| 462 | |||
| 463 | ;;; Aux. variables | ||
| 464 | |||
| 465 | ;; Current region was started using cua-set-mark. | ||
| 466 | (defvar cua--explicit-region-start nil) | ||
| 467 | |||
| 468 | ;; Latest region was started using shifted movement command. | ||
| 469 | (defvar cua--last-region-shifted nil) | ||
| 470 | |||
| 471 | ;; buffer + point prior to current command when rectangle is active | ||
| 472 | ;; checked in post-command hook to see if point was moved | ||
| 473 | (defvar cua--buffer-and-point-before-command nil) | ||
| 474 | |||
| 475 | ;; status string for mode line indications | ||
| 476 | (defvar cua--status-string nil) | ||
| 477 | |||
| 478 | (defvar cua--debug nil) | ||
| 479 | |||
| 480 | |||
| 481 | ;;; Prefix key override mechanism | ||
| 482 | |||
| 483 | ;; The prefix override (when mark-active) operates in three substates: | ||
| 484 | ;; [1] Before using a prefix key | ||
| 485 | ;; [2] Immediately after using a prefix key | ||
| 486 | ;; [3] A fraction of a second later | ||
| 487 | |||
| 488 | ;; In state [1], the cua--prefix-override-keymap is active. | ||
| 489 | ;; This keymap binds the C-x and C-c prefix keys to the | ||
| 490 | ;; cua--prefix-override-handler function. | ||
| 491 | |||
| 492 | ;; When a prefix key is typed in state [1], cua--prefix-override-handler | ||
| 493 | ;; will push back the keys already read to the event queue. If input is | ||
| 494 | ;; pending, it changes directly to state [3]. Otherwise, a short timer [T] | ||
| 495 | ;; is started, and it changes to state [2]. | ||
| 496 | |||
| 497 | ;; In state [2], the cua--prefix-override-keymap is inactive. Instead the | ||
| 498 | ;; cua--prefix-repeat-keymap is active. This keymap binds C-c C-c and C-x | ||
| 499 | ;; C-x to the cua--prefix-repeat-handler function. | ||
| 500 | |||
| 501 | ;; If the prefix key is repeated in state [2], cua--prefix-repeat-handler | ||
| 502 | ;; will cancel [T], back the keys already read (except for the second prefix | ||
| 503 | ;; keys) to the event queue, and changes to state [3]. | ||
| 504 | |||
| 505 | ;; The basic cua--cua-keys-keymap binds [C-x timeout] to kill-region and | ||
| 506 | ;; [C-c timeout] to copy-region-as-kill, so if [T] times out in state [2], | ||
| 507 | ;; the cua--prefix-override-timeout function will push a `timeout' event on | ||
| 508 | ;; the event queue, and changes to state [3]. | ||
| 509 | |||
| 510 | ;; In state [3] both cua--prefix-override-keymap and cua--prefix-repeat-keymap | ||
| 511 | ;; are inactive, so the timeout in cua-global-keymap binding is used, or the | ||
| 512 | ;; normal prefix key binding from the global or local map will be used. | ||
| 513 | |||
| 514 | ;; The pre-command hook (executed as a consequence of the timeout or normal | ||
| 515 | ;; prefix key binding) will cancel [T] and change from state [3] back to | ||
| 516 | ;; state [1]. So cua--prefix-override-handler and cua--prefix-repeat-handler | ||
| 517 | ;; are always called with state reset to [1]! | ||
| 518 | |||
| 519 | ;; State [1] is recognized by cua--prefix-override-timer is nil, | ||
| 520 | ;; state [2] is recognized by cua--prefix-override-timer is a timer, and | ||
| 521 | ;; state [3] is recognized by cua--prefix-override-timer is t. | ||
| 522 | |||
| 523 | (defvar cua--prefix-override-timer nil) | ||
| 524 | (defvar cua--prefix-override-length nil) | ||
| 525 | |||
| 526 | (defun cua--prefix-override-replay (arg repeat) | ||
| 527 | (let* ((keys (this-command-keys)) | ||
| 528 | (i (length keys)) | ||
| 529 | (key (aref keys (1- i)))) | ||
| 530 | (setq cua--prefix-override-length (- i repeat)) | ||
| 531 | (setq cua--prefix-override-timer | ||
| 532 | (or | ||
| 533 | ;; In state [2], change to state [3] | ||
| 534 | (> repeat 0) | ||
| 535 | ;; In state [1], change directly to state [3] | ||
| 536 | (and cua-check-pending-input (input-pending-p)) | ||
| 537 | ;; In state [1], [T] disabled, so change to state [3] | ||
| 538 | (not (numberp cua-prefix-override-inhibit-delay)) | ||
| 539 | (<= cua-prefix-override-inhibit-delay 0) | ||
| 540 | ;; In state [1], start [T] and change to state [2] | ||
| 541 | (run-with-timer cua-prefix-override-inhibit-delay nil | ||
| 542 | 'cua--prefix-override-timeout))) | ||
| 543 | ;; Don't record this command | ||
| 544 | (setq this-command last-command) | ||
| 545 | ;; Restore the prefix arg | ||
| 546 | (setq prefix-arg arg) | ||
| 547 | (reset-this-command-lengths) | ||
| 548 | ;; Push the key back on the event queue | ||
| 549 | (setq unread-command-events (cons key unread-command-events)))) | ||
| 550 | |||
| 551 | (defun cua--prefix-override-handler (arg) | ||
| 552 | "Start timer waiting for prefix key to be followed by another key. | ||
| 553 | Repeating prefix key when region is active works as a single prefix key." | ||
| 554 | (interactive "P") | ||
| 555 | (cua--prefix-override-replay arg 0)) | ||
| 556 | |||
| 557 | (defun cua--prefix-repeat-handler (arg) | ||
| 558 | "Repeating prefix key when region is active works as a single prefix key." | ||
| 559 | (interactive "P") | ||
| 560 | (cua--prefix-override-replay arg 1)) | ||
| 561 | |||
| 562 | (defun cua--prefix-copy-handler (arg) | ||
| 563 | "Copy region/rectangle, then replay last key." | ||
| 564 | (interactive "P") | ||
| 565 | (if cua--rectangle | ||
| 566 | (cua-copy-rectangle arg) | ||
| 567 | (cua-copy-region arg)) | ||
| 568 | (let ((keys (this-single-command-keys))) | ||
| 569 | (setq unread-command-events | ||
| 570 | (cons (aref keys (1- (length keys))) unread-command-events)))) | ||
| 571 | |||
| 572 | (defun cua--prefix-cut-handler (arg) | ||
| 573 | "Cut region/rectangle, then replay last key." | ||
| 574 | (interactive "P") | ||
| 575 | (if cua--rectangle | ||
| 576 | (cua-cut-rectangle arg) | ||
| 577 | (cua-cut-region arg)) | ||
| 578 | (let ((keys (this-single-command-keys))) | ||
| 579 | (setq unread-command-events | ||
| 580 | (cons (aref keys (1- (length keys))) unread-command-events)))) | ||
| 581 | |||
| 582 | (defun cua--prefix-override-timeout () | ||
| 583 | (setq cua--prefix-override-timer t) | ||
| 584 | (when (= (length (this-command-keys)) cua--prefix-override-length) | ||
| 585 | (setq unread-command-events (cons 'timeout unread-command-events)) | ||
| 586 | (if prefix-arg | ||
| 587 | (reset-this-command-lengths) | ||
| 588 | (setq overriding-terminal-local-map nil)) | ||
| 589 | (cua--fix-keymaps nil))) | ||
| 590 | |||
| 591 | |||
| 592 | ;;; Aux. functions | ||
| 593 | |||
| 594 | (defun cua--fallback () | ||
| 595 | ;; Execute original command | ||
| 596 | (setq this-command this-original-command) | ||
| 597 | (call-interactively this-command)) | ||
| 598 | |||
| 599 | (defun cua--keep-active () | ||
| 600 | (setq mark-active t | ||
| 601 | deactivate-mark nil)) | ||
| 602 | |||
| 603 | (defun cua--deactivate (&optional now) | ||
| 604 | (setq cua--explicit-region-start nil) | ||
| 605 | (if (not now) | ||
| 606 | (setq deactivate-mark t) | ||
| 607 | (setq mark-active nil) | ||
| 608 | (run-hooks 'deactivate-mark-hook))) | ||
| 609 | |||
| 610 | |||
| 611 | ;; The current register prefix | ||
| 612 | (defvar cua--register nil) | ||
| 613 | |||
| 614 | (defun cua--prefix-arg (arg) | ||
| 615 | (setq cua--register | ||
| 616 | (and cua-enable-register-prefix | ||
| 617 | (integerp (this-command-keys)) | ||
| 618 | (cond ((eq cua-enable-register-prefix 'not-ctrl-u) | ||
| 619 | (not (= (aref (this-command-keys) 0) ?\C-u))) | ||
| 620 | ((eq cua-enable-register-prefix 'ctrl-u-only) | ||
| 621 | (= (aref (this-command-keys) 0) ?\C-u)) | ||
| 622 | (t t)) | ||
| 623 | (integerp arg) (>= arg 0) (< arg 10) | ||
| 624 | (+ arg ?0))) | ||
| 625 | (if cua--register nil arg)) | ||
| 626 | |||
| 627 | |||
| 628 | ;;; Enhanced undo - restore rectangle selections | ||
| 629 | |||
| 630 | (defun cua-undo (&optional arg) | ||
| 631 | "Undo some previous changes. | ||
| 632 | Knows about CUA rectangle highlighting in addition to standard undo." | ||
| 633 | (interactive "*P") | ||
| 634 | (if (fboundp 'cua--rectangle-undo) | ||
| 635 | (cua--rectangle-undo arg) | ||
| 636 | (undo arg))) | ||
| 637 | |||
| 638 | ;;; Region specific commands | ||
| 639 | |||
| 640 | (defun cua-delete-region () | ||
| 641 | "Delete the active region. | ||
| 642 | Save a copy in register 0 if `cua-delete-copy-to-register-0' is non-nil." | ||
| 643 | (interactive) | ||
| 644 | (let ((start (mark)) (end (point))) | ||
| 645 | (or (<= start end) | ||
| 646 | (setq start (prog1 end (setq end start)))) | ||
| 647 | (if cua-delete-copy-to-register-0 | ||
| 648 | (copy-to-register ?0 start end nil)) | ||
| 649 | (delete-region start end) | ||
| 650 | (cua--deactivate))) | ||
| 651 | |||
| 652 | (defun cua-replace-region () | ||
| 653 | "Replace the active region with the character you type." | ||
| 654 | (interactive) | ||
| 655 | (cua-delete-region) | ||
| 656 | (if (not (eq this-original-command this-command)) | ||
| 657 | (cua--fallback))) | ||
| 658 | |||
| 659 | (defun cua-copy-region (arg) | ||
| 660 | "Copy the region to the kill ring. | ||
| 661 | With numeric prefix arg, copy to register 0-9 instead." | ||
| 662 | (interactive "P") | ||
| 663 | (setq arg (cua--prefix-arg arg)) | ||
| 664 | (setq cua--last-killed-rectangle nil) | ||
| 665 | (let ((start (mark)) (end (point))) | ||
| 666 | (or (<= start end) | ||
| 667 | (setq start (prog1 end (setq end start)))) | ||
| 668 | (if cua--register | ||
| 669 | (copy-to-register cua--register start end nil) | ||
| 670 | (copy-region-as-kill start end)) | ||
| 671 | (if cua-keep-region-after-copy | ||
| 672 | (cua--keep-active) | ||
| 673 | (cua--deactivate)))) | ||
| 674 | |||
| 675 | (defun cua-cut-region (arg) | ||
| 676 | "Cut the region and copy to the kill ring. | ||
| 677 | With numeric prefix arg, copy to register 0-9 instead." | ||
| 678 | (interactive "P") | ||
| 679 | (setq cua--last-killed-rectangle nil) | ||
| 680 | (if buffer-read-only | ||
| 681 | (cua-copy-region arg) | ||
| 682 | (setq arg (cua--prefix-arg arg)) | ||
| 683 | (let ((start (mark)) (end (point))) | ||
| 684 | (or (<= start end) | ||
| 685 | (setq start (prog1 end (setq end start)))) | ||
| 686 | (if cua--register | ||
| 687 | (copy-to-register cua--register start end t) | ||
| 688 | (kill-region start end))) | ||
| 689 | (cua--deactivate))) | ||
| 690 | |||
| 691 | ;;; Generic commands for regions, rectangles, and global marks | ||
| 692 | |||
| 693 | (defun cua-cancel () | ||
| 694 | "Cancel the active region, rectangle, or global mark." | ||
| 695 | (interactive) | ||
| 696 | (setq mark-active nil) | ||
| 697 | (setq cua--explicit-region-start nil) | ||
| 698 | (if (fboundp 'cua--cancel-rectangle) | ||
| 699 | (cua--cancel-rectangle))) | ||
| 700 | |||
| 701 | (defun cua-paste (arg) | ||
| 702 | "Paste last cut or copied region or rectangle. | ||
| 703 | An active region is deleted before executing the command. | ||
| 704 | With numeric prefix arg, paste from register 0-9 instead. | ||
| 705 | If global mark is active, copy from register or one character." | ||
| 706 | (interactive "P") | ||
| 707 | (setq arg (cua--prefix-arg arg)) | ||
| 708 | (let ((regtxt (and cua--register (get-register cua--register))) | ||
| 709 | (count (prefix-numeric-value arg))) | ||
| 710 | (cond | ||
| 711 | ((and cua--register (not regtxt)) | ||
| 712 | (message "Nothing in register %c" cua--register)) | ||
| 713 | (cua--global-mark-active | ||
| 714 | (if regtxt | ||
| 715 | (cua--insert-at-global-mark regtxt) | ||
| 716 | (when (not (eobp)) | ||
| 717 | (cua--insert-at-global-mark (buffer-substring (point) (+ (point) count))) | ||
| 718 | (forward-char count)))) | ||
| 719 | (buffer-read-only | ||
| 720 | (message "Cannot paste into a read-only buffer")) | ||
| 721 | (t | ||
| 722 | ;; Must save register here, since delete may override reg 0. | ||
| 723 | (if mark-active | ||
| 724 | ;; Before a yank command, make sure we don't yank | ||
| 725 | ;; the same region that we are going to delete. | ||
| 726 | ;; That would make yank a no-op. | ||
| 727 | (if cua--rectangle | ||
| 728 | (cua--delete-rectangle) | ||
| 729 | (if (string= (buffer-substring (point) (mark)) | ||
| 730 | (car kill-ring)) | ||
| 731 | (current-kill 1)) | ||
| 732 | (cua-delete-region))) | ||
| 733 | (cond | ||
| 734 | (regtxt | ||
| 735 | (cond | ||
| 736 | ((consp regtxt) (cua--insert-rectangle regtxt)) | ||
| 737 | ((stringp regtxt) (insert-for-yank regtxt)) | ||
| 738 | (t (message "Unknown data in register %c" cua--register)))) | ||
| 739 | ((and cua--last-killed-rectangle | ||
| 740 | (eq (and kill-ring (car kill-ring)) (car cua--last-killed-rectangle))) | ||
| 741 | (let ((pt (point))) | ||
| 742 | (when (not (eq buffer-undo-list t)) | ||
| 743 | (setq this-command 'cua--paste-rectangle) | ||
| 744 | (undo-boundary) | ||
| 745 | (setq buffer-undo-list (cons pt buffer-undo-list))) | ||
| 746 | (cua--insert-rectangle (cdr cua--last-killed-rectangle)) | ||
| 747 | (if arg (goto-char pt)))) | ||
| 748 | (t (yank arg))))))) | ||
| 749 | |||
| 750 | (defun cua-paste-pop (arg) | ||
| 751 | "Replace a just-pasted text or rectangle with a different text. | ||
| 752 | See `yank-pop' for details." | ||
| 753 | (interactive "P") | ||
| 754 | (if (eq last-command 'cua--paste-rectangle) | ||
| 755 | (progn | ||
| 756 | (undo) | ||
| 757 | (yank arg)) | ||
| 758 | (yank-pop (prefix-numeric-value arg)))) | ||
| 759 | |||
| 760 | (defun cua-exchange-point-and-mark (arg) | ||
| 761 | "Exchanges point and mark, but don't activate the mark. | ||
| 762 | Activates the mark if a prefix argument is given." | ||
| 763 | (interactive "P") | ||
| 764 | (if arg | ||
| 765 | (setq mark-active t) | ||
| 766 | (let (mark-active) | ||
| 767 | (exchange-point-and-mark) | ||
| 768 | (if cua--rectangle | ||
| 769 | (cua--rectangle-corner 0))))) | ||
| 770 | |||
| 771 | (defun cua-help-for-region (&optional help) | ||
| 772 | "Show region specific help in echo area." | ||
| 773 | (interactive) | ||
| 774 | (message | ||
| 775 | (concat (if help "C-?:help " "") | ||
| 776 | "C-z:undo C-x:cut C-c:copy C-v:paste S-ret:rect"))) | ||
| 777 | |||
| 778 | |||
| 779 | ;;; Shift activated / extended region | ||
| 780 | |||
| 781 | (defun cua-set-mark (&optional arg) | ||
| 782 | "Set mark at where point is, clear mark, or jump to mark. | ||
| 783 | With no prefix argument, set mark, push old mark position on local mark | ||
| 784 | ring, and push mark on global mark ring, or if mark is already set, clear mark. | ||
| 785 | With argument, jump to mark, and pop a new position for mark off the ring; | ||
| 786 | then it jumps to the next mark off the ring if repeated with no argument, or | ||
| 787 | sets the mark at the new position if repeated with argument." | ||
| 788 | (interactive "P") | ||
| 789 | (if (and (eq this-command last-command) | ||
| 790 | last-prefix-arg) | ||
| 791 | (setq arg (if arg nil last-prefix-arg) | ||
| 792 | current-prefix-arg arg)) | ||
| 793 | (cond | ||
| 794 | (arg | ||
| 795 | (if (null (mark t)) | ||
| 796 | (error "No mark set in this buffer") | ||
| 797 | (goto-char (mark t)) | ||
| 798 | (pop-mark))) | ||
| 799 | (mark-active | ||
| 800 | (cua--deactivate) | ||
| 801 | (message "Mark Cleared")) | ||
| 802 | (t | ||
| 803 | (push-mark nil nil t) | ||
| 804 | (setq cua--explicit-region-start t) | ||
| 805 | (setq cua--last-region-shifted nil) | ||
| 806 | (if cua-enable-region-auto-help | ||
| 807 | (cua-help-for-region t))))) | ||
| 808 | |||
| 809 | (defvar cua--standard-movement-commands | ||
| 810 | '(forward-char backward-char | ||
| 811 | next-line previous-line | ||
| 812 | forward-word backward-word | ||
| 813 | end-of-line beginning-of-line | ||
| 814 | end-of-buffer beginning-of-buffer | ||
| 815 | scroll-up scroll-down forward-paragraph backward-paragraph) | ||
| 816 | "List of standard movement commands. | ||
| 817 | Extra commands should be added to `cua-user-movement-commands'") | ||
| 818 | |||
| 819 | (defvar cua-movement-commands nil | ||
| 820 | "User may add additional movement commands to this list.") | ||
| 821 | |||
| 822 | |||
| 823 | ;;; Cursor indications | ||
| 824 | |||
| 825 | (defun cua--update-indications () | ||
| 826 | (let ((cursor | ||
| 827 | (cond | ||
| 828 | ((and cua--global-mark-active | ||
| 829 | (stringp cua-global-mark-cursor-color)) | ||
| 830 | cua-global-mark-cursor-color) | ||
| 831 | ((and buffer-read-only | ||
| 832 | (stringp cua-read-only-cursor-color)) | ||
| 833 | cua-read-only-cursor-color) | ||
| 834 | ((and (stringp cua-overwrite-cursor-color) | ||
| 835 | (or overwrite-mode | ||
| 836 | (and cua--rectangle (cua--rectangle-padding)))) | ||
| 837 | cua-overwrite-cursor-color) | ||
| 838 | (t cua-normal-cursor-color)))) | ||
| 839 | (if (and cursor | ||
| 840 | (not (equal cursor (frame-parameter nil 'cursor-color)))) | ||
| 841 | (set-cursor-color cursor)) | ||
| 842 | cursor)) | ||
| 843 | |||
| 844 | |||
| 845 | ;;; Pre-command hook | ||
| 846 | |||
| 847 | (defun cua--pre-command-handler () | ||
| 848 | (condition-case nil | ||
| 849 | (let ((movement (or (memq this-command cua--standard-movement-commands) | ||
| 850 | (memq this-command cua-movement-commands)))) | ||
| 851 | |||
| 852 | ;; Cancel prefix key timeout if user enters another key. | ||
| 853 | (when cua--prefix-override-timer | ||
| 854 | (if (timerp cua--prefix-override-timer) | ||
| 855 | (cancel-timer cua--prefix-override-timer)) | ||
| 856 | (setq cua--prefix-override-timer nil)) | ||
| 857 | |||
| 858 | ;; Handle shifted cursor keys and other movement commands. | ||
| 859 | ;; If region is not active, region is activated if key is shifted. | ||
| 860 | ;; If region is active, region is cancelled if key is unshifted (and region not started with C-SPC). | ||
| 861 | ;; If rectangle is active, expand rectangle in specified direction and ignore the movement. | ||
| 862 | (if movement | ||
| 863 | (cond | ||
| 864 | ((memq 'shift (event-modifiers (aref (this-single-command-raw-keys) 0))) | ||
| 865 | (unless mark-active | ||
| 866 | (push-mark nil t t)) | ||
| 867 | (setq cua--last-region-shifted t) | ||
| 868 | (setq cua--explicit-region-start nil)) | ||
| 869 | ((or cua--explicit-region-start cua--rectangle) | ||
| 870 | (unless mark-active | ||
| 871 | (push-mark nil nil t))) | ||
| 872 | (t | ||
| 873 | ;; If we set mark-active to nil here, the region highlight will not be | ||
| 874 | ;; removed by the direct_output_ commands. | ||
| 875 | (setq deactivate-mark t))) | ||
| 876 | |||
| 877 | ;; Handle delete-selection property on other commands | ||
| 878 | (let* ((ds (or (get this-command 'delete-selection) | ||
| 879 | (get this-command 'pending-delete))) | ||
| 880 | (nc (cond | ||
| 881 | ((eq ds 'yank) | ||
| 882 | 'cua-paste) | ||
| 883 | ((eq ds 'kill) | ||
| 884 | (if cua--rectangle | ||
| 885 | 'cua-copy-rectangle | ||
| 886 | 'cua-copy-region)) | ||
| 887 | ((eq ds 'supersede) | ||
| 888 | (if cua--rectangle | ||
| 889 | 'cua-delete-rectangle ;; replace? | ||
| 890 | 'cua-replace-region)) | ||
| 891 | (ds | ||
| 892 | (if cua--rectangle | ||
| 893 | 'cua-delete-rectangle | ||
| 894 | 'cua-delete-region)) | ||
| 895 | (t nil)))) | ||
| 896 | (if nc | ||
| 897 | (setq this-original-command this-command | ||
| 898 | this-command nc)))) | ||
| 899 | |||
| 900 | ;; Detect extension of rectangles by mouse or other movement | ||
| 901 | (setq cua--buffer-and-point-before-command | ||
| 902 | (if cua--rectangle (cons (current-buffer) (point)))) | ||
| 903 | ) | ||
| 904 | (error nil))) | ||
| 905 | |||
| 906 | ;;; Post-command hook | ||
| 907 | |||
| 908 | (defun cua--post-command-handler () | ||
| 909 | (condition-case nil | ||
| 910 | (progn | ||
| 911 | (when cua--global-mark-active | ||
| 912 | (cua--global-mark-post-command)) | ||
| 913 | (when (fboundp 'cua--rectangle-post-command) | ||
| 914 | (cua--rectangle-post-command)) | ||
| 915 | (setq cua--buffer-and-point-before-command nil) | ||
| 916 | (if (or (not mark-active) deactivate-mark) | ||
| 917 | (setq cua--explicit-region-start nil)) | ||
| 918 | |||
| 919 | ;; Debugging | ||
| 920 | (if cua--debug | ||
| 921 | (cond | ||
| 922 | (cua--rectangle (cua--rectangle-assert)) | ||
| 923 | (mark-active (message "Mark=%d Point=%d Expl=%s" | ||
| 924 | (mark t) (point) cua--explicit-region-start)))) | ||
| 925 | |||
| 926 | ;; Disable transient-mark-mode if rectangle active in current buffer. | ||
| 927 | (if (not (window-minibuffer-p (selected-window))) | ||
| 928 | (setq transient-mark-mode (and (not cua--rectangle) | ||
| 929 | (if cua-highlight-region-shift-only | ||
| 930 | (not cua--explicit-region-start) | ||
| 931 | t)))) | ||
| 932 | (if cua-enable-cursor-indications | ||
| 933 | (cua--update-indications)) | ||
| 934 | |||
| 935 | (cua--fix-keymaps nil) | ||
| 936 | ) | ||
| 937 | |||
| 938 | (error nil))) | ||
| 939 | |||
| 940 | |||
| 941 | ;;; Keymaps | ||
| 942 | |||
| 943 | (defun cua--M/H-key (map key fct) | ||
| 944 | ;; bind H-KEY or M-KEY to FCT in MAP | ||
| 945 | (if (eq key 'space) (setq key ? )) | ||
| 946 | (unless (listp key) (setq key (list key))) | ||
| 947 | (define-key map (vector (cons (if cua-use-hyper-key 'hyper 'meta) key)) fct)) | ||
| 948 | |||
| 949 | (defvar cua-global-keymap (make-sparse-keymap)) | ||
| 950 | (defvar cua--cua-keys-keymap (make-sparse-keymap)) | ||
| 951 | (defvar cua--prefix-override-keymap (make-sparse-keymap)) | ||
| 952 | (defvar cua--prefix-repeat-keymap (make-sparse-keymap)) | ||
| 953 | (defvar cua--global-mark-keymap (make-sparse-keymap)) ; Initalized when cua-gmrk.el is loaded | ||
| 954 | (defvar cua--rectangle-keymap (make-sparse-keymap)) ; Initalized when cua-rect.el is loaded | ||
| 955 | (defvar cua--region-keymap (make-sparse-keymap)) | ||
| 956 | |||
| 957 | (defvar cua--ena-cua-keys-keymap nil) | ||
| 958 | (defvar cua--ena-prefix-override-keymap nil) | ||
| 959 | (defvar cua--ena-prefix-repeat-keymap nil) | ||
| 960 | (defvar cua--ena-region-keymap nil) | ||
| 961 | (defvar cua--ena-global-mark-keymap nil) | ||
| 962 | |||
| 963 | (defvar cua--mmap-prefix-override-keymap (cons 'cua--ena-prefix-override-keymap cua--prefix-override-keymap)) | ||
| 964 | (defvar cua--mmap-prefix-repeat-keymap (cons 'cua--ena-prefix-repeat-keymap cua--prefix-repeat-keymap)) | ||
| 965 | (defvar cua--mmap-cua-keys-keymap (cons 'cua--ena-cua-keys-keymap cua--cua-keys-keymap)) | ||
| 966 | (defvar cua--mmap-global-mark-keymap (cons 'cua--ena-global-mark-keymap cua--global-mark-keymap)) | ||
| 967 | (defvar cua--mmap-rectangle-keymap (cons 'cua--rectangle cua--rectangle-keymap)) | ||
| 968 | (defvar cua--mmap-region-keymap (cons 'cua--ena-region-keymap cua--region-keymap)) | ||
| 969 | (defvar cua--mmap-global-keymap (cons 'cua-mode cua-global-keymap)) | ||
| 970 | |||
| 971 | (defvar cua--mmap-list | ||
| 972 | (list cua--mmap-prefix-override-keymap | ||
| 973 | cua--mmap-prefix-repeat-keymap | ||
| 974 | cua--mmap-cua-keys-keymap | ||
| 975 | cua--mmap-global-mark-keymap | ||
| 976 | cua--mmap-rectangle-keymap | ||
| 977 | cua--mmap-region-keymap | ||
| 978 | cua--mmap-global-keymap)) | ||
| 979 | |||
| 980 | (defun cua--fix-keymaps (disable) | ||
| 981 | ;; Ensure that cua's keymaps are in minor-mode-map-alist and | ||
| 982 | ;; in the correct order. | ||
| 983 | (let (fix | ||
| 984 | (mmap minor-mode-map-alist) | ||
| 985 | (ml cua--mmap-list)) | ||
| 986 | (while (and (not fix) mmap ml) | ||
| 987 | (if (not (eq (car mmap) (car ml))) | ||
| 988 | (setq fix t) | ||
| 989 | (setq mmap (cdr mmap) | ||
| 990 | ml (cdr ml)))) | ||
| 991 | (if ml | ||
| 992 | (setq fix t)) | ||
| 993 | (when (or fix disable) | ||
| 994 | (setq ml cua--mmap-list) | ||
| 995 | (while ml | ||
| 996 | (setq minor-mode-map-alist (delq (car ml) minor-mode-map-alist)) | ||
| 997 | (setq ml (cdr ml)))) | ||
| 998 | (when (and fix (not disable)) | ||
| 999 | (setq minor-mode-map-alist | ||
| 1000 | (append (copy-sequence cua--mmap-list) minor-mode-map-alist)))) | ||
| 1001 | (setq cua--ena-region-keymap | ||
| 1002 | (and mark-active (not deactivate-mark))) | ||
| 1003 | (setq cua--ena-prefix-override-keymap | ||
| 1004 | (and cua--ena-region-keymap | ||
| 1005 | cua-enable-cua-keys | ||
| 1006 | (or (eq cua-enable-cua-keys t) | ||
| 1007 | (not cua--explicit-region-start)) | ||
| 1008 | (not executing-kbd-macro) | ||
| 1009 | (not cua--prefix-override-timer))) | ||
| 1010 | (setq cua--ena-prefix-repeat-keymap | ||
| 1011 | (and cua--ena-region-keymap | ||
| 1012 | (timerp cua--prefix-override-timer))) | ||
| 1013 | (setq cua--ena-cua-keys-keymap | ||
| 1014 | (and cua-enable-cua-keys | ||
| 1015 | (or (eq cua-enable-cua-keys t) | ||
| 1016 | cua--last-region-shifted))) | ||
| 1017 | (setq cua--ena-global-mark-keymap | ||
| 1018 | (and cua--global-mark-active | ||
| 1019 | (not (window-minibuffer-p))))) | ||
| 1020 | |||
| 1021 | (defvar cua--keymaps-initalized nil) | ||
| 1022 | |||
| 1023 | (defun cua--init-keymaps () | ||
| 1024 | (unless (eq cua-use-hyper-key 'only) | ||
| 1025 | (define-key cua-global-keymap [(shift return)] 'cua-set-rectangle-mark)) | ||
| 1026 | (when cua-use-hyper-key | ||
| 1027 | (cua--M/H-key cua-global-keymap 'space 'cua-set-rectangle-mark) | ||
| 1028 | (define-key cua-global-keymap [(hyper mouse-1)] 'cua-mouse-set-rectangle-mark)) | ||
| 1029 | |||
| 1030 | (define-key cua-global-keymap [(shift control ? )] 'cua-toggle-global-mark) | ||
| 1031 | |||
| 1032 | ;; replace region with rectangle or element on kill ring | ||
| 1033 | (define-key cua-global-keymap [remap yank] 'cua-paste) | ||
| 1034 | (define-key cua-global-keymap [remap clipboard-yank] 'cua-paste) | ||
| 1035 | ;; replace current yank with previous kill ring element | ||
| 1036 | (define-key cua-global-keymap [remap yank-pop] 'cua-paste-pop) | ||
| 1037 | ;; set mark | ||
| 1038 | (define-key cua-global-keymap [remap set-mark-command] 'cua-set-mark) | ||
| 1039 | ;; undo | ||
| 1040 | (define-key cua-global-keymap [remap undo] 'cua-undo) | ||
| 1041 | (define-key cua-global-keymap [remap advertised-undo] 'cua-undo) | ||
| 1042 | |||
| 1043 | (define-key cua--cua-keys-keymap [(control x) timeout] 'kill-region) | ||
| 1044 | (define-key cua--cua-keys-keymap [(shift control x)] 'Control-X-prefix) | ||
| 1045 | (define-key cua--cua-keys-keymap [(control c) timeout] 'copy-region-as-kill) | ||
| 1046 | (define-key cua--cua-keys-keymap [(shift control c)] 'mode-specific-command-prefix) | ||
| 1047 | (define-key cua--cua-keys-keymap [(control z)] 'undo) | ||
| 1048 | (define-key cua--cua-keys-keymap [(control v)] 'yank) | ||
| 1049 | (define-key cua--cua-keys-keymap [remap exchange-point-and-mark] 'cua-exchange-point-and-mark) | ||
| 1050 | |||
| 1051 | (define-key cua--prefix-override-keymap [(control x)] 'cua--prefix-override-handler) | ||
| 1052 | (define-key cua--prefix-override-keymap [(control c)] 'cua--prefix-override-handler) | ||
| 1053 | |||
| 1054 | (define-key cua--prefix-repeat-keymap [(control x) (control x)] 'cua--prefix-repeat-handler) | ||
| 1055 | (define-key cua--prefix-repeat-keymap [(control x) up] 'cua--prefix-cut-handler) | ||
| 1056 | (define-key cua--prefix-repeat-keymap [(control x) down] 'cua--prefix-cut-handler) | ||
| 1057 | (define-key cua--prefix-repeat-keymap [(control x) left] 'cua--prefix-cut-handler) | ||
| 1058 | (define-key cua--prefix-repeat-keymap [(control x) right] 'cua--prefix-cut-handler) | ||
| 1059 | (define-key cua--prefix-repeat-keymap [(control c) (control c)] 'cua--prefix-repeat-handler) | ||
| 1060 | (define-key cua--prefix-repeat-keymap [(control c) up] 'cua--prefix-copy-handler) | ||
| 1061 | (define-key cua--prefix-repeat-keymap [(control c) down] 'cua--prefix-copy-handler) | ||
| 1062 | (define-key cua--prefix-repeat-keymap [(control c) left] 'cua--prefix-copy-handler) | ||
| 1063 | (define-key cua--prefix-repeat-keymap [(control c) right] 'cua--prefix-copy-handler) | ||
| 1064 | |||
| 1065 | ;; replace current region | ||
| 1066 | (define-key cua--region-keymap [remap self-insert-command] 'cua-replace-region) | ||
| 1067 | (define-key cua--region-keymap [remap self-insert-iso] 'cua-replace-region) | ||
| 1068 | (define-key cua--region-keymap [remap insert-register] 'cua-replace-region) | ||
| 1069 | (define-key cua--region-keymap [remap newline-and-indent] 'cua-replace-region) | ||
| 1070 | (define-key cua--region-keymap [remap newline] 'cua-replace-region) | ||
| 1071 | (define-key cua--region-keymap [remap open-line] 'cua-replace-region) | ||
| 1072 | ;; delete current region | ||
| 1073 | (define-key cua--region-keymap [remap delete-backward-char] 'cua-delete-region) | ||
| 1074 | (define-key cua--region-keymap [remap backward-delete-char] 'cua-delete-region) | ||
| 1075 | (define-key cua--region-keymap [remap backward-delete-char-untabify] 'cua-delete-region) | ||
| 1076 | (define-key cua--region-keymap [remap delete-char] 'cua-delete-region) | ||
| 1077 | ;; kill region | ||
| 1078 | (define-key cua--region-keymap [remap kill-region] 'cua-cut-region) | ||
| 1079 | ;; copy region | ||
| 1080 | (define-key cua--region-keymap [remap copy-region-as-kill] 'cua-copy-region) | ||
| 1081 | (define-key cua--region-keymap [remap kill-ring-save] 'cua-copy-region) | ||
| 1082 | ;; cancel current region/rectangle | ||
| 1083 | (define-key cua--region-keymap [remap keyboard-escape-quit] 'cua-cancel) | ||
| 1084 | (define-key cua--region-keymap [remap keyboard-quit] 'cua-cancel) | ||
| 1085 | ) | ||
| 1086 | |||
| 1087 | |||
| 1088 | ;;;###autoload | ||
| 1089 | (defun cua-mode (&optional arg) | ||
| 1090 | "Toggle CUA key-binding mode. | ||
| 1091 | When enabled, using shifted movement keys will activate the region (and | ||
| 1092 | highlight the region using `transient-mark-mode'), and typed text replaces | ||
| 1093 | the active selection. C-z, C-x, C-c, and C-v will undo, cut, copy, and | ||
| 1094 | paste (in addition to the normal emacs bindings)." | ||
| 1095 | (interactive "P") | ||
| 1096 | (setq cua-mode | ||
| 1097 | (cond | ||
| 1098 | ((null arg) (not cua-mode)) | ||
| 1099 | ((symbolp arg) t) | ||
| 1100 | (t (> (prefix-numeric-value arg) 0)))) | ||
| 1101 | |||
| 1102 | (setq mark-even-if-inactive t) | ||
| 1103 | (setq highlight-nonselected-windows nil) | ||
| 1104 | (make-variable-buffer-local 'cua--explicit-region-start) | ||
| 1105 | (make-variable-buffer-local 'cua--status-string) | ||
| 1106 | |||
| 1107 | (unless cua--keymaps-initalized | ||
| 1108 | (cua--init-keymaps) | ||
| 1109 | (setq cua--keymaps-initalized t)) | ||
| 1110 | |||
| 1111 | (if cua-mode | ||
| 1112 | (progn | ||
| 1113 | (add-hook 'pre-command-hook 'cua--pre-command-handler) | ||
| 1114 | (add-hook 'post-command-hook 'cua--post-command-handler) | ||
| 1115 | (if (and cua-enable-modeline-indications (not (assoc 'cua-mode minor-mode-alist))) | ||
| 1116 | (setq minor-mode-alist (cons '(cua-mode cua--status-string) minor-mode-alist))) | ||
| 1117 | ) | ||
| 1118 | (remove-hook 'pre-command-hook 'cua--pre-command-handler) | ||
| 1119 | (remove-hook 'post-command-hook 'cua--post-command-handler)) | ||
| 1120 | (cua--fix-keymaps (not cua-mode)) | ||
| 1121 | (if (fboundp 'cua--rectangle-on-off) | ||
| 1122 | (cua--rectangle-on-off cua-mode)) | ||
| 1123 | (setq transient-mark-mode (and cua-mode | ||
| 1124 | (if cua-highlight-region-shift-only | ||
| 1125 | (not cua--explicit-region-start) | ||
| 1126 | t)))) | ||
| 1127 | |||
| 1128 | (defun cua-debug () | ||
| 1129 | "Toggle cua debugging." | ||
| 1130 | (interactive) | ||
| 1131 | (setq cua--debug (not cua--debug))) | ||
| 1132 | |||
| 1133 | ;;; cua-base.el ends here | ||
diff --git a/lisp/emulation/cua-gmrk.el b/lisp/emulation/cua-gmrk.el new file mode 100644 index 00000000000..2ae7dc6dc65 --- /dev/null +++ b/lisp/emulation/cua-gmrk.el | |||
| @@ -0,0 +1,385 @@ | |||
| 1 | ;;; cua-gmrk.el --- CUA unified global mark support | ||
| 2 | |||
| 3 | ;; Copyright (C) 1997-2002 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | ;; Author: Kim F. Storm <storm@cua.dk> | ||
| 6 | ;; Keywords: keyboard emulations convenience cua mark | ||
| 7 | |||
| 8 | ;; This file is part of GNU Emacs. | ||
| 9 | |||
| 10 | ;; GNU Emacs is free software; you can redistribute it and/or modify | ||
| 11 | ;; it under the terms of the GNU General Public License as published by | ||
| 12 | ;; the Free Software Foundation; either version 2, or (at your option) | ||
| 13 | ;; any later version. | ||
| 14 | |||
| 15 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 18 | ;; GNU General Public License for more details. | ||
| 19 | |||
| 20 | ;; You should have received a copy of the GNU General Public License | ||
| 21 | ;; along with GNU Emacs; see the file COPYING. If not, write to the | ||
| 22 | ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
| 23 | ;; Boston, MA 02111-1307, USA. | ||
| 24 | |||
| 25 | |||
| 26 | (provide 'cua-gmrk) | ||
| 27 | |||
| 28 | (eval-when-compile | ||
| 29 | (require 'cua-base) | ||
| 30 | (require 'cua-rect) | ||
| 31 | ) | ||
| 32 | |||
| 33 | ;;; Global Marker | ||
| 34 | |||
| 35 | ;; Non-nil when global marker is active. | ||
| 36 | (defvar cua--global-mark-active nil) | ||
| 37 | |||
| 38 | ;; Global mark position marker. | ||
| 39 | (defvar cua--global-mark-marker nil) | ||
| 40 | |||
| 41 | ;; Overlay for global mark position. | ||
| 42 | (defvar cua--global-mark-overlay nil) | ||
| 43 | |||
| 44 | ;; Initialize global mark things once... | ||
| 45 | (defvar cua--global-mark-initialized nil) | ||
| 46 | |||
| 47 | ;; Saved configured blink-cursor-interval | ||
| 48 | (defvar cua--orig-blink-cursor-interval nil) | ||
| 49 | |||
| 50 | (defun cua--deactivate-global-mark (&optional msg) | ||
| 51 | (when cua--global-mark-overlay | ||
| 52 | (delete-overlay cua--global-mark-overlay) | ||
| 53 | (setq cua--global-mark-overlay nil)) | ||
| 54 | (if (markerp cua--global-mark-marker) | ||
| 55 | (move-marker cua--global-mark-marker nil)) | ||
| 56 | (if cua--orig-blink-cursor-interval | ||
| 57 | (setq blink-cursor-interval cua--orig-blink-cursor-interval | ||
| 58 | cua--orig-blink-cursor-interval nil)) | ||
| 59 | (setq cua--global-mark-active nil) | ||
| 60 | (if msg | ||
| 61 | (message "Global Mark Cleared"))) | ||
| 62 | |||
| 63 | (defun cua--activate-global-mark (&optional msg) | ||
| 64 | (if (not (markerp cua--global-mark-marker)) | ||
| 65 | (setq cua--global-mark-marker (make-marker))) | ||
| 66 | (when (eobp) | ||
| 67 | (insert " ") | ||
| 68 | (backward-char 1)) | ||
| 69 | (move-marker cua--global-mark-marker (point)) | ||
| 70 | (if (overlayp cua--global-mark-overlay) | ||
| 71 | (move-overlay cua--global-mark-overlay (point) (1+ (point))) | ||
| 72 | (setq cua--global-mark-overlay | ||
| 73 | (make-overlay (point) (1+ (point)))) | ||
| 74 | (overlay-put cua--global-mark-overlay 'face 'cua-global-mark-face)) | ||
| 75 | (if (and cua-global-mark-blink-cursor-interval | ||
| 76 | (not cua--orig-blink-cursor-interval)) | ||
| 77 | (setq cua--orig-blink-cursor-interval blink-cursor-interval | ||
| 78 | blink-cursor-interval cua-global-mark-blink-cursor-interval)) | ||
| 79 | (setq cua--global-mark-active t) | ||
| 80 | (if msg | ||
| 81 | (message "Global Mark Set"))) | ||
| 82 | |||
| 83 | (defun cua--global-mark-active () | ||
| 84 | (if cua--global-mark-active | ||
| 85 | (or (and (markerp cua--global-mark-marker) | ||
| 86 | (marker-buffer cua--global-mark-marker)) | ||
| 87 | (and (cua--deactivate-global-mark nil) | ||
| 88 | nil)))) | ||
| 89 | |||
| 90 | (defun cua-toggle-global-mark (stay) | ||
| 91 | "Set or cancel the global marker. | ||
| 92 | When the global marker is set, CUA cut and copy commands will automatically | ||
| 93 | insert the deleted or copied text before the global marker, even when the | ||
| 94 | global marker is in another buffer. | ||
| 95 | If the global marker isn't set, set the global marker at point in the current | ||
| 96 | buffer. Otherwise jump to the global marker position and cancel it. | ||
| 97 | With prefix argument, don't jump to global mark when cancelling it." | ||
| 98 | (interactive "P") | ||
| 99 | (unless cua--global-mark-initialized | ||
| 100 | (cua--init-global-mark)) | ||
| 101 | (if (not (cua--global-mark-active)) | ||
| 102 | (if (not buffer-read-only) | ||
| 103 | (cua--activate-global-mark t) | ||
| 104 | (ding) | ||
| 105 | (message "Cannot set global mark in read-only buffer.")) | ||
| 106 | (when (not stay) | ||
| 107 | (pop-to-buffer (marker-buffer cua--global-mark-marker)) | ||
| 108 | (goto-char cua--global-mark-marker)) | ||
| 109 | (cua--deactivate-global-mark t))) | ||
| 110 | |||
| 111 | (defun cua--insert-at-global-mark (str &optional msg) | ||
| 112 | ;; Insert string at global marker and move marker | ||
| 113 | (save-excursion | ||
| 114 | (set-buffer (marker-buffer cua--global-mark-marker)) | ||
| 115 | (goto-char (marker-position cua--global-mark-marker)) | ||
| 116 | (insert-for-yank str) | ||
| 117 | (cua--activate-global-mark)) | ||
| 118 | (if msg | ||
| 119 | (message "%s %d to global mark in %s:%d" msg | ||
| 120 | (length str) | ||
| 121 | (buffer-name (marker-buffer cua--global-mark-marker)) | ||
| 122 | (marker-position cua--global-mark-marker)))) | ||
| 123 | |||
| 124 | (defun cua--delete-at-global-mark (arg &optional msg) | ||
| 125 | ;; Delete chars at global marker | ||
| 126 | (save-excursion | ||
| 127 | (set-buffer (marker-buffer cua--global-mark-marker)) | ||
| 128 | (goto-char (marker-position cua--global-mark-marker)) | ||
| 129 | (delete-char arg)) | ||
| 130 | (if msg | ||
| 131 | (message "%s %d chars at global mark in %s:%d" msg arg | ||
| 132 | (buffer-name (marker-buffer cua--global-mark-marker)) | ||
| 133 | (marker-position cua--global-mark-marker)))) | ||
| 134 | |||
| 135 | (defun cua-copy-region-to-global-mark (start end) | ||
| 136 | "Copy region to global mark buffer/position." | ||
| 137 | (interactive "r") | ||
| 138 | (if (cua--global-mark-active) | ||
| 139 | (let ((src-buf (current-buffer))) | ||
| 140 | (save-excursion | ||
| 141 | (if (equal (marker-buffer cua--global-mark-marker) src-buf) | ||
| 142 | (let ((text (buffer-substring-no-properties start end))) | ||
| 143 | (goto-char (marker-position cua--global-mark-marker)) | ||
| 144 | (insert text)) | ||
| 145 | (set-buffer (marker-buffer cua--global-mark-marker)) | ||
| 146 | (goto-char (marker-position cua--global-mark-marker)) | ||
| 147 | (insert-buffer-substring-as-yank src-buf start end)) | ||
| 148 | (cua--activate-global-mark) | ||
| 149 | (message "Copied %d to global mark in %s:%d" | ||
| 150 | (abs (- end start)) | ||
| 151 | (buffer-name (marker-buffer cua--global-mark-marker)) | ||
| 152 | (marker-position cua--global-mark-marker)))) | ||
| 153 | (cua--deactivate-global-mark) | ||
| 154 | (message "No Global Mark"))) | ||
| 155 | |||
| 156 | (defun cua-cut-region-to-global-mark (start end) | ||
| 157 | "Move region to global buffer/position." | ||
| 158 | (interactive "r") | ||
| 159 | (if (cua--global-mark-active) | ||
| 160 | (let ((src-buf (current-buffer))) | ||
| 161 | (save-excursion | ||
| 162 | (if (equal (marker-buffer cua--global-mark-marker) src-buf) | ||
| 163 | (if (and (< start (marker-position cua--global-mark-marker)) | ||
| 164 | (< (marker-position cua--global-mark-marker) end)) | ||
| 165 | (message "Can't move region into itself.") | ||
| 166 | (let ((text (buffer-substring-no-properties start end)) | ||
| 167 | (p1 (copy-marker start)) | ||
| 168 | (p2 (copy-marker end))) | ||
| 169 | (goto-char (marker-position cua--global-mark-marker)) | ||
| 170 | (insert text) | ||
| 171 | (cua--activate-global-mark) | ||
| 172 | (delete-region (marker-position p1) (marker-position p2)) | ||
| 173 | (move-marker p1 nil) | ||
| 174 | (move-marker p2 nil))) | ||
| 175 | (set-buffer (marker-buffer cua--global-mark-marker)) | ||
| 176 | (goto-char (marker-position cua--global-mark-marker)) | ||
| 177 | (insert-buffer-substring src-buf start end) | ||
| 178 | (message "Moved %d to global mark in %s:%d" | ||
| 179 | (abs (- end start)) | ||
| 180 | (buffer-name (marker-buffer cua--global-mark-marker)) | ||
| 181 | (marker-position cua--global-mark-marker)) | ||
| 182 | (cua--activate-global-mark) | ||
| 183 | (set-buffer src-buf) | ||
| 184 | (delete-region start end)))) | ||
| 185 | (cua--deactivate-global-mark) | ||
| 186 | (message "No Global Mark"))) | ||
| 187 | |||
| 188 | (defun cua--copy-rectangle-to-global-mark (as-text) | ||
| 189 | ;; Copy rectangle to global mark buffer/position. | ||
| 190 | (if (cua--global-mark-active) | ||
| 191 | (let ((src-buf (current-buffer)) | ||
| 192 | (text (cua--extract-rectangle))) | ||
| 193 | (save-excursion | ||
| 194 | (set-buffer (marker-buffer cua--global-mark-marker)) | ||
| 195 | (goto-char (marker-position cua--global-mark-marker)) | ||
| 196 | (if as-text | ||
| 197 | (while text | ||
| 198 | (insert-for-yank (car text)) | ||
| 199 | (if (setq text (cdr text)) | ||
| 200 | (insert "\n"))) | ||
| 201 | (cua--insert-rectangle text 'auto)) | ||
| 202 | (cua--activate-global-mark) | ||
| 203 | (message "Copied rectangle to global mark in %s:%d" | ||
| 204 | (buffer-name (marker-buffer cua--global-mark-marker)) | ||
| 205 | (marker-position cua--global-mark-marker)))) | ||
| 206 | (cua--deactivate-global-mark) | ||
| 207 | (message "No Global Mark"))) | ||
| 208 | |||
| 209 | (defun cua--cut-rectangle-to-global-mark (as-text) | ||
| 210 | ;; Move rectangle to global buffer/position. | ||
| 211 | (if (cua--global-mark-active) | ||
| 212 | (let ((src-buf (current-buffer))) | ||
| 213 | (save-excursion | ||
| 214 | (if (equal (marker-buffer cua--global-mark-marker) src-buf) | ||
| 215 | (let ((olist (overlays-at (marker-position cua--global-mark-marker))) | ||
| 216 | in-rect) | ||
| 217 | (while olist | ||
| 218 | (if (eq (overlay-get (car olist) 'face) 'cua-rectangle-face) | ||
| 219 | (setq in-rect t olist nil) | ||
| 220 | (setq olist (cdr olist)))) | ||
| 221 | (if in-rect | ||
| 222 | (message "Can't move rectangle into itself.") | ||
| 223 | (let ((text (cua--extract-rectangle))) | ||
| 224 | (cua--delete-rectangle) | ||
| 225 | (goto-char (marker-position cua--global-mark-marker)) | ||
| 226 | (if as-text | ||
| 227 | (while text | ||
| 228 | (insert-for-yank (car text)) | ||
| 229 | (if (setq text (cdr text)) | ||
| 230 | (insert "\n"))) | ||
| 231 | (cua--insert-rectangle text 'auto)) | ||
| 232 | (cua--activate-global-mark)))) | ||
| 233 | (let ((text (cua--extract-rectangle))) | ||
| 234 | (cua--delete-rectangle) | ||
| 235 | (set-buffer (marker-buffer cua--global-mark-marker)) | ||
| 236 | (goto-char (marker-position cua--global-mark-marker)) | ||
| 237 | (cua--insert-rectangle text 'auto)) | ||
| 238 | (message "Moved rectangle to global mark in %s:%d" | ||
| 239 | (buffer-name (marker-buffer cua--global-mark-marker)) | ||
| 240 | (marker-position cua--global-mark-marker)) | ||
| 241 | (cua--activate-global-mark)))) | ||
| 242 | (cua--deactivate-global-mark) | ||
| 243 | (message "No Global Mark"))) | ||
| 244 | |||
| 245 | (defun cua-copy-to-global-mark () | ||
| 246 | "Copy active region/rectangle to global mark buffer/position." | ||
| 247 | (interactive) | ||
| 248 | (setq cua--last-killed-rectangle nil) | ||
| 249 | (if cua--rectangle | ||
| 250 | (cua--copy-rectangle-to-global-mark nil) | ||
| 251 | (let ((start (mark)) (end (point))) | ||
| 252 | (or (<= start end) | ||
| 253 | (setq start (prog1 end (setq end start)))) | ||
| 254 | (cua-copy-region-to-global-mark start end)))) | ||
| 255 | |||
| 256 | (defun cua-copy-next-to-global-mark (n) | ||
| 257 | "Copy the following N characters in buffer to global mark buffer/position." | ||
| 258 | (interactive "p") | ||
| 259 | (setq cua--last-killed-rectangle nil) | ||
| 260 | (or (eobp) | ||
| 261 | (let ((p (point))) | ||
| 262 | (goto-char (+ p n)) | ||
| 263 | (cua-copy-region-to-global-mark p (point))))) | ||
| 264 | |||
| 265 | (defun cua-cut-to-global-mark () | ||
| 266 | "Move active region/rectangle to global mark buffer/position." | ||
| 267 | (interactive) | ||
| 268 | (if buffer-read-only | ||
| 269 | (cua-copy-to-global-mark) | ||
| 270 | (setq cua--last-killed-rectangle nil) | ||
| 271 | (if cua--rectangle | ||
| 272 | (cua--cut-rectangle-to-global-mark nil) | ||
| 273 | (let ((start (mark)) (end (point))) | ||
| 274 | (or (<= start end) | ||
| 275 | (setq start (prog1 end (setq end start)))) | ||
| 276 | (cua-cut-region-to-global-mark start end))))) | ||
| 277 | |||
| 278 | (defun cua-cut-next-to-global-mark (n) | ||
| 279 | "Move the following N characters in buffer to global mark buffer/position." | ||
| 280 | (interactive "p") | ||
| 281 | (setq cua--last-killed-rectangle nil) | ||
| 282 | (or (eobp) | ||
| 283 | (let ((p (point))) | ||
| 284 | (goto-char (+ p n)) | ||
| 285 | (cua-cut-region-to-global-mark p (point))))) | ||
| 286 | |||
| 287 | (defun cua-delete-char-at-global-mark (arg) | ||
| 288 | "Delete character following the global mark position." | ||
| 289 | (interactive "p") | ||
| 290 | (cua--delete-at-global-mark arg "Deleted")) | ||
| 291 | |||
| 292 | (defun cua-delete-backward-char-at-global-mark (arg) | ||
| 293 | "Delete character before the global mark position." | ||
| 294 | (interactive "p") | ||
| 295 | (cua--delete-at-global-mark (- arg) "Deleted backward")) | ||
| 296 | |||
| 297 | (defun cua-insert-char-at-global-mark () | ||
| 298 | "Insert the character you type at the global mark position." | ||
| 299 | (interactive) | ||
| 300 | (cua--insert-at-global-mark (char-to-string (aref (this-single-command-keys) 0)) "Inserted")) | ||
| 301 | |||
| 302 | (defun cua-insert-newline-at-global-mark () | ||
| 303 | "Insert a newline at the global mark position." | ||
| 304 | (interactive) | ||
| 305 | (cua--insert-at-global-mark "\n")) | ||
| 306 | |||
| 307 | (defun cua-indent-to-global-mark-column () | ||
| 308 | "Indent current line or rectangle to global mark column." | ||
| 309 | (interactive "*") | ||
| 310 | (if (cua--global-mark-active) | ||
| 311 | (let (col) | ||
| 312 | (save-excursion | ||
| 313 | (set-buffer (marker-buffer cua--global-mark-marker)) | ||
| 314 | (goto-char (marker-position cua--global-mark-marker)) | ||
| 315 | (setq col (current-column))) | ||
| 316 | (if cua--rectangle | ||
| 317 | (cua--indent-rectangle nil col t) | ||
| 318 | (indent-to col)) | ||
| 319 | (if (eq (current-buffer) (marker-buffer cua--global-mark-marker)) | ||
| 320 | (save-excursion | ||
| 321 | (goto-char (marker-position cua--global-mark-marker)) | ||
| 322 | (move-to-column col) | ||
| 323 | (move-marker cua--global-mark-marker (point)) | ||
| 324 | (move-overlay cua--global-mark-overlay (point) (1+ (point)))))))) | ||
| 325 | |||
| 326 | |||
| 327 | (defun cua-cancel-global-mark () | ||
| 328 | "Cancel the global mark." | ||
| 329 | (interactive) | ||
| 330 | (if mark-active | ||
| 331 | (cua-cancel) | ||
| 332 | (if (cua--global-mark-active) | ||
| 333 | (cua--deactivate-global-mark t))) | ||
| 334 | (cua--fallback)) | ||
| 335 | |||
| 336 | ;;; Post-command hook for global mark. | ||
| 337 | |||
| 338 | (defun cua--global-mark-post-command () | ||
| 339 | (when (and (cua--global-mark-active) ;; Updates cua--global-mark-active variable | ||
| 340 | cua-global-mark-keep-visible) | ||
| 341 | ;; keep global mark position visible | ||
| 342 | (sit-for 0) | ||
| 343 | (if (or (not (eq (current-buffer) (marker-buffer cua--global-mark-marker))) | ||
| 344 | (not (pos-visible-in-window-p (marker-position cua--global-mark-marker)))) | ||
| 345 | (let ((w (selected-window)) (p (point)) h) | ||
| 346 | ;; The following code is an attempt to keep the global mark visible in | ||
| 347 | ;; other window -- but it doesn't work. | ||
| 348 | (switch-to-buffer-other-window (marker-buffer cua--global-mark-marker) t) | ||
| 349 | (goto-char (marker-position cua--global-mark-marker)) | ||
| 350 | (if (not (pos-visible-in-window-p (marker-position cua--global-mark-marker))) | ||
| 351 | (recenter (if (> (setq h (- (window-height) 4)) 1) h '(4)))) | ||
| 352 | (select-window w) | ||
| 353 | (goto-char p))))) | ||
| 354 | |||
| 355 | ;;; Initialization | ||
| 356 | |||
| 357 | (defun cua--init-global-mark () | ||
| 358 | (unless (face-background 'cua-global-mark-face) | ||
| 359 | (copy-face 'region 'cua-global-mark-face) | ||
| 360 | (set-face-foreground 'cua-global-mark-face "black") | ||
| 361 | (set-face-background 'cua-global-mark-face "cyan")) | ||
| 362 | |||
| 363 | (define-key cua--global-mark-keymap [remap copy-region-as-kill] 'cua-copy-to-global-mark) | ||
| 364 | (define-key cua--global-mark-keymap [remap kill-ring-save] 'cua-copy-to-global-mark) | ||
| 365 | (define-key cua--global-mark-keymap [remap kill-region] 'cua-cut-to-global-mark) | ||
| 366 | (define-key cua--global-mark-keymap [remap yank] 'cua-copy-next-to-global-mark) | ||
| 367 | |||
| 368 | (define-key cua--global-mark-keymap [remap keyboard-escape-quit] 'cua-cancel-global-mark) | ||
| 369 | (define-key cua--global-mark-keymap [remap keyboard-quit] 'cua-cancel-global-mark) | ||
| 370 | |||
| 371 | (define-key cua--global-mark-keymap [(control ?d)] 'cua-cut-next-to-global-mark) | ||
| 372 | (define-key cua--global-mark-keymap [remap delete-backward-char] 'cua-delete-backward-char-at-global-mark) | ||
| 373 | (define-key cua--global-mark-keymap [remap backward-delete-char] 'cua-delete-backward-char-at-global-mark) | ||
| 374 | (define-key cua--global-mark-keymap [remap backward-delete-char-untabify] 'cua-delete-backward-char-at-global-mark) | ||
| 375 | (define-key cua--global-mark-keymap [remap self-insert-command] 'cua-insert-char-at-global-mark) | ||
| 376 | (define-key cua--global-mark-keymap [remap self-insert-iso] 'cua-insert-char-at-global-mark) | ||
| 377 | (define-key cua--global-mark-keymap [remap newline] 'cua-insert-newline-at-global-mark) | ||
| 378 | (define-key cua--global-mark-keymap [remap newline-and-indent] 'cua-insert-newline-at-global-mark) | ||
| 379 | (define-key cua--global-mark-keymap "\r" 'cua-insert-newline-at-global-mark) | ||
| 380 | |||
| 381 | (define-key cua--global-mark-keymap "\t" 'cua-indent-to-global-mark-column) | ||
| 382 | |||
| 383 | (setq cua--global-mark-initialized t)) | ||
| 384 | |||
| 385 | ;;; cua-gmrk.el ends here | ||
diff --git a/lisp/emulation/cua-rect.el b/lisp/emulation/cua-rect.el new file mode 100644 index 00000000000..009dfde71d8 --- /dev/null +++ b/lisp/emulation/cua-rect.el | |||
| @@ -0,0 +1,1375 @@ | |||
| 1 | ;;; cua-rect.el --- CUA unified rectangle support | ||
| 2 | |||
| 3 | ;; Copyright (C) 1997-2002 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | ;; Author: Kim F. Storm <storm@cua.dk> | ||
| 6 | ;; Keywords: keyboard emulations convenience CUA | ||
| 7 | |||
| 8 | ;; This file is part of GNU Emacs. | ||
| 9 | |||
| 10 | ;; GNU Emacs is free software; you can redistribute it and/or modify | ||
| 11 | ;; it under the terms of the GNU General Public License as published by | ||
| 12 | ;; the Free Software Foundation; either version 2, or (at your option) | ||
| 13 | ;; any later version. | ||
| 14 | |||
| 15 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 18 | ;; GNU General Public License for more details. | ||
| 19 | |||
| 20 | ;; You should have received a copy of the GNU General Public License | ||
| 21 | ;; along with GNU Emacs; see the file COPYING. If not, write to the | ||
| 22 | ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
| 23 | ;; Boston, MA 02111-1307, USA. | ||
| 24 | |||
| 25 | ;;; Acknowledgements | ||
| 26 | |||
| 27 | ;; The rectangle handling and display code borrows from the standard | ||
| 28 | ;; GNU emacs rect.el package and the the rect-mark.el package by Rick | ||
| 29 | ;; Sladkey <jrs@world.std.com>. | ||
| 30 | |||
| 31 | (provide 'cua-rect) | ||
| 32 | |||
| 33 | (eval-when-compile | ||
| 34 | (require 'cua-base) | ||
| 35 | (require 'cua-gmrk) | ||
| 36 | ) | ||
| 37 | |||
| 38 | ;;; Rectangle support | ||
| 39 | |||
| 40 | (require 'rect) | ||
| 41 | |||
| 42 | ;; If non-nil, restrict current region to this rectangle. | ||
| 43 | ;; Value is a vector [top bot left right corner ins pad select]. | ||
| 44 | ;; CORNER specifies currently active corner 0=t/l 1=t/r 2=b/l 3=b/r. | ||
| 45 | ;; INS specifies whether to insert on left(nil) or right(t) side. | ||
| 46 | ;; If PAD is non-nil, tabs are converted to spaces when necessary. | ||
| 47 | ;; If SELECT is a regexp, only lines starting with that regexp are affected.") | ||
| 48 | (defvar cua--rectangle nil) | ||
| 49 | (make-variable-buffer-local 'cua--rectangle) | ||
| 50 | |||
| 51 | ;; Most recent rectangle geometry. Note: car is buffer. | ||
| 52 | (defvar cua--last-rectangle nil) | ||
| 53 | |||
| 54 | ;; Rectangle restored by undo. | ||
| 55 | (defvar cua--restored-rectangle nil) | ||
| 56 | |||
| 57 | ;; Last rectangle copied/killed; nil if last kill was not a rectangle. | ||
| 58 | (defvar cua--last-killed-rectangle nil) | ||
| 59 | |||
| 60 | ;; List of overlays used to display current rectangle. | ||
| 61 | (defvar cua--rectangle-overlays nil) | ||
| 62 | (make-variable-buffer-local 'cua--rectangle-overlays) | ||
| 63 | |||
| 64 | ;; Per-buffer CUA mode undo list. | ||
| 65 | (defvar cua--undo-list nil) | ||
| 66 | (make-variable-buffer-local 'cua--undo-list) | ||
| 67 | |||
| 68 | ;; Record undo boundary for rectangle undo. | ||
| 69 | (defun cua--rectangle-undo-boundary () | ||
| 70 | (when (listp buffer-undo-list) | ||
| 71 | (if (> (length cua--undo-list) cua-undo-max) | ||
| 72 | (setcdr (nthcdr (1- cua-undo-max) cua--undo-list) nil)) | ||
| 73 | (undo-boundary) | ||
| 74 | (setq cua--undo-list | ||
| 75 | (cons (cons (cdr buffer-undo-list) (copy-sequence cua--rectangle)) cua--undo-list)))) | ||
| 76 | |||
| 77 | (defun cua--rectangle-undo (&optional arg) | ||
| 78 | "Undo some previous changes. | ||
| 79 | Knows about CUA rectangle highlighting in addition to standard undo." | ||
| 80 | (interactive "*P") | ||
| 81 | (if cua--rectangle | ||
| 82 | (cua--rectangle-undo-boundary)) | ||
| 83 | (undo arg) | ||
| 84 | (let ((l cua--undo-list)) | ||
| 85 | (while l | ||
| 86 | (if (eq (car (car l)) pending-undo-list) | ||
| 87 | (setq cua--restored-rectangle | ||
| 88 | (and (vectorp (cdr (car l))) (cdr (car l))) | ||
| 89 | l nil) | ||
| 90 | (setq l (cdr l))))) | ||
| 91 | (setq cua--buffer-and-point-before-command nil)) | ||
| 92 | |||
| 93 | (defvar cua--tidy-undo-counter 0 | ||
| 94 | "Number of times `cua--tidy-undo-lists' have run successfully.") | ||
| 95 | |||
| 96 | ;; Clean out danling entries from cua's undo list. | ||
| 97 | ;; Since this list contains pointers into the standard undo list, | ||
| 98 | ;; such references are only meningful as undo information if the | ||
| 99 | ;; corresponding entry is still on the standard undo list. | ||
| 100 | |||
| 101 | (defun cua--tidy-undo-lists (&optional clean) | ||
| 102 | (let ((buffers (buffer-list)) (cnt cua--tidy-undo-counter)) | ||
| 103 | (while (and buffers (or clean (not (input-pending-p)))) | ||
| 104 | (with-current-buffer (car buffers) | ||
| 105 | (when (local-variable-p 'cua--undo-list) | ||
| 106 | (if (or clean (null cua--undo-list) (eq buffer-undo-list t)) | ||
| 107 | (progn | ||
| 108 | (kill-local-variable 'cua--undo-list) | ||
| 109 | (setq cua--tidy-undo-counter (1+ cua--tidy-undo-counter))) | ||
| 110 | (let* ((bul buffer-undo-list) | ||
| 111 | (cul (cons nil cua--undo-list)) | ||
| 112 | (cc (car (car (cdr cul))))) | ||
| 113 | (while (and bul cc) | ||
| 114 | (if (setq bul (memq cc bul)) | ||
| 115 | (setq cul (cdr cul) | ||
| 116 | cc (and (cdr cul) (car (car (cdr cul))))))) | ||
| 117 | (when cc | ||
| 118 | (if cua--debug | ||
| 119 | (setq cc (length (cdr cul)))) | ||
| 120 | (if (eq (cdr cul) cua--undo-list) | ||
| 121 | (setq cua--undo-list nil) | ||
| 122 | (setcdr cul nil)) | ||
| 123 | (setq cua--tidy-undo-counter (1+ cua--tidy-undo-counter)) | ||
| 124 | (if cua--debug | ||
| 125 | (message "Clean undo list in %s (%d)" | ||
| 126 | (buffer-name) cc))))))) | ||
| 127 | (setq buffers (cdr buffers))) | ||
| 128 | (/= cnt cua--tidy-undo-counter))) | ||
| 129 | |||
| 130 | ;;; Rectangle geometry | ||
| 131 | |||
| 132 | (defun cua--rectangle-top (&optional val) | ||
| 133 | ;; Top of CUA rectangle (buffer position on first line). | ||
| 134 | (if (not val) | ||
| 135 | (aref cua--rectangle 0) | ||
| 136 | (setq val (line-beginning-position)) | ||
| 137 | (if (<= val (aref cua--rectangle 1)) | ||
| 138 | (aset cua--rectangle 0 val) | ||
| 139 | (aset cua--rectangle 1 val) | ||
| 140 | (cua--rectangle-corner 2)))) | ||
| 141 | |||
| 142 | (defun cua--rectangle-bot (&optional val) | ||
| 143 | ;; Bot of CUA rectangle (buffer position on last line). | ||
| 144 | (if (not val) | ||
| 145 | (aref cua--rectangle 1) | ||
| 146 | (setq val (line-end-position)) | ||
| 147 | (if (>= val (aref cua--rectangle 0)) | ||
| 148 | (aset cua--rectangle 1 val) | ||
| 149 | (aset cua--rectangle 0 val) | ||
| 150 | (cua--rectangle-corner 2)))) | ||
| 151 | |||
| 152 | (defun cua--rectangle-left (&optional val) | ||
| 153 | ;; Left column of CUA rectangle. | ||
| 154 | (if (integerp val) | ||
| 155 | (if (<= val (aref cua--rectangle 3)) | ||
| 156 | (aset cua--rectangle 2 val) | ||
| 157 | (aset cua--rectangle 3 val) | ||
| 158 | (cua--rectangle-corner (if (cua--rectangle-right-side) -1 1))) | ||
| 159 | (aref cua--rectangle 2))) | ||
| 160 | |||
| 161 | (defun cua--rectangle-right (&optional val) | ||
| 162 | ;; Right column of CUA rectangle. | ||
| 163 | (if (integerp val) | ||
| 164 | (if (>= val (aref cua--rectangle 2)) | ||
| 165 | (aset cua--rectangle 3 val) | ||
| 166 | (aset cua--rectangle 2 val) | ||
| 167 | (cua--rectangle-corner (if (cua--rectangle-right-side) -1 1))) | ||
| 168 | (aref cua--rectangle 3))) | ||
| 169 | |||
| 170 | (defun cua--rectangle-corner (&optional advance) | ||
| 171 | ;; Currently active corner of rectangle. | ||
| 172 | (let ((c (aref cua--rectangle 4))) | ||
| 173 | (if (not (integerp advance)) | ||
| 174 | c | ||
| 175 | (aset cua--rectangle 4 | ||
| 176 | (if (= advance 0) | ||
| 177 | (- 3 c) ; opposite corner | ||
| 178 | (mod (+ c 4 advance) 4))) | ||
| 179 | (aset cua--rectangle 5 0)))) | ||
| 180 | |||
| 181 | (defun cua--rectangle-right-side (&optional topbot) | ||
| 182 | ;; t if point is on right side of rectangle. | ||
| 183 | (if (and topbot (= (cua--rectangle-left) (cua--rectangle-right))) | ||
| 184 | (< (cua--rectangle-corner) 2) | ||
| 185 | (= (mod (cua--rectangle-corner) 2) 1))) | ||
| 186 | |||
| 187 | (defun cua--rectangle-column () | ||
| 188 | (if (cua--rectangle-right-side) | ||
| 189 | (cua--rectangle-right) | ||
| 190 | (cua--rectangle-left))) | ||
| 191 | |||
| 192 | (defun cua--rectangle-insert-col (&optional col) | ||
| 193 | ;; Currently active corner of rectangle. | ||
| 194 | (if (integerp col) | ||
| 195 | (aset cua--rectangle 5 col) | ||
| 196 | (if (cua--rectangle-right-side t) | ||
| 197 | (if (= (aref cua--rectangle 5) 0) | ||
| 198 | (1+ (cua--rectangle-right)) | ||
| 199 | (aref cua--rectangle 5)) | ||
| 200 | (cua--rectangle-left)))) | ||
| 201 | |||
| 202 | (defun cua--rectangle-padding (&optional set val) | ||
| 203 | ;; Current setting of rectangle padding | ||
| 204 | (if set | ||
| 205 | (aset cua--rectangle 6 val)) | ||
| 206 | (and (not buffer-read-only) | ||
| 207 | (aref cua--rectangle 6))) | ||
| 208 | |||
| 209 | (defun cua--rectangle-restriction (&optional val bounded negated) | ||
| 210 | ;; Current rectangle restriction | ||
| 211 | (if val | ||
| 212 | (aset cua--rectangle 7 | ||
| 213 | (and (stringp val) | ||
| 214 | (> (length val) 0) | ||
| 215 | (list val bounded negated))) | ||
| 216 | (aref cua--rectangle 7))) | ||
| 217 | |||
| 218 | (defun cua--rectangle-assert () | ||
| 219 | (message "%S (%d)" cua--rectangle (point)) | ||
| 220 | (if (< (cua--rectangle-right) (cua--rectangle-left)) | ||
| 221 | (message "rectangle right < left")) | ||
| 222 | (if (< (cua--rectangle-bot) (cua--rectangle-top)) | ||
| 223 | (message "rectangle bot < top"))) | ||
| 224 | |||
| 225 | (defun cua--rectangle-get-corners (&optional pad) | ||
| 226 | ;; Calculate the rectangular region represented by point and mark, | ||
| 227 | ;; putting start in the upper left corner and end in the | ||
| 228 | ;; bottom right corner. | ||
| 229 | (let ((top (point)) (bot (mark)) r l corner) | ||
| 230 | (save-excursion | ||
| 231 | (goto-char top) | ||
| 232 | (setq l (current-column)) | ||
| 233 | (goto-char bot) | ||
| 234 | (setq r (current-column)) | ||
| 235 | (if (<= top bot) | ||
| 236 | (setq corner (if (<= l r) 0 1)) | ||
| 237 | (setq top (prog1 bot (setq bot top))) | ||
| 238 | (setq corner (if (<= l r) 2 3))) | ||
| 239 | (if (<= l r) | ||
| 240 | (if (< l r) | ||
| 241 | (setq r (1- r))) | ||
| 242 | (setq l (prog1 r (setq r l))) | ||
| 243 | (goto-char top) | ||
| 244 | (move-to-column l pad) | ||
| 245 | (setq top (point)) | ||
| 246 | (goto-char bot) | ||
| 247 | (move-to-column r pad) | ||
| 248 | (setq bot (point)))) | ||
| 249 | (vector top bot l r corner 0 pad nil))) | ||
| 250 | |||
| 251 | (defun cua--rectangle-set-corners () | ||
| 252 | ;; Set mark and point in opposite corners of current rectangle. | ||
| 253 | (let (pp pc mp mc (c (cua--rectangle-corner))) | ||
| 254 | (cond | ||
| 255 | ((= c 0) ; top/left -> bot/right | ||
| 256 | (setq pp (cua--rectangle-top) pc (cua--rectangle-left) | ||
| 257 | mp (cua--rectangle-bot) mc (cua--rectangle-right))) | ||
| 258 | ((= c 1) ; top/right -> bot/left | ||
| 259 | (setq pp (cua--rectangle-top) pc (cua--rectangle-right) | ||
| 260 | mp (cua--rectangle-bot) mc (cua--rectangle-left))) | ||
| 261 | ((= c 2) ; bot/left -> top/right | ||
| 262 | (setq pp (cua--rectangle-bot) pc (cua--rectangle-left) | ||
| 263 | mp (cua--rectangle-top) mc (cua--rectangle-right))) | ||
| 264 | ((= c 3) ; bot/right -> top/left | ||
| 265 | (setq pp (cua--rectangle-bot) pc (cua--rectangle-right) | ||
| 266 | mp (cua--rectangle-top) mc (cua--rectangle-left)))) | ||
| 267 | (goto-char mp) | ||
| 268 | (move-to-column mc (cua--rectangle-padding)) | ||
| 269 | (set-mark (point)) | ||
| 270 | (goto-char pp) | ||
| 271 | (move-to-column pc (cua--rectangle-padding)))) | ||
| 272 | |||
| 273 | ;;; Rectangle resizing | ||
| 274 | |||
| 275 | (defun cua--forward-line (n pad) | ||
| 276 | ;; Move forward/backward one line. Returns t if movement. | ||
| 277 | (if (or (not pad) (< n 0)) | ||
| 278 | (= (forward-line n) 0) | ||
| 279 | (next-line 1) | ||
| 280 | t)) | ||
| 281 | |||
| 282 | (defun cua--rectangle-resized () | ||
| 283 | ;; Refresh state after resizing rectangle | ||
| 284 | (setq cua--buffer-and-point-before-command nil) | ||
| 285 | (cua--pad-rectangle) | ||
| 286 | (cua--rectangle-insert-col 0) | ||
| 287 | (cua--rectangle-set-corners) | ||
| 288 | (cua--keep-active)) | ||
| 289 | |||
| 290 | (defun cua-resize-rectangle-right (n) | ||
| 291 | "Resize rectangle to the right." | ||
| 292 | (interactive "p") | ||
| 293 | (let ((pad (cua--rectangle-padding)) (resized (> n 0))) | ||
| 294 | (while (> n 0) | ||
| 295 | (setq n (1- n)) | ||
| 296 | (cond | ||
| 297 | ((and (cua--rectangle-right-side) (or pad (eolp))) | ||
| 298 | (cua--rectangle-right (1+ (cua--rectangle-right))) | ||
| 299 | (move-to-column (cua--rectangle-right) pad)) | ||
| 300 | ((cua--rectangle-right-side) | ||
| 301 | (forward-char 1) | ||
| 302 | (cua--rectangle-right (current-column))) | ||
| 303 | ((or pad (eolp)) | ||
| 304 | (cua--rectangle-left (1+ (cua--rectangle-left))) | ||
| 305 | (move-to-column (cua--rectangle-right) pad)) | ||
| 306 | (t | ||
| 307 | (forward-char 1) | ||
| 308 | (cua--rectangle-left (current-column))))) | ||
| 309 | (if resized | ||
| 310 | (cua--rectangle-resized)))) | ||
| 311 | |||
| 312 | (defun cua-resize-rectangle-left (n) | ||
| 313 | "Resize rectangle to the left." | ||
| 314 | (interactive "p") | ||
| 315 | (let ((pad (cua--rectangle-padding)) resized) | ||
| 316 | (while (> n 0) | ||
| 317 | (setq n (1- n)) | ||
| 318 | (if (or (= (cua--rectangle-right) 0) | ||
| 319 | (and (not (cua--rectangle-right-side)) (= (cua--rectangle-left) 0))) | ||
| 320 | (setq n 0) | ||
| 321 | (cond | ||
| 322 | ((and (cua--rectangle-right-side) (or pad (eolp) (bolp))) | ||
| 323 | (cua--rectangle-right (1- (cua--rectangle-right))) | ||
| 324 | (move-to-column (cua--rectangle-right) pad)) | ||
| 325 | ((cua--rectangle-right-side) | ||
| 326 | (backward-char 1) | ||
| 327 | (cua--rectangle-right (current-column))) | ||
| 328 | ((or pad (eolp) (bolp)) | ||
| 329 | (cua--rectangle-left (1- (cua--rectangle-left))) | ||
| 330 | (move-to-column (cua--rectangle-right) pad)) | ||
| 331 | (t | ||
| 332 | (backward-char 1) | ||
| 333 | (cua--rectangle-left (current-column)))) | ||
| 334 | (setq resized t))) | ||
| 335 | (if resized | ||
| 336 | (cua--rectangle-resized)))) | ||
| 337 | |||
| 338 | (defun cua-resize-rectangle-down (n) | ||
| 339 | "Resize rectangle downwards." | ||
| 340 | (interactive "p") | ||
| 341 | (let ((pad (cua--rectangle-padding)) resized) | ||
| 342 | (while (> n 0) | ||
| 343 | (setq n (1- n)) | ||
| 344 | (cond | ||
| 345 | ((>= (cua--rectangle-corner) 2) | ||
| 346 | (goto-char (cua--rectangle-bot)) | ||
| 347 | (when (cua--forward-line 1 pad) | ||
| 348 | (move-to-column (cua--rectangle-column) pad) | ||
| 349 | (cua--rectangle-bot t) | ||
| 350 | (setq resized t))) | ||
| 351 | (t | ||
| 352 | (goto-char (cua--rectangle-top)) | ||
| 353 | (when (cua--forward-line 1 pad) | ||
| 354 | (move-to-column (cua--rectangle-column) pad) | ||
| 355 | (cua--rectangle-top t) | ||
| 356 | (setq resized t))))) | ||
| 357 | (if resized | ||
| 358 | (cua--rectangle-resized)))) | ||
| 359 | |||
| 360 | (defun cua-resize-rectangle-up (n) | ||
| 361 | "Resize rectangle upwards." | ||
| 362 | (interactive "p") | ||
| 363 | (let ((pad (cua--rectangle-padding)) resized) | ||
| 364 | (while (> n 0) | ||
| 365 | (setq n (1- n)) | ||
| 366 | (cond | ||
| 367 | ((>= (cua--rectangle-corner) 2) | ||
| 368 | (goto-char (cua--rectangle-bot)) | ||
| 369 | (when (cua--forward-line -1 pad) | ||
| 370 | (move-to-column (cua--rectangle-column) pad) | ||
| 371 | (cua--rectangle-bot t) | ||
| 372 | (setq resized t))) | ||
| 373 | (t | ||
| 374 | (goto-char (cua--rectangle-top)) | ||
| 375 | (when (cua--forward-line -1 pad) | ||
| 376 | (move-to-column (cua--rectangle-column) pad) | ||
| 377 | (cua--rectangle-top t) | ||
| 378 | (setq resized t))))) | ||
| 379 | (if resized | ||
| 380 | (cua--rectangle-resized)))) | ||
| 381 | |||
| 382 | (defun cua-resize-rectangle-eol () | ||
| 383 | "Resize rectangle to end of line." | ||
| 384 | (interactive) | ||
| 385 | (unless (eolp) | ||
| 386 | (end-of-line) | ||
| 387 | (if (> (current-column) (cua--rectangle-right)) | ||
| 388 | (cua--rectangle-right (current-column))) | ||
| 389 | (if (not (cua--rectangle-right-side)) | ||
| 390 | (cua--rectangle-corner 1)) | ||
| 391 | (cua--rectangle-resized))) | ||
| 392 | |||
| 393 | (defun cua-resize-rectangle-bol () | ||
| 394 | "Resize rectangle to beginning of line." | ||
| 395 | (interactive) | ||
| 396 | (unless (bolp) | ||
| 397 | (beginning-of-line) | ||
| 398 | (cua--rectangle-left (current-column)) | ||
| 399 | (if (cua--rectangle-right-side) | ||
| 400 | (cua--rectangle-corner -1)) | ||
| 401 | (cua--rectangle-resized))) | ||
| 402 | |||
| 403 | (defun cua-resize-rectangle-bot () | ||
| 404 | "Resize rectangle to bottom of buffer." | ||
| 405 | (interactive) | ||
| 406 | (goto-char (point-max)) | ||
| 407 | (move-to-column (cua--rectangle-column) (cua--rectangle-padding)) | ||
| 408 | (cua--rectangle-bot t) | ||
| 409 | (cua--rectangle-resized)) | ||
| 410 | |||
| 411 | (defun cua-resize-rectangle-top () | ||
| 412 | "Resize rectangle to top of buffer." | ||
| 413 | (interactive) | ||
| 414 | (goto-char (point-min)) | ||
| 415 | (move-to-column (cua--rectangle-column) (cua--rectangle-padding)) | ||
| 416 | (cua--rectangle-top t) | ||
| 417 | (cua--rectangle-resized)) | ||
| 418 | |||
| 419 | (defun cua-resize-rectangle-page-up () | ||
| 420 | "Resize rectangle upwards by one scroll page." | ||
| 421 | (interactive) | ||
| 422 | (let ((pad (cua--rectangle-padding))) | ||
| 423 | (scroll-down) | ||
| 424 | (move-to-column (cua--rectangle-column) pad) | ||
| 425 | (if (>= (cua--rectangle-corner) 2) | ||
| 426 | (cua--rectangle-bot t) | ||
| 427 | (cua--rectangle-top t)) | ||
| 428 | (cua--rectangle-resized))) | ||
| 429 | |||
| 430 | (defun cua-resize-rectangle-page-down () | ||
| 431 | "Resize rectangle downwards by one scroll page." | ||
| 432 | (interactive) | ||
| 433 | (let ((pad (cua--rectangle-padding))) | ||
| 434 | (scroll-up) | ||
| 435 | (move-to-column (cua--rectangle-column) pad) | ||
| 436 | (if (>= (cua--rectangle-corner) 2) | ||
| 437 | (cua--rectangle-bot t) | ||
| 438 | (cua--rectangle-top t)) | ||
| 439 | (cua--rectangle-resized))) | ||
| 440 | |||
| 441 | ;;; Mouse support | ||
| 442 | |||
| 443 | ;; This is pretty simplistic, but it does the job... | ||
| 444 | |||
| 445 | (defun cua-mouse-resize-rectangle (event) | ||
| 446 | "Set rectangle corner at mouse click position." | ||
| 447 | (interactive "e") | ||
| 448 | (mouse-set-point event) | ||
| 449 | (if (cua--rectangle-padding) | ||
| 450 | (move-to-column (car (posn-col-row (event-end event))) t)) | ||
| 451 | (if (cua--rectangle-right-side) | ||
| 452 | (cua--rectangle-right (current-column)) | ||
| 453 | (cua--rectangle-left (current-column))) | ||
| 454 | (if (>= (cua--rectangle-corner) 2) | ||
| 455 | (cua--rectangle-bot t) | ||
| 456 | (cua--rectangle-top t)) | ||
| 457 | (cua--rectangle-resized)) | ||
| 458 | |||
| 459 | (defvar cua--mouse-last-pos nil) | ||
| 460 | |||
| 461 | (defun cua-mouse-set-rectangle-mark (event) | ||
| 462 | "Start rectangle at mouse click position." | ||
| 463 | (interactive "e") | ||
| 464 | (when cua--rectangle | ||
| 465 | (cua--deactivate-rectangle) | ||
| 466 | (cua--deactivate t)) | ||
| 467 | (setq cua--last-rectangle nil) | ||
| 468 | (mouse-set-point event) | ||
| 469 | (cua-set-rectangle-mark) | ||
| 470 | (setq cua--buffer-and-point-before-command nil) | ||
| 471 | (setq cua--mouse-last-pos nil)) | ||
| 472 | |||
| 473 | (defun cua-mouse-save-then-kill-rectangle (event arg) | ||
| 474 | "Expand rectangle to mouse click position and copy rectangle. | ||
| 475 | If command is repeated at same position, delete the rectangle." | ||
| 476 | (interactive "e\nP") | ||
| 477 | (if (and (eq this-command last-command) | ||
| 478 | (eq (point) (car-safe cua--mouse-last-pos)) | ||
| 479 | (eq cua--last-killed-rectangle (cdr-safe cua--mouse-last-pos))) | ||
| 480 | (progn | ||
| 481 | (unless buffer-read-only | ||
| 482 | (cua--delete-rectangle)) | ||
| 483 | (cua--deactivate)) | ||
| 484 | (cua-mouse-resize-rectangle event) | ||
| 485 | (let ((cua-keep-region-after-copy t)) | ||
| 486 | (cua-copy-rectangle arg) | ||
| 487 | (setq cua--mouse-last-pos (cons (point) cua--last-killed-rectangle))))) | ||
| 488 | (defun cua--mouse-ignore (event) | ||
| 489 | (interactive "e") | ||
| 490 | (setq this-command last-command)) | ||
| 491 | |||
| 492 | (defun cua--rectangle-move (dir) | ||
| 493 | (let ((pad (cua--rectangle-padding)) | ||
| 494 | (moved t) | ||
| 495 | (top (cua--rectangle-top)) | ||
| 496 | (bot (cua--rectangle-bot)) | ||
| 497 | (l (cua--rectangle-left)) | ||
| 498 | (r (cua--rectangle-right))) | ||
| 499 | (cond | ||
| 500 | ((eq dir 'up) | ||
| 501 | (goto-char top) | ||
| 502 | (when (cua--forward-line -1 pad) | ||
| 503 | (cua--rectangle-top t) | ||
| 504 | (goto-char bot) | ||
| 505 | (forward-line -1) | ||
| 506 | (cua--rectangle-bot t))) | ||
| 507 | ((eq dir 'down) | ||
| 508 | (goto-char bot) | ||
| 509 | (when (cua--forward-line 1 pad) | ||
| 510 | (cua--rectangle-bot t) | ||
| 511 | (goto-char top) | ||
| 512 | (cua--forward-line 1 pad) | ||
| 513 | (cua--rectangle-top t))) | ||
| 514 | ((eq dir 'left) | ||
| 515 | (when (> l 0) | ||
| 516 | (cua--rectangle-left (1- l)) | ||
| 517 | (cua--rectangle-right (1- r)))) | ||
| 518 | ((eq dir 'right) | ||
| 519 | (cua--rectangle-right (1+ r)) | ||
| 520 | (cua--rectangle-left (1+ l))) | ||
| 521 | (t | ||
| 522 | (setq moved nil))) | ||
| 523 | (when moved | ||
| 524 | (setq cua--buffer-and-point-before-command nil) | ||
| 525 | (cua--pad-rectangle) | ||
| 526 | (cua--rectangle-set-corners) | ||
| 527 | (cua--keep-active)))) | ||
| 528 | |||
| 529 | |||
| 530 | ;;; Operations on current rectangle | ||
| 531 | |||
| 532 | (defun cua--rectangle-operation (keep-clear visible undo pad &optional fct post-fct) | ||
| 533 | ;; Call FCT for each line of region with 4 parameters: | ||
| 534 | ;; Region start, end, left-col, right-col | ||
| 535 | ;; Point is at start when FCT is called | ||
| 536 | ;; Set undo boundary if UNDO is non-nil. | ||
| 537 | ;; Rectangle is padded if PAD = t or numeric and (cua--rectangle-padding) | ||
| 538 | ;; Mark is kept if keep-clear is 'keep and cleared if keep-clear is 'clear. | ||
| 539 | (let* ((start (cua--rectangle-top)) | ||
| 540 | (end (cua--rectangle-bot)) | ||
| 541 | (l (cua--rectangle-left)) | ||
| 542 | (r (1+ (cua--rectangle-right))) | ||
| 543 | (m (make-marker)) | ||
| 544 | (tabpad (and (integerp pad) (= pad 2))) | ||
| 545 | (sel (cua--rectangle-restriction))) | ||
| 546 | (if undo | ||
| 547 | (cua--rectangle-undo-boundary)) | ||
| 548 | (if (integerp pad) | ||
| 549 | (setq pad (cua--rectangle-padding))) | ||
| 550 | (save-excursion | ||
| 551 | (save-restriction | ||
| 552 | (widen) | ||
| 553 | (when (> (cua--rectangle-corner) 1) | ||
| 554 | (goto-char end) | ||
| 555 | (and (bolp) (not (eolp)) (not (eobp)) | ||
| 556 | (setq end (1+ end)))) | ||
| 557 | (when visible | ||
| 558 | (setq start (max (window-start) start)) | ||
| 559 | (setq end (min (window-end) end))) | ||
| 560 | (goto-char end) | ||
| 561 | (setq end (line-end-position)) | ||
| 562 | (goto-char start) | ||
| 563 | (setq start (line-beginning-position)) | ||
| 564 | (narrow-to-region start end) | ||
| 565 | (goto-char (point-min)) | ||
| 566 | (while (< (point) (point-max)) | ||
| 567 | (move-to-column r pad) | ||
| 568 | (and (not pad) (not visible) (> (current-column) r) | ||
| 569 | (backward-char 1)) | ||
| 570 | (if (and tabpad (not pad) (looking-at "\t")) | ||
| 571 | (forward-char 1)) | ||
| 572 | (set-marker m (point)) | ||
| 573 | (move-to-column l pad) | ||
| 574 | (if fct | ||
| 575 | (let ((v t) (p (point))) | ||
| 576 | (when sel | ||
| 577 | (if (car (cdr sel)) | ||
| 578 | (setq v (looking-at (car sel))) | ||
| 579 | (setq v (re-search-forward (car sel) m t)) | ||
| 580 | (goto-char p)) | ||
| 581 | (if (car (cdr (cdr sel))) | ||
| 582 | (setq v (null v)))) | ||
| 583 | (if visible | ||
| 584 | (funcall fct p m l r v) | ||
| 585 | (if v | ||
| 586 | (funcall fct p m l r))))) | ||
| 587 | (set-marker m nil) | ||
| 588 | (forward-line 1)) | ||
| 589 | (if (not visible) | ||
| 590 | (cua--rectangle-bot t)) | ||
| 591 | (if post-fct | ||
| 592 | (funcall post-fct l r)))) | ||
| 593 | (cond | ||
| 594 | ((eq keep-clear 'keep) | ||
| 595 | (cua--keep-active)) | ||
| 596 | ((eq keep-clear 'clear) | ||
| 597 | (cua--deactivate)) | ||
| 598 | ((eq keep-clear 'corners) | ||
| 599 | (cua--rectangle-set-corners) | ||
| 600 | (cua--keep-active))) | ||
| 601 | (setq cua--buffer-and-point-before-command nil))) | ||
| 602 | |||
| 603 | (put 'cua--rectangle-operation 'lisp-indent-function 4) | ||
| 604 | |||
| 605 | (defun cua--pad-rectangle (&optional pad) | ||
| 606 | (if (or pad (cua--rectangle-padding)) | ||
| 607 | (cua--rectangle-operation nil nil t t))) | ||
| 608 | |||
| 609 | (defun cua--delete-rectangle () | ||
| 610 | (cua--rectangle-operation nil nil t 2 | ||
| 611 | '(lambda (s e l r) | ||
| 612 | (delete-region s (if (> e s) e (1+ e)))))) | ||
| 613 | |||
| 614 | (defun cua--extract-rectangle () | ||
| 615 | (let (rect) | ||
| 616 | (cua--rectangle-operation nil nil nil 1 | ||
| 617 | '(lambda (s e l r) | ||
| 618 | (setq rect (cons (buffer-substring-no-properties s e) rect)))) | ||
| 619 | (nreverse rect))) | ||
| 620 | |||
| 621 | (defun cua--insert-rectangle (rect &optional below) | ||
| 622 | ;; Insert rectangle as insert-rectangle, but don't set mark and exit with | ||
| 623 | ;; point at either next to top right or below bottom left corner | ||
| 624 | ;; Notice: In overwrite mode, the rectangle is inserted as separate text lines. | ||
| 625 | (if (and below (eq below 'auto)) | ||
| 626 | (setq below (and (bolp) | ||
| 627 | (or (eolp) (eobp) (= (1+ (point)) (point-max)))))) | ||
| 628 | (let ((lines rect) | ||
| 629 | (insertcolumn (current-column)) | ||
| 630 | (first t) | ||
| 631 | p) | ||
| 632 | (while (or lines below) | ||
| 633 | (or first | ||
| 634 | (if overwrite-mode | ||
| 635 | (insert ?\n) | ||
| 636 | (forward-line 1) | ||
| 637 | (or (bolp) (insert ?\n)) | ||
| 638 | (move-to-column insertcolumn t))) | ||
| 639 | (if (not lines) | ||
| 640 | (setq below nil) | ||
| 641 | (insert-for-yank (car lines)) | ||
| 642 | (setq lines (cdr lines)) | ||
| 643 | (and first (not below) | ||
| 644 | (setq p (point)))) | ||
| 645 | (setq first nil)) | ||
| 646 | (and p (not overwrite-mode) | ||
| 647 | (goto-char p)))) | ||
| 648 | |||
| 649 | (defun cua--copy-rectangle-as-kill (&optional ring) | ||
| 650 | (if cua--register | ||
| 651 | (set-register cua--register (cua--extract-rectangle)) | ||
| 652 | (setq killed-rectangle (cua--extract-rectangle)) | ||
| 653 | (setq cua--last-killed-rectangle (cons (and kill-ring (car kill-ring)) killed-rectangle)) | ||
| 654 | (if ring | ||
| 655 | (kill-new (mapconcat | ||
| 656 | (function (lambda (row) (concat row "\n"))) | ||
| 657 | killed-rectangle ""))))) | ||
| 658 | |||
| 659 | (defun cua--activate-rectangle (&optional force) | ||
| 660 | ;; Turn on rectangular marking mode by disabling transient mark mode | ||
| 661 | ;; and manually handling highlighting from a post command hook. | ||
| 662 | ;; Be careful if we are already marking a rectangle. | ||
| 663 | (setq cua--rectangle | ||
| 664 | (if (and cua--last-rectangle | ||
| 665 | (eq (car cua--last-rectangle) (current-buffer)) | ||
| 666 | (eq (car (cdr cua--last-rectangle)) (point))) | ||
| 667 | (cdr (cdr cua--last-rectangle)) | ||
| 668 | (cua--rectangle-get-corners | ||
| 669 | (and (not buffer-read-only) | ||
| 670 | (or cua-auto-expand-rectangles | ||
| 671 | force | ||
| 672 | (eq major-mode 'picture-mode))))) | ||
| 673 | cua--status-string (if (cua--rectangle-padding) " Pad" "") | ||
| 674 | cua--last-rectangle nil)) | ||
| 675 | |||
| 676 | ;; (defvar cua-save-point nil) | ||
| 677 | |||
| 678 | (defun cua--deactivate-rectangle () | ||
| 679 | ;; This is used to clean up after `cua--activate-rectangle'. | ||
| 680 | (mapcar (function delete-overlay) cua--rectangle-overlays) | ||
| 681 | (setq cua--last-rectangle (cons (current-buffer) | ||
| 682 | (cons (point) ;; cua-save-point | ||
| 683 | cua--rectangle)) | ||
| 684 | cua--rectangle nil | ||
| 685 | cua--rectangle-overlays nil | ||
| 686 | cua--status-string nil | ||
| 687 | cua--mouse-last-pos nil)) | ||
| 688 | |||
| 689 | (defun cua--highlight-rectangle () | ||
| 690 | ;; This function is used to highlight the rectangular region. | ||
| 691 | ;; We do this by putting an overlay on each line within the rectangle. | ||
| 692 | ;; Each overlay extends across all the columns of the rectangle. | ||
| 693 | ;; We try to reuse overlays where possible because this is more efficient | ||
| 694 | ;; and results in less flicker. | ||
| 695 | ;; If cua--rectangle-padding is nil and the buffer contains tabs or short lines, | ||
| 696 | ;; the higlighted region may not be perfectly rectangular. | ||
| 697 | (let ((deactivate-mark deactivate-mark) | ||
| 698 | (old cua--rectangle-overlays) | ||
| 699 | (new nil) | ||
| 700 | (left (cua--rectangle-left)) | ||
| 701 | (right (1+ (cua--rectangle-right)))) | ||
| 702 | (when (/= left right) | ||
| 703 | (sit-for 0) ; make window top/bottom reliable | ||
| 704 | (cua--rectangle-operation nil t nil nil | ||
| 705 | '(lambda (s e l r v) | ||
| 706 | (let ((rface (if v 'cua-rectangle-face 'cua-rectangle-noselect-face)) | ||
| 707 | overlay) | ||
| 708 | ;; Trim old leading overlays. | ||
| 709 | (if (= s e) (setq e (1+ e))) | ||
| 710 | (while (and old | ||
| 711 | (setq overlay (car old)) | ||
| 712 | (< (overlay-start overlay) s) | ||
| 713 | (/= (overlay-end overlay) e)) | ||
| 714 | (delete-overlay overlay) | ||
| 715 | (setq old (cdr old))) | ||
| 716 | ;; Reuse an overlay if possible, otherwise create one. | ||
| 717 | (if (and old | ||
| 718 | (setq overlay (car old)) | ||
| 719 | (or (= (overlay-start overlay) s) | ||
| 720 | (= (overlay-end overlay) e))) | ||
| 721 | (progn | ||
| 722 | (move-overlay overlay s e) | ||
| 723 | (setq old (cdr old))) | ||
| 724 | (setq overlay (make-overlay s e))) | ||
| 725 | (overlay-put overlay 'face rface) | ||
| 726 | (setq new (cons overlay new)))))) | ||
| 727 | ;; Trim old trailing overlays. | ||
| 728 | (mapcar (function delete-overlay) old) | ||
| 729 | (setq cua--rectangle-overlays (nreverse new)))) | ||
| 730 | |||
| 731 | (defun cua--indent-rectangle (&optional ch to-col clear) | ||
| 732 | ;; Indent current rectangle. | ||
| 733 | (let ((col (cua--rectangle-insert-col)) | ||
| 734 | (pad (cua--rectangle-padding)) | ||
| 735 | indent) | ||
| 736 | (cua--rectangle-operation (if clear 'clear 'corners) nil t pad | ||
| 737 | '(lambda (s e l r) | ||
| 738 | (move-to-column col pad) | ||
| 739 | (if (and (eolp) | ||
| 740 | (< (current-column) col)) | ||
| 741 | (move-to-column col t)) | ||
| 742 | (cond | ||
| 743 | (to-col (indent-to to-col)) | ||
| 744 | (ch (insert ch)) | ||
| 745 | (t (tab-to-tab-stop))) | ||
| 746 | (if (cua--rectangle-right-side t) | ||
| 747 | (cua--rectangle-insert-col (current-column)) | ||
| 748 | (setq indent (- (current-column) l)))) | ||
| 749 | '(lambda (l r) | ||
| 750 | (when (and indent (> indent 0)) | ||
| 751 | (aset cua--rectangle 2 (+ l indent)) | ||
| 752 | (aset cua--rectangle 3 (+ r indent -1))))))) | ||
| 753 | |||
| 754 | ;; | ||
| 755 | ;; rectangle functions / actions | ||
| 756 | ;; | ||
| 757 | |||
| 758 | (defvar cua--rectangle-initialized nil) | ||
| 759 | |||
| 760 | (defun cua-set-rectangle-mark (&optional reopen) | ||
| 761 | "Set mark and start in CUA rectangle mode. | ||
| 762 | With prefix argument, activate previous rectangle if possible." | ||
| 763 | (interactive "P") | ||
| 764 | (unless cua--rectangle-initialized | ||
| 765 | (cua--init-rectangles)) | ||
| 766 | (when (not cua--rectangle) | ||
| 767 | (if (and reopen | ||
| 768 | cua--last-rectangle | ||
| 769 | (eq (car cua--last-rectangle) (current-buffer))) | ||
| 770 | (goto-char (car (cdr cua--last-rectangle))) | ||
| 771 | (if (not mark-active) | ||
| 772 | (push-mark nil nil t))) | ||
| 773 | (cua--activate-rectangle) | ||
| 774 | (cua--rectangle-set-corners) | ||
| 775 | (setq mark-active t | ||
| 776 | cua--explicit-region-start t) | ||
| 777 | (if cua-enable-rectangle-auto-help | ||
| 778 | (cua-help-for-rectangle t)))) | ||
| 779 | |||
| 780 | (defun cua-clear-rectangle-mark () | ||
| 781 | "Cancel current rectangle." | ||
| 782 | (interactive) | ||
| 783 | (when cua--rectangle | ||
| 784 | (setq mark-active nil | ||
| 785 | cua--explicit-region-start nil) | ||
| 786 | (cua--deactivate-rectangle))) | ||
| 787 | |||
| 788 | (defun cua-toggle-rectangle-mark () | ||
| 789 | (interactive) | ||
| 790 | (if cua--rectangle | ||
| 791 | (cua--deactivate-rectangle) | ||
| 792 | (unless cua--rectangle-initialized | ||
| 793 | (cua--init-rectangles)) | ||
| 794 | (cua--activate-rectangle)) | ||
| 795 | (if cua--rectangle | ||
| 796 | (if cua-enable-rectangle-auto-help | ||
| 797 | (cua-help-for-rectangle t)) | ||
| 798 | (if cua-enable-region-auto-help | ||
| 799 | (cua-help-for-region t)))) | ||
| 800 | |||
| 801 | (defun cua-restrict-regexp-rectangle (arg) | ||
| 802 | "Restrict rectangle to lines (not) matching REGEXP. | ||
| 803 | With prefix argument, the toggle restriction." | ||
| 804 | (interactive "P") | ||
| 805 | (let ((r (cua--rectangle-restriction)) regexp) | ||
| 806 | (if (and r (null (car (cdr r)))) | ||
| 807 | (if arg | ||
| 808 | (cua--rectangle-restriction (car r) nil (not (car (cdr (cdr r))))) | ||
| 809 | (cua--rectangle-restriction "" nil nil)) | ||
| 810 | (cua--rectangle-restriction | ||
| 811 | (read-from-minibuffer "Restrict rectangle (regexp): " | ||
| 812 | nil nil nil nil) nil arg)))) | ||
| 813 | |||
| 814 | (defun cua-restrict-prefix-rectangle (arg) | ||
| 815 | "Restrict rectangle to lines (not) starting with CHAR. | ||
| 816 | With prefix argument, the toggle restriction." | ||
| 817 | (interactive "P") | ||
| 818 | (let ((r (cua--rectangle-restriction)) regexp) | ||
| 819 | (if (and r (car (cdr r))) | ||
| 820 | (if arg | ||
| 821 | (cua--rectangle-restriction (car r) t (not (car (cdr (cdr r))))) | ||
| 822 | (cua--rectangle-restriction "" nil nil)) | ||
| 823 | (cua--rectangle-restriction | ||
| 824 | (format "[%c]" | ||
| 825 | (read-char "Restrictive rectangle (char): ")) t arg)))) | ||
| 826 | |||
| 827 | (defun cua-move-rectangle-up () | ||
| 828 | (interactive) | ||
| 829 | (cua--rectangle-move 'up)) | ||
| 830 | |||
| 831 | (defun cua-move-rectangle-down () | ||
| 832 | (interactive) | ||
| 833 | (cua--rectangle-move 'down)) | ||
| 834 | |||
| 835 | (defun cua-move-rectangle-left () | ||
| 836 | (interactive) | ||
| 837 | (cua--rectangle-move 'left)) | ||
| 838 | |||
| 839 | (defun cua-move-rectangle-right () | ||
| 840 | (interactive) | ||
| 841 | (cua--rectangle-move 'right)) | ||
| 842 | |||
| 843 | (defun cua-copy-rectangle (arg) | ||
| 844 | (interactive "P") | ||
| 845 | (setq arg (cua--prefix-arg arg)) | ||
| 846 | (cua--copy-rectangle-as-kill arg) | ||
| 847 | (if cua-keep-region-after-copy | ||
| 848 | (cua--keep-active) | ||
| 849 | (cua--deactivate))) | ||
| 850 | |||
| 851 | (defun cua-cut-rectangle (arg) | ||
| 852 | (interactive "P") | ||
| 853 | (if buffer-read-only | ||
| 854 | (cua-copy-rectangle arg) | ||
| 855 | (setq arg (cua--prefix-arg arg)) | ||
| 856 | (goto-char (min (mark) (point))) | ||
| 857 | (cua--copy-rectangle-as-kill arg) | ||
| 858 | (cua--delete-rectangle)) | ||
| 859 | (cua--deactivate)) | ||
| 860 | |||
| 861 | (defun cua-delete-rectangle () | ||
| 862 | (interactive) | ||
| 863 | (goto-char (min (point) (mark))) | ||
| 864 | (if cua-delete-copy-to-register-0 | ||
| 865 | (set-register ?0 (cua--extract-rectangle))) | ||
| 866 | (cua--delete-rectangle) | ||
| 867 | (cua--deactivate)) | ||
| 868 | |||
| 869 | (defun cua-rotate-rectangle () | ||
| 870 | (interactive) | ||
| 871 | (cua--rectangle-corner (if (= (cua--rectangle-left) (cua--rectangle-right)) 0 1)) | ||
| 872 | (cua--rectangle-set-corners)) | ||
| 873 | |||
| 874 | (defun cua-toggle-rectangle-padding () | ||
| 875 | (interactive) | ||
| 876 | (if buffer-read-only | ||
| 877 | (message "Cannot do padding in read-only buffer.") | ||
| 878 | (cua--rectangle-padding t (not (cua--rectangle-padding))) | ||
| 879 | (cua--pad-rectangle) | ||
| 880 | (cua--rectangle-set-corners)) | ||
| 881 | (setq cua--status-string (and (cua--rectangle-padding) " Pad")) | ||
| 882 | (cua--keep-active)) | ||
| 883 | |||
| 884 | (defun cua-do-rectangle-padding () | ||
| 885 | (interactive) | ||
| 886 | (if buffer-read-only | ||
| 887 | (message "Cannot do padding in read-only buffer.") | ||
| 888 | (cua--pad-rectangle t) | ||
| 889 | (cua--rectangle-set-corners)) | ||
| 890 | (cua--keep-active)) | ||
| 891 | |||
| 892 | (defun cua-open-rectangle () | ||
| 893 | "Blank out CUA rectangle, shifting text right. | ||
| 894 | The text previously in the region is not overwritten by the blanks, | ||
| 895 | but instead winds up to the right of the rectangle." | ||
| 896 | (interactive) | ||
| 897 | (cua--rectangle-operation 'corners nil t 1 | ||
| 898 | '(lambda (s e l r) | ||
| 899 | (skip-chars-forward " \t") | ||
| 900 | (let ((ws (- (current-column) l)) | ||
| 901 | (p (point))) | ||
| 902 | (skip-chars-backward " \t") | ||
| 903 | (delete-region (point) p) | ||
| 904 | (indent-to (+ r ws)))))) | ||
| 905 | |||
| 906 | (defun cua-close-rectangle (arg) | ||
| 907 | "Delete all whitespace starting at left edge of CUA rectangle. | ||
| 908 | On each line in the rectangle, all continuous whitespace starting | ||
| 909 | at that column is deleted. | ||
| 910 | With prefix arg, also delete whitespace to the left of that column." | ||
| 911 | (interactive "P") | ||
| 912 | (cua--rectangle-operation 'clear nil t 1 | ||
| 913 | '(lambda (s e l r) | ||
| 914 | (when arg | ||
| 915 | (skip-syntax-backward " " (line-beginning-position)) | ||
| 916 | (setq s (point))) | ||
| 917 | (skip-syntax-forward " " (line-end-position)) | ||
| 918 | (delete-region s (point))))) | ||
| 919 | |||
| 920 | (defun cua-blank-rectangle () | ||
| 921 | "Blank out CUA rectangle. | ||
| 922 | The text previously in the rectangle is overwritten by the blanks." | ||
| 923 | (interactive) | ||
| 924 | (cua--rectangle-operation 'keep nil nil 1 | ||
| 925 | '(lambda (s e l r) | ||
| 926 | (goto-char e) | ||
| 927 | (skip-syntax-forward " " (line-end-position)) | ||
| 928 | (setq e (point)) | ||
| 929 | (let ((column (current-column))) | ||
| 930 | (goto-char s) | ||
| 931 | (skip-syntax-backward " " (line-beginning-position)) | ||
| 932 | (delete-region (point) e) | ||
| 933 | (indent-to column))))) | ||
| 934 | |||
| 935 | (defun cua-align-rectangle () | ||
| 936 | "Align rectangle lines to left column." | ||
| 937 | (interactive) | ||
| 938 | (let (x) | ||
| 939 | (cua--rectangle-operation 'clear nil t t | ||
| 940 | '(lambda (s e l r) | ||
| 941 | (let ((b (line-beginning-position))) | ||
| 942 | (skip-syntax-backward "^ " b) | ||
| 943 | (skip-syntax-backward " " b) | ||
| 944 | (setq s (point))) | ||
| 945 | (skip-syntax-forward " " (line-end-position)) | ||
| 946 | (delete-region s (point)) | ||
| 947 | (indent-to l)) | ||
| 948 | '(lambda (l r) | ||
| 949 | (move-to-column l) | ||
| 950 | ;; (setq cua-save-point (point)) | ||
| 951 | )))) | ||
| 952 | |||
| 953 | (defun cua-copy-rectangle-as-text (&optional arg delete) | ||
| 954 | "Copy rectangle, but store as normal text." | ||
| 955 | (interactive "P") | ||
| 956 | (if cua--global-mark-active | ||
| 957 | (if delete | ||
| 958 | (cua--cut-rectangle-to-global-mark t) | ||
| 959 | (cua--copy-rectangle-to-global-mark t)) | ||
| 960 | (let* ((rect (cua--extract-rectangle)) | ||
| 961 | (text (mapconcat | ||
| 962 | (function (lambda (row) (concat row "\n"))) | ||
| 963 | rect ""))) | ||
| 964 | (setq arg (cua--prefix-arg arg)) | ||
| 965 | (if cua--register | ||
| 966 | (set-register cua--register text) | ||
| 967 | (kill-new text))) | ||
| 968 | (if delete | ||
| 969 | (cua--delete-rectangle)) | ||
| 970 | (cua--deactivate))) | ||
| 971 | |||
| 972 | (defun cua-cut-rectangle-as-text (arg) | ||
| 973 | "Kill rectangle, but store as normal text." | ||
| 974 | (interactive "P") | ||
| 975 | (cua-copy-rectangle-as-text arg (not buffer-read-only))) | ||
| 976 | |||
| 977 | (defun cua-string-rectangle (string) | ||
| 978 | "Replace CUA rectangle contents with STRING on each line. | ||
| 979 | The length of STRING need not be the same as the rectangle width." | ||
| 980 | (interactive "sString rectangle: ") | ||
| 981 | (cua--rectangle-operation 'keep nil t t | ||
| 982 | '(lambda (s e l r) | ||
| 983 | (delete-region s e) | ||
| 984 | (skip-chars-forward " \t") | ||
| 985 | (let ((ws (- (current-column) l))) | ||
| 986 | (delete-region s (point)) | ||
| 987 | (insert string) | ||
| 988 | (indent-to (+ (current-column) ws)))) | ||
| 989 | (unless (cua--rectangle-restriction) | ||
| 990 | '(lambda (l r) | ||
| 991 | (cua--rectangle-right (max l (+ l (length string) -1))))))) | ||
| 992 | |||
| 993 | (defun cua-fill-char-rectangle (ch) | ||
| 994 | "Replace CUA rectangle contents with CHARACTER." | ||
| 995 | (interactive "cFill rectangle with character: ") | ||
| 996 | (cua--rectangle-operation 'clear nil t 1 | ||
| 997 | '(lambda (s e l r) | ||
| 998 | (delete-region s e) | ||
| 999 | (move-to-column l t) | ||
| 1000 | (insert-char ch (- r l))))) | ||
| 1001 | |||
| 1002 | (defun cua-replace-in-rectangle (regexp newtext) | ||
| 1003 | "Replace REGEXP with NEWTEXT in each line of CUA rectangle." | ||
| 1004 | (interactive "sReplace regexp: \nsNew text: ") | ||
| 1005 | (if buffer-read-only | ||
| 1006 | (message "Cannot replace in read-only buffer") | ||
| 1007 | (cua--rectangle-operation 'keep nil t 1 | ||
| 1008 | '(lambda (s e l r) | ||
| 1009 | (if (re-search-forward regexp e t) | ||
| 1010 | (replace-match newtext nil nil)))))) | ||
| 1011 | |||
| 1012 | (defun cua-incr-rectangle (increment) | ||
| 1013 | "Increment each line of CUA rectangle by prefix amount." | ||
| 1014 | (interactive "p") | ||
| 1015 | (cua--rectangle-operation 'keep nil t 1 | ||
| 1016 | '(lambda (s e l r) | ||
| 1017 | (cond | ||
| 1018 | ((re-search-forward "0x\\([0-9a-fA-F]+\\)" e t) | ||
| 1019 | (let* ((txt (buffer-substring-no-properties (match-beginning 1) (match-end 1))) | ||
| 1020 | (n (string-to-number txt 16)) | ||
| 1021 | (fmt (format "0x%%0%dx" (length txt)))) | ||
| 1022 | (replace-match (format fmt (+ n increment))))) | ||
| 1023 | ((re-search-forward "\\( *-?[0-9]+\\)" e t) | ||
| 1024 | (let* ((txt (buffer-substring-no-properties (match-beginning 1) (match-end 1))) | ||
| 1025 | (prefix (if (= (aref txt 0) ?0) "0" "")) | ||
| 1026 | (n (string-to-number txt 10)) | ||
| 1027 | (fmt (format "%%%s%dd" prefix (length txt)))) | ||
| 1028 | (replace-match (format fmt (+ n increment))))) | ||
| 1029 | (t nil))))) | ||
| 1030 | |||
| 1031 | (defvar cua--rectangle-seq-format "%d" | ||
| 1032 | "Last format used by cua-sequence-rectangle.") | ||
| 1033 | |||
| 1034 | (defun cua-sequence-rectangle (first incr fmt) | ||
| 1035 | "Resequence each line of CUA rectangle starting from FIRST. | ||
| 1036 | The numbers are formatted according to the FORMAT string." | ||
| 1037 | (interactive | ||
| 1038 | (list (if current-prefix-arg | ||
| 1039 | (prefix-numeric-value current-prefix-arg) | ||
| 1040 | (string-to-number | ||
| 1041 | (read-string "Start value: (0) " nil nil "0"))) | ||
| 1042 | (string-to-number | ||
| 1043 | (read-string "Increment: (1) " nil nil "1")) | ||
| 1044 | (read-string (concat "Format: (" cua--rectangle-seq-format ") ")))) | ||
| 1045 | (if (= (length fmt) 0) | ||
| 1046 | (setq fmt cua--rectangle-seq-format) | ||
| 1047 | (setq cua--rectangle-seq-format fmt)) | ||
| 1048 | (cua--rectangle-operation 'clear nil t 1 | ||
| 1049 | '(lambda (s e l r) | ||
| 1050 | (delete-region s e) | ||
| 1051 | (insert (format fmt first)) | ||
| 1052 | (setq first (+ first incr))))) | ||
| 1053 | |||
| 1054 | (defun cua-upcase-rectangle () | ||
| 1055 | "Convert the rectangle to upper case." | ||
| 1056 | (interactive) | ||
| 1057 | (cua--rectangle-operation 'clear nil nil nil | ||
| 1058 | '(lambda (s e l r) | ||
| 1059 | (upcase-region s e)))) | ||
| 1060 | |||
| 1061 | (defun cua-downcase-rectangle () | ||
| 1062 | "Convert the rectangle to lower case." | ||
| 1063 | (interactive) | ||
| 1064 | (cua--rectangle-operation 'clear nil nil nil | ||
| 1065 | '(lambda (s e l r) | ||
| 1066 | (downcase-region s e)))) | ||
| 1067 | |||
| 1068 | |||
| 1069 | ;;; Replace/rearrange text in current rectangle | ||
| 1070 | |||
| 1071 | (defun cua--rectangle-aux-replace (width adjust keep replace pad format-fct &optional setup-fct) | ||
| 1072 | ;; Process text inserted by calling SETUP-FCT or current rectangle if nil. | ||
| 1073 | ;; Then call FORMAT-FCT on text (if non-nil); takes two args: start and end. | ||
| 1074 | ;; Fill to WIDTH characters if > 0 or fill to current width if == 0. | ||
| 1075 | ;; Don't fill if WIDTH < 0. | ||
| 1076 | ;; Replace current rectangle by filled text if REPLACE is non-nil | ||
| 1077 | (let ((auxbuf (get-buffer-create "*CUA temp*")) | ||
| 1078 | (w (if (> width 1) width | ||
| 1079 | (- (cua--rectangle-right) (cua--rectangle-left) -1))) | ||
| 1080 | (r (or setup-fct (cua--extract-rectangle))) | ||
| 1081 | y z (tr 0)) | ||
| 1082 | (save-excursion | ||
| 1083 | (set-buffer auxbuf) | ||
| 1084 | (erase-buffer) | ||
| 1085 | (if setup-fct | ||
| 1086 | (funcall setup-fct) | ||
| 1087 | (cua--insert-rectangle r)) | ||
| 1088 | (if format-fct | ||
| 1089 | (let ((fill-column w)) | ||
| 1090 | (funcall format-fct (point-min) (point-max)))) | ||
| 1091 | (when replace | ||
| 1092 | (goto-char (point-min)) | ||
| 1093 | (while (not (eobp)) | ||
| 1094 | (setq z (cons (buffer-substring (point) (line-end-position)) z)) | ||
| 1095 | (forward-line 1)))) | ||
| 1096 | (if (not cua--debug) | ||
| 1097 | (kill-buffer auxbuf)) | ||
| 1098 | (when replace | ||
| 1099 | (setq z (reverse z)) | ||
| 1100 | (if cua--debug | ||
| 1101 | (print z auxbuf)) | ||
| 1102 | (cua--rectangle-operation nil nil t pad | ||
| 1103 | '(lambda (s e l r) | ||
| 1104 | (let (cc) | ||
| 1105 | (goto-char e) | ||
| 1106 | (skip-chars-forward " \t") | ||
| 1107 | (setq cc (current-column)) | ||
| 1108 | (if cua--debug | ||
| 1109 | (print (list cc s e) auxbuf)) | ||
| 1110 | (delete-region s (point)) | ||
| 1111 | (if (not z) | ||
| 1112 | (setq y 0) | ||
| 1113 | (move-to-column l t) | ||
| 1114 | (insert (car z)) | ||
| 1115 | (when (> (current-column) (+ l w)) | ||
| 1116 | (setq y (point)) | ||
| 1117 | (move-to-column (+ l w) t) | ||
| 1118 | (delete-region (point) y) | ||
| 1119 | (setq tr (1+ tr))) | ||
| 1120 | (setq z (cdr z))) | ||
| 1121 | (if cua--debug | ||
| 1122 | (print (list (current-column) cc) auxbuf)) | ||
| 1123 | (indent-to cc)))) | ||
| 1124 | (if (> tr 0) | ||
| 1125 | (message "Warning: Truncated %d row%s" tr (if (> tr 1) "s" ""))) | ||
| 1126 | (if adjust | ||
| 1127 | (cua--rectangle-right (+ (cua--rectangle-left) w -1))) | ||
| 1128 | (if keep | ||
| 1129 | (cua--rectangle-resized))))) | ||
| 1130 | |||
| 1131 | (put 'cua--rectangle-aux-replace 'lisp-indent-function 4) | ||
| 1132 | |||
| 1133 | (defun cua--left-fill-rectangle (start end) | ||
| 1134 | (beginning-of-line) | ||
| 1135 | (while (< (point) (point-max)) | ||
| 1136 | (delete-horizontal-space nil) | ||
| 1137 | (forward-line 1)) | ||
| 1138 | (fill-region-as-paragraph (point-min) (point-max) 'left nil) | ||
| 1139 | (untabify (point-min) (point-max))) | ||
| 1140 | |||
| 1141 | (defun cua-text-fill-rectangle (width text) | ||
| 1142 | "Replace rectagle with filled TEXT read from minibuffer. | ||
| 1143 | A numeric prefix argument is used a new width for the filled rectangle." | ||
| 1144 | (interactive (list | ||
| 1145 | (prefix-numeric-value current-prefix-arg) | ||
| 1146 | (read-from-minibuffer "Enter text: " | ||
| 1147 | nil nil nil nil))) | ||
| 1148 | (cua--rectangle-aux-replace width t t t 1 | ||
| 1149 | 'cua--left-fill-rectangle | ||
| 1150 | '(lambda () (insert text)))) | ||
| 1151 | |||
| 1152 | (defun cua-refill-rectangle (width) | ||
| 1153 | "Fill contents of current rectagle. | ||
| 1154 | A numeric prefix argument is used as new width for the filled rectangle." | ||
| 1155 | (interactive "P") | ||
| 1156 | (cua--rectangle-aux-replace | ||
| 1157 | (if width (prefix-numeric-value width) 0) | ||
| 1158 | t t t 1 'cua--left-fill-rectangle)) | ||
| 1159 | |||
| 1160 | (defun cua-shell-command-on-rectangle (replace command) | ||
| 1161 | "Run shell command on rectangle like `shell-command-on-region'. | ||
| 1162 | With prefix arg, replace rectangle with output from command." | ||
| 1163 | (interactive (list | ||
| 1164 | current-prefix-arg | ||
| 1165 | (read-from-minibuffer "Shell command on rectangle: " | ||
| 1166 | nil nil nil | ||
| 1167 | 'shell-command-history))) | ||
| 1168 | (cua--rectangle-aux-replace -1 t t replace 1 | ||
| 1169 | '(lambda (s e) | ||
| 1170 | (shell-command-on-region s e command | ||
| 1171 | replace replace nil)))) | ||
| 1172 | |||
| 1173 | (defun cua-reverse-rectangle () | ||
| 1174 | "Reverse the lines of the rectangle." | ||
| 1175 | (interactive) | ||
| 1176 | (cua--rectangle-aux-replace 0 t t t t 'reverse-region)) | ||
| 1177 | |||
| 1178 | (defun cua-scroll-rectangle-up () | ||
| 1179 | "Remove the first line of the rectangle and scroll remaining lines up." | ||
| 1180 | (interactive) | ||
| 1181 | (cua--rectangle-aux-replace 0 t t t t | ||
| 1182 | '(lambda (s e) | ||
| 1183 | (if (= (forward-line 1) 0) | ||
| 1184 | (delete-region s (point)))))) | ||
| 1185 | |||
| 1186 | (defun cua-scroll-rectangle-down () | ||
| 1187 | "Insert a blank line at the first line of the rectangle. | ||
| 1188 | The remaining lines are scrolled down, losing the last line." | ||
| 1189 | (interactive) | ||
| 1190 | (cua--rectangle-aux-replace 0 t t t t | ||
| 1191 | '(lambda (s e) | ||
| 1192 | (goto-char s) | ||
| 1193 | (insert "\n")))) | ||
| 1194 | |||
| 1195 | |||
| 1196 | ;;; Insert/delete text to left or right of rectangle | ||
| 1197 | |||
| 1198 | (defun cua-insert-char-rectangle (&optional ch) | ||
| 1199 | (interactive) | ||
| 1200 | (if buffer-read-only | ||
| 1201 | (ding) | ||
| 1202 | (cua--indent-rectangle (or ch (aref (this-single-command-keys) 0))) | ||
| 1203 | (cua--keep-active)) | ||
| 1204 | t) | ||
| 1205 | |||
| 1206 | (defun cua-indent-rectangle (column) | ||
| 1207 | "Indent rectangle to next tab stop. | ||
| 1208 | With prefix arg, indent to that column." | ||
| 1209 | (interactive "P") | ||
| 1210 | (if (null column) | ||
| 1211 | (cua-insert-char-rectangle ?\t) | ||
| 1212 | (cua--indent-rectangle nil (prefix-numeric-value column)))) | ||
| 1213 | |||
| 1214 | (defun cua-delete-char-rectangle () | ||
| 1215 | "Delete char to left or right of rectangle." | ||
| 1216 | (interactive) | ||
| 1217 | (let ((col (cua--rectangle-insert-col)) | ||
| 1218 | (pad (cua--rectangle-padding)) | ||
| 1219 | indent) | ||
| 1220 | (cua--rectangle-operation 'corners nil t pad | ||
| 1221 | '(lambda (s e l r) | ||
| 1222 | (move-to-column | ||
| 1223 | (if (cua--rectangle-right-side t) | ||
| 1224 | (max (1+ r) col) l) | ||
| 1225 | pad) | ||
| 1226 | (if (bolp) | ||
| 1227 | nil | ||
| 1228 | (delete-backward-char 1) | ||
| 1229 | (if (cua--rectangle-right-side t) | ||
| 1230 | (cua--rectangle-insert-col (current-column)) | ||
| 1231 | (setq indent (- l (current-column)))))) | ||
| 1232 | '(lambda (l r) | ||
| 1233 | (when (and indent (> indent 0)) | ||
| 1234 | (aset cua--rectangle 2 (- l indent)) | ||
| 1235 | (aset cua--rectangle 3 (- r indent 1))))))) | ||
| 1236 | |||
| 1237 | (defun cua-help-for-rectangle (&optional help) | ||
| 1238 | (interactive) | ||
| 1239 | (let ((M (if cua-use-hyper-key " H-" " M-"))) | ||
| 1240 | (message | ||
| 1241 | (concat (if help "C-?:help" "") | ||
| 1242 | M "p:pad" M "o:open" M "c:close" M "b:blank" | ||
| 1243 | M "s:string" M "f:fill" M "i:incr" M "n:seq")))) | ||
| 1244 | |||
| 1245 | |||
| 1246 | ;;; CUA-like cut & paste for rectangles | ||
| 1247 | |||
| 1248 | (defun cua--cancel-rectangle () | ||
| 1249 | ;; Cancel rectangle | ||
| 1250 | (if cua--rectangle | ||
| 1251 | (cua--deactivate-rectangle)) | ||
| 1252 | (setq cua--last-rectangle nil)) | ||
| 1253 | |||
| 1254 | (defun cua--rectangle-post-command () | ||
| 1255 | (if cua--restored-rectangle | ||
| 1256 | (setq cua--rectangle cua--restored-rectangle | ||
| 1257 | cua--restored-rectangle nil | ||
| 1258 | mark-active t | ||
| 1259 | deactivate-mark nil) | ||
| 1260 | (when (and cua--rectangle cua--buffer-and-point-before-command | ||
| 1261 | (equal (car cua--buffer-and-point-before-command) (current-buffer)) | ||
| 1262 | (not (= (cdr cua--buffer-and-point-before-command) (point)))) | ||
| 1263 | (if (cua--rectangle-right-side) | ||
| 1264 | (cua--rectangle-right (current-column)) | ||
| 1265 | (cua--rectangle-left (current-column))) | ||
| 1266 | (if (>= (cua--rectangle-corner) 2) | ||
| 1267 | (cua--rectangle-bot t) | ||
| 1268 | (cua--rectangle-top t)) | ||
| 1269 | (if (cua--rectangle-padding) | ||
| 1270 | (setq unread-command-events | ||
| 1271 | (cons (if cua-use-hyper-key ?\H-P ?\M-P) unread-command-events))))) | ||
| 1272 | (if cua--rectangle | ||
| 1273 | (if (and mark-active | ||
| 1274 | (not deactivate-mark)) | ||
| 1275 | (cua--highlight-rectangle) | ||
| 1276 | (cua--deactivate-rectangle)))) | ||
| 1277 | |||
| 1278 | |||
| 1279 | ;;; Initialization | ||
| 1280 | |||
| 1281 | (defun cua--rect-M/H-key (key cmd) | ||
| 1282 | (cua--M/H-key cua--rectangle-keymap key cmd)) | ||
| 1283 | |||
| 1284 | (defun cua--rectangle-on-off (on) | ||
| 1285 | (cancel-function-timers 'cua--tidy-undo-lists) | ||
| 1286 | (if on | ||
| 1287 | (run-with-idle-timer 10 t 'cua--tidy-undo-lists) | ||
| 1288 | (cua--tidy-undo-lists t))) | ||
| 1289 | |||
| 1290 | (defun cua--init-rectangles () | ||
| 1291 | (unless (face-background 'cua-rectangle-face) | ||
| 1292 | (copy-face 'region 'cua-rectangle-face) | ||
| 1293 | (set-face-background 'cua-rectangle-face "maroon") | ||
| 1294 | (set-face-foreground 'cua-rectangle-face "white")) | ||
| 1295 | |||
| 1296 | (unless (face-background 'cua-rectangle-noselect-face) | ||
| 1297 | (copy-face 'region 'cua-rectangle-noselect-face) | ||
| 1298 | (set-face-background 'cua-rectangle-noselect-face "dimgray") | ||
| 1299 | (set-face-foreground 'cua-rectangle-noselect-face "white")) | ||
| 1300 | |||
| 1301 | (unless (eq cua-use-hyper-key 'only) | ||
| 1302 | (define-key cua--rectangle-keymap [(shift return)] 'cua-clear-rectangle-mark) | ||
| 1303 | (define-key cua--region-keymap [(shift return)] 'cua-toggle-rectangle-mark)) | ||
| 1304 | (when cua-use-hyper-key | ||
| 1305 | (cua--rect-M/H-key 'space 'cua-clear-rectangle-mark) | ||
| 1306 | (cua--M/H-key cua--region-keymap 'space 'cua-toggle-rectangle-mark)) | ||
| 1307 | |||
| 1308 | (define-key cua--rectangle-keymap [remap copy-region-as-kill] 'cua-copy-rectangle) | ||
| 1309 | (define-key cua--rectangle-keymap [remap kill-ring-save] 'cua-copy-rectangle) | ||
| 1310 | (define-key cua--rectangle-keymap [remap kill-region] 'cua-cut-rectangle) | ||
| 1311 | (define-key cua--rectangle-keymap [remap delete-char] 'cua-delete-rectangle) | ||
| 1312 | (define-key cua--rectangle-keymap [remap set-mark-command] 'cua-toggle-rectangle-mark) | ||
| 1313 | |||
| 1314 | (define-key cua--rectangle-keymap [remap forward-char] 'cua-resize-rectangle-right) | ||
| 1315 | (define-key cua--rectangle-keymap [remap backward-char] 'cua-resize-rectangle-left) | ||
| 1316 | (define-key cua--rectangle-keymap [remap next-line] 'cua-resize-rectangle-down) | ||
| 1317 | (define-key cua--rectangle-keymap [remap previous-line] 'cua-resize-rectangle-up) | ||
| 1318 | (define-key cua--rectangle-keymap [remap end-of-line] 'cua-resize-rectangle-eol) | ||
| 1319 | (define-key cua--rectangle-keymap [remap beginning-of-line] 'cua-resize-rectangle-bol) | ||
| 1320 | (define-key cua--rectangle-keymap [remap end-of-buffer] 'cua-resize-rectangle-bot) | ||
| 1321 | (define-key cua--rectangle-keymap [remap beginning-of-buffer] 'cua-resize-rectangle-top) | ||
| 1322 | (define-key cua--rectangle-keymap [remap scroll-down] 'cua-resize-rectangle-page-up) | ||
| 1323 | (define-key cua--rectangle-keymap [remap scroll-up] 'cua-resize-rectangle-page-down) | ||
| 1324 | |||
| 1325 | (define-key cua--rectangle-keymap [remap delete-backward-char] 'cua-delete-char-rectangle) | ||
| 1326 | (define-key cua--rectangle-keymap [remap backward-delete-char] 'cua-delete-char-rectangle) | ||
| 1327 | (define-key cua--rectangle-keymap [remap backward-delete-char-untabify] 'cua-delete-char-rectangle) | ||
| 1328 | (define-key cua--rectangle-keymap [remap self-insert-command] 'cua-insert-char-rectangle) | ||
| 1329 | (define-key cua--rectangle-keymap [remap self-insert-iso] 'cua-insert-char-rectangle) | ||
| 1330 | |||
| 1331 | (define-key cua--rectangle-keymap "\r" 'cua-rotate-rectangle) | ||
| 1332 | (define-key cua--rectangle-keymap "\t" 'cua-indent-rectangle) | ||
| 1333 | |||
| 1334 | (define-key cua--rectangle-keymap [(control ??)] 'cua-help-for-rectangle) | ||
| 1335 | |||
| 1336 | (define-key cua--rectangle-keymap [mouse-1] 'cua-mouse-set-rectangle-mark) | ||
| 1337 | (define-key cua--rectangle-keymap [down-mouse-1] 'cua--mouse-ignore) | ||
| 1338 | (define-key cua--rectangle-keymap [drag-mouse-1] 'cua--mouse-ignore) | ||
| 1339 | (define-key cua--rectangle-keymap [mouse-3] 'cua-mouse-save-then-kill-rectangle) | ||
| 1340 | (define-key cua--rectangle-keymap [down-mouse-3] 'cua--mouse-ignore) | ||
| 1341 | (define-key cua--rectangle-keymap [drag-mouse-3] 'cua--mouse-ignore) | ||
| 1342 | |||
| 1343 | (cua--rect-M/H-key 'up 'cua-move-rectangle-up) | ||
| 1344 | (cua--rect-M/H-key 'down 'cua-move-rectangle-down) | ||
| 1345 | (cua--rect-M/H-key 'left 'cua-move-rectangle-left) | ||
| 1346 | (cua--rect-M/H-key 'right 'cua-move-rectangle-right) | ||
| 1347 | |||
| 1348 | (cua--rect-M/H-key '(control up) 'cua-scroll-rectangle-up) | ||
| 1349 | (cua--rect-M/H-key '(control down) 'cua-scroll-rectangle-down) | ||
| 1350 | |||
| 1351 | (cua--rect-M/H-key ?a 'cua-align-rectangle) | ||
| 1352 | (cua--rect-M/H-key ?b 'cua-blank-rectangle) | ||
| 1353 | (cua--rect-M/H-key ?c 'cua-close-rectangle) | ||
| 1354 | (cua--rect-M/H-key ?f 'cua-fill-char-rectangle) | ||
| 1355 | (cua--rect-M/H-key ?i 'cua-incr-rectangle) | ||
| 1356 | (cua--rect-M/H-key ?k 'cua-cut-rectangle-as-text) | ||
| 1357 | (cua--rect-M/H-key ?l 'cua-downcase-rectangle) | ||
| 1358 | (cua--rect-M/H-key ?m 'cua-copy-rectangle-as-text) | ||
| 1359 | (cua--rect-M/H-key ?n 'cua-sequence-rectangle) | ||
| 1360 | (cua--rect-M/H-key ?o 'cua-open-rectangle) | ||
| 1361 | (cua--rect-M/H-key ?p 'cua-toggle-rectangle-padding) | ||
| 1362 | (cua--rect-M/H-key ?P 'cua-do-rectangle-padding) | ||
| 1363 | (cua--rect-M/H-key ?q 'cua-refill-rectangle) | ||
| 1364 | (cua--rect-M/H-key ?r 'cua-replace-in-rectangle) | ||
| 1365 | (cua--rect-M/H-key ?R 'cua-reverse-rectangle) | ||
| 1366 | (cua--rect-M/H-key ?s 'cua-string-rectangle) | ||
| 1367 | (cua--rect-M/H-key ?t 'cua-text-fill-rectangle) | ||
| 1368 | (cua--rect-M/H-key ?u 'cua-upcase-rectangle) | ||
| 1369 | (cua--rect-M/H-key ?| 'cua-shell-command-on-rectangle) | ||
| 1370 | (cua--rect-M/H-key ?' 'cua-restrict-prefix-rectangle) | ||
| 1371 | (cua--rect-M/H-key ?/ 'cua-restrict-regexp-rectangle) | ||
| 1372 | |||
| 1373 | (setq cua--rectangle-initialized t)) | ||
| 1374 | |||
| 1375 | ;;; cua-rect.el ends here | ||
diff --git a/lisp/emulation/keypad.el b/lisp/emulation/keypad.el new file mode 100644 index 00000000000..abbf511c95f --- /dev/null +++ b/lisp/emulation/keypad.el | |||
| @@ -0,0 +1,185 @@ | |||
| 1 | ;;; keypad.el --- simplified keypad bindings | ||
| 2 | |||
| 3 | ;; Copyright (C) 2002 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | ;; Author: Kim F. Storm <storm@cua.dk> | ||
| 6 | ;; Keywords: keyboard convenience | ||
| 7 | |||
| 8 | ;; This file is part of GNU Emacs. | ||
| 9 | |||
| 10 | ;; GNU Emacs is free software; you can redistribute it and/or modify | ||
| 11 | ;; it under the terms of the GNU General Public License as published by | ||
| 12 | ;; the Free Software Foundation; either version 2, or (at your option) | ||
| 13 | ;; any later version. | ||
| 14 | |||
| 15 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 18 | ;; GNU General Public License for more details. | ||
| 19 | |||
| 20 | ;; You should have received a copy of the GNU General Public License | ||
| 21 | ;; along with GNU Emacs; see the file COPYING. If not, write to the | ||
| 22 | ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
| 23 | ;; Boston, MA 02111-1307, USA. | ||
| 24 | |||
| 25 | ;;; Commentary: | ||
| 26 | |||
| 27 | ;; The keypad package allows easy binding of the keypad keys to | ||
| 28 | ;; various commonly used sets of commands. | ||
| 29 | ;; | ||
| 30 | ;; With the following setup, the keypad can be used for numeric data | ||
| 31 | ;; entry, or to give numeric prefix arguments to emacs commands. | ||
| 32 | ;; | ||
| 33 | ;; (keypad-setup 'numeric) | ||
| 34 | ;; (keypad-setup 'prefix t) | ||
| 35 | ;; | ||
| 36 | ;; +--------+--------+--------+ | ||
| 37 | ;; | M-7 | M-8 | M-9 | | ||
| 38 | ;; | 7 | 8 | 9 | | ||
| 39 | ;; +--------+--------+--------+ | ||
| 40 | ;; | M-4 | M-5 | M-6 | | ||
| 41 | ;; | 4 | 5 | 6 | | ||
| 42 | ;; +--------+--------+--------+ | ||
| 43 | ;; | M-1 | M-2 | M-3 | | ||
| 44 | ;; | 1 | 2 | 3 | | ||
| 45 | ;; +--------+--------+--------+ | ||
| 46 | ;; | M-0 | M-- | | ||
| 47 | ;; | 0 | . | | ||
| 48 | ;; +-----------------+--------+ | ||
| 49 | |||
| 50 | ;; The following keypad setup is used for navigation: | ||
| 51 | ;; | ||
| 52 | ;; (keypad-setup 'cursor) | ||
| 53 | ;; (keypad-setup 'S-cursor t) | ||
| 54 | ;; | ||
| 55 | ;; +--------+--------+--------+ | ||
| 56 | ;; | S-home | S-up | S-PgUp | | ||
| 57 | ;; | Home | up | PgUp | | ||
| 58 | ;; +--------+--------+--------+ | ||
| 59 | ;; | S-left |S-space |S-right | | ||
| 60 | ;; | left | space | right | | ||
| 61 | ;; +--------+--------+--------+ | ||
| 62 | ;; | S-end | S-down | S-PgDn | | ||
| 63 | ;; | end | down | PgDn | | ||
| 64 | ;; +--------+--------+--------+ | ||
| 65 | ;; | S-insert |S-delete| | ||
| 66 | ;; | insert | delete | | ||
| 67 | ;; +-----------------+--------+ | ||
| 68 | |||
| 69 | |||
| 70 | ;;; Code: | ||
| 71 | |||
| 72 | (provide 'keypad) | ||
| 73 | |||
| 74 | ;;; Customization | ||
| 75 | |||
| 76 | ;;;###autoload | ||
| 77 | (defcustom keypad-setup nil | ||
| 78 | "Specifies the keypad setup for unshifted keypad keys. | ||
| 79 | The options are: | ||
| 80 | 'prefix Numeric prefix argument, i.e. M-0 .. M-9 and M-- | ||
| 81 | 'cursor Cursor movement keys. | ||
| 82 | 'S-cursor Shifted cursor movement keys. | ||
| 83 | 'numeric Plain numeric, i.e. 0 .. 9 and . (or DECIMAL arg) | ||
| 84 | 'none Removes all bindings for keypad keys in function-key-map. | ||
| 85 | nil Keep existing bindings for the keypad keys." | ||
| 86 | :set (lambda (symbol value) | ||
| 87 | (if value | ||
| 88 | (keypad-setup value nil keypad-decimal-key))) | ||
| 89 | :initialize 'custom-initialize-default | ||
| 90 | :set-after '(keypad-decimal-key) | ||
| 91 | :require 'keypad | ||
| 92 | :link '(emacs-commentary-link "keypad.el") | ||
| 93 | :version "21.4" | ||
| 94 | :type '(choice (const :tag "Numeric prefix arguments" prefix) | ||
| 95 | (const :tag "Cursor keys" cursor) | ||
| 96 | (const :tag "Shifted cursor keys" S-cursor) | ||
| 97 | (const :tag "Plain Numeric Keypad" numeric) | ||
| 98 | (const :tag "Remove bindings" none) | ||
| 99 | (other :tag "Keep existing bindings" :value nil)) | ||
| 100 | :group 'keyboard) | ||
| 101 | |||
| 102 | (defcustom keypad-decimal-key ?. | ||
| 103 | "Character produced by the unshifted decimal key on the keypad." | ||
| 104 | :type 'character | ||
| 105 | :group 'keyboard) | ||
| 106 | |||
| 107 | ;;;###autoload | ||
| 108 | (defcustom keypad-shifted-setup nil | ||
| 109 | "Specifies the keypad setup for shifted keypad keys. | ||
| 110 | See `keypad-setup' for available options." | ||
| 111 | :set (lambda (symbol value) | ||
| 112 | (if value | ||
| 113 | (keypad-setup value t keypad-shifted-decimal-key))) | ||
| 114 | :initialize 'custom-initialize-default | ||
| 115 | :set-after '(keypad-shifted-decimal-key) | ||
| 116 | :require 'keypad | ||
| 117 | :link '(emacs-commentary-link "keypad.el") | ||
| 118 | :version "21.4" | ||
| 119 | :type '(choice (const :tag "Numeric prefix arguments" prefix) | ||
| 120 | (const :tag "Cursor keys" cursor) | ||
| 121 | (const :tag "Shifted cursor keys" S-cursor) | ||
| 122 | (const :tag "Plain Numeric Keypad" numeric) | ||
| 123 | (const :tag "Remove bindings" none) | ||
| 124 | (other :tag "Keep existing bindings" :value nil)) | ||
| 125 | :group 'keyboard) | ||
| 126 | |||
| 127 | (defcustom keypad-shifted-decimal-key ?. | ||
| 128 | "Character produced by the unshifted decimal key on the keypad." | ||
| 129 | :type 'character | ||
| 130 | :group 'keyboard) | ||
| 131 | |||
| 132 | ;;;###autoload | ||
| 133 | (defun keypad-setup (setup &optional numlock decimal) | ||
| 134 | "Set keypad bindings in function-key-map according to SETUP. | ||
| 135 | If optional second argument NUMLOCK is non-nil, the NumLock On bindings | ||
| 136 | are changed. Otherwise, the NumLock Off bindings are changed. | ||
| 137 | |||
| 138 | Setup Binding | ||
| 139 | ------------------------------------------------------------- | ||
| 140 | 'prefix Command prefix argument, i.e. M-0 .. M-9 and M-- | ||
| 141 | 'S-cursor Bind shifted keypad keys to the shifted cursor movement keys. | ||
| 142 | 'cursor Bind keypad keys to the cursor movement keys. | ||
| 143 | 'numeric Plain numeric, i.e. 0 .. 9 and . (or DECIMAL arg) | ||
| 144 | 'none Removes all bindings for keypad keys in function-key-map. | ||
| 145 | |||
| 146 | If SETUP is 'numeric and the optional third argument DECIMAL is non-nil, | ||
| 147 | the decimal key on the keypad is mapped to DECIMAL instead of `.'" | ||
| 148 | (let ((i 0) | ||
| 149 | (kp | ||
| 150 | (cond | ||
| 151 | (numlock | ||
| 152 | [kp-decimal kp-0 kp-1 kp-2 kp-3 kp-4 | ||
| 153 | kp-5 kp-6 kp-7 kp-8 kp-9]) | ||
| 154 | (t | ||
| 155 | [kp-delete kp-insert kp-end kp-down kp-next kp-left | ||
| 156 | kp-space kp-right kp-home kp-up kp-prior]))) | ||
| 157 | (bind | ||
| 158 | (cond | ||
| 159 | ((eq setup 'numeric) | ||
| 160 | (vector (or decimal ?.) ?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9)) | ||
| 161 | ((eq setup 'prefix) | ||
| 162 | [?\M-- ?\M-0 ?\M-1 ?\M-2 ?\M-3 ?\M-4 | ||
| 163 | ?\M-5 ?\M-6 ?\M-7 ?\M-8 ?\M-9]) | ||
| 164 | ((eq setup 'cursor) | ||
| 165 | [delete insert end down next left | ||
| 166 | space right home up prior]) | ||
| 167 | ((eq setup 'S-cursor) | ||
| 168 | [S-delete S-insert S-end S-down S-next S-left | ||
| 169 | S-space S-right S-home S-up S-prior]) | ||
| 170 | ((eq setup 'none) | ||
| 171 | nil) | ||
| 172 | (t | ||
| 173 | (signal 'error (list "Unknown keypad setup: " setup)))))) | ||
| 174 | |||
| 175 | ;; Bind the keys in KP list to BIND list in function-key-map. | ||
| 176 | ;; If BIND is nil, all bindings for the keys are removed. | ||
| 177 | (if (not (boundp 'function-key-map)) | ||
| 178 | (setq function-key-map (make-sparse-keymap))) | ||
| 179 | |||
| 180 | (while (< i 11) | ||
| 181 | (define-key function-key-map (vector (aref kp i)) | ||
| 182 | (if bind (vector (aref bind i)))) | ||
| 183 | (setq i (1+ i))))) | ||
| 184 | |||
| 185 | ;;; keypad.el ends here | ||