1 ;;; iedit-rect.el --- visible rectangle editing support based on Iedit.
3 ;; Copyright (C) 2010, 2011, 2012 Victor Ren
5 ;; Time-stamp: <2012-09-05 09:49:55 Victor Ren>
6 ;; Author: Victor Ren <victorhge@gmail.com>
7 ;; Keywords: occurrence region simultaneous rectangle refactoring
9 ;; X-URL: http://www.emacswiki.org/emacs/Iedit
10 ;; Compatibility: GNU Emacs: 22.x, 23.x, 24.x
12 ;; This file is not part of GNU Emacs, but it is distributed under
13 ;; the same terms as GNU Emacs.
15 ;; GNU Emacs is free software: you can redistribute it and/or modify
16 ;; it under the terms of the GNU General Public License as published by
17 ;; the Free Software Foundation, either version 3 of the License, or
18 ;; (at your option) any later version.
20 ;; GNU Emacs is distributed in the hope that it will be useful,
21 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
22 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 ;; GNU General Public License for more details.
25 ;; You should have received a copy of the GNU General Public License
26 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
30 ;; This package also provides rectangle support with *visible rectangle*
31 ;; highlighting, which is similar with cua-mode rectangle support. But it is
32 ;; lighter weight and uses iedit mechanisms.
34 ;; The code was developed and fully tested on Gnu Emacs 24.0.93, partially
35 ;; tested on Gnu Emacs 22. If you have any compatible problem, please let me
39 ;; - Add restrict function back
43 (eval-when-compile (require 'cl))
44 (require 'rect) ;; kill-rectangle
47 (defvar iedit-rectangle-mode nil) ;; Name of the minor mode
49 (make-variable-buffer-local 'iedit-rectangle-mode)
50 (or (assq 'iedit-rectangle-mode minor-mode-alist)
51 (nconc minor-mode-alist
52 (list '(iedit-rectangle-mode iedit-rectangle-mode))))
55 ;;; Default key bindings:
56 (define-key global-map [C-return] 'iedit-rectangle-mode)
58 (defvar iedit-rectangle nil
59 "This buffer local variable which is the rectangle geometry if
60 current mode is iedit-rect. Otherwise it is nil.
61 \(car iedit-rectangle) is the top-left corner and
62 \(cadr iedit-rectangle) is the bottom-right corner" )
64 (make-variable-buffer-local 'iedit-rectangle)
66 ;;; Define Iedit rect mode map
67 (defvar iedit-rect-keymap
68 (let ((map (make-sparse-keymap)))
69 (set-keymap-parent map iedit-occurrence-keymap-default)
70 (define-key map (kbd "M-K") 'iedit-kill-rectangle)
72 "Keymap used within overlays in Iedit-rect mode.")
74 (or (assq 'iedit-rectangle-mode minor-mode-map-alist)
75 (setq minor-mode-map-alist
76 (cons (cons 'iedit-rectangle-mode iedit-lib-keymap) minor-mode-map-alist)))
79 ;; Avoid to restore Iedit-rect mode when restoring desktop
80 (add-to-list 'desktop-minor-mode-handlers
81 '(iedit-rectangle-mode . nil))
84 (defun iedit-rectangle-mode ()
85 "Toggle Iedit-rect mode.
87 When Iedit-rect mode is on, a rectangle is started with visible
88 rectangle highlighting. Rectangle editing support is based on
92 \\{iedit-rect-keymap}"
94 (if iedit-rectangle-mode
95 (iedit-rectangle-done)
96 (iedit-barf-if-lib-active)
97 (if (iedit-region-active)
98 (let ((beg (region-beginning))
100 (setq mark-active nil)
101 (run-hooks 'deactivate-mark-hook)
102 (iedit-rectangle-start beg end)))))
104 (defun iedit-rectangle-start (beg end)
105 "Start Iedit mode for the region as a rectangle."
106 (barf-if-buffer-read-only)
107 (setq iedit-occurrences-overlays nil)
108 (setq iedit-rectangle (list beg end))
109 (setq iedit-initial-string-local nil)
110 (setq iedit-occurrence-keymap iedit-rect-keymap)
112 (let ((beg-col (progn (goto-char beg) (current-column)))
113 (end-col (progn (goto-char end) (current-column))))
114 (when (< end-col beg-col)
115 (rotatef beg-col end-col))
118 (push (iedit-make-occurrence-overlay
120 (move-to-column beg-col t)
123 (move-to-column end-col t)
125 iedit-occurrences-overlays)
127 until (> (point) end))
128 (setq iedit-occurrences-overlays (nreverse iedit-occurrences-overlays))))
129 (setq iedit-rectangle-mode (propertize
130 (concat " Iedit-rect:" (number-to-string (length iedit-occurrences-overlays)))
131 'face 'font-lock-warning-face))
132 (force-mode-line-update)
133 (add-hook 'kbd-macro-termination-hook 'iedit-rectangle-done nil t)
134 (add-hook 'change-major-mode-hook 'iedit-rectangle-done nil t)
135 (add-hook 'iedit-aborting-hook 'iedit-rectangle-done nil t))
137 (defun iedit-rectangle-done ()
139 Save the current occurrence string locally and globally. Save
140 the initial string globally."
141 (when iedit-buffering
142 (iedit-stop-buffering))
144 (setq iedit-rectangle-mode nil)
145 (force-mode-line-update)
146 (remove-hook 'kbd-macro-termination-hook 'iedit-rectangle-done t)
147 (remove-hook 'change-major-mode-hook 'iedit-rectangle-done t)
148 (remove-hook 'iedit-aborting-hook 'iedit-rectangle-done t))
150 (defun iedit-kill-rectangle(&optional fill)
152 The behavior is the same as `kill-rectangle' in rect mode."
154 (or (and iedit-rectangle (iedit-same-column))
155 (error "Not a rectangle"))
156 (let ((inhibit-modification-hooks t)
157 (beg (overlay-start (car iedit-occurrences-overlays)))
158 (end (overlay-end (progn (iedit-last-occurrence)
159 (iedit-find-current-occurrence-overlay)))))
160 (kill-rectangle beg end fill)))
162 (provide 'iedit-rect)
164 ;;; iedit-rect.el ends here
166 ;; LocalWords: iedit el MERCHANTABILITY kbd isearch todo ert Lindberg Tassilo
167 ;; LocalWords: eval rect defgroup defcustom boolean defvar assq alist nconc
168 ;; LocalWords: substring cadr keymap defconst purecopy bkm defun princ prev
169 ;; LocalWords: iso lefttab backtab upcase downcase concat setq autoload arg
170 ;; LocalWords: refactoring propertize cond goto nreverse progn rotatef eq elp
171 ;; LocalWords: dolist pos unmatch args ov sReplace iedit's cdr quote'ed