summaryrefslogtreecommitdiff
path: root/iedit.el
diff options
context:
space:
mode:
Diffstat (limited to 'iedit.el')
-rw-r--r--iedit.el766
1 files changed, 766 insertions, 0 deletions
diff --git a/iedit.el b/iedit.el
new file mode 100644
index 0000000..f44b9a3
--- /dev/null
+++ b/iedit.el
@@ -0,0 +1,766 @@
+;;; iedit.el --- Edit multiple regions in the same way simultaneously.
+
+;; Copyright (C) 2010, 2011, 2012 Victor Ren
+
+;; Time-stamp: <2016-09-20 00:04:51 Victor Ren>
+;; Author: Victor Ren <victorhge@gmail.com>
+;; Keywords: occurrence region simultaneous refactoring
+;; Version: 0.9.9
+;; X-URL: http://www.emacswiki.org/emacs/Iedit
+;; https://github.com/victorhge/iedit
+;; Compatibility: GNU Emacs: 22.x, 23.x, 24.x
+
+;; This file is not part of GNU Emacs, but it is distributed under
+;; the same terms as GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This package is an Emacs minor mode and allows you to edit one occurrence of
+;; some text in a buffer (possibly narrowed) or region, and simultaneously have
+;; other occurrences edited in the same way.
+;;
+;; Normal scenario of iedit-mode is like:
+;;
+;; - Highlight certain contents - by press C-; (The default key binding)
+;; All occurrences of a symbol, string in the buffer or a region may be
+;; highlighted corresponding to current mark, point and prefix argument.
+;; Refer to the document of `iedit-mode' for details.
+;;
+;; - Edit one of the occurrences
+;; The change is applied to other occurrences simultaneously.
+;;
+;; - Finish - by pressing C-; again
+;;
+;; You can also use Iedit mode as a quick way to temporarily show only the
+;; buffer lines that match the current text being edited. This gives you the
+;; effect of a temporary `keep-lines' or `occur'. To get this effect, hit C-'
+;; when in Iedit mode - it toggles hiding non-matching lines.
+;;
+;; Renaming refactoring is convenient in Iedit mode
+;;
+;; - The symbol under point is selected as occurrence by default and only
+;; complete symbols are matched
+;; - With digit prefix argument 0, only symbols in current function are matched
+;; - Restricting symbols in current region can be done by pressing C-; again
+;; - Last renaming refactoring is remembered and can be applied to other buffers
+;; later
+;;
+;; There are also some other facilities you may never think about. Refer to the
+;; document of function `iedit-mode' (C-h f iedit-mode RET) for more details.
+
+;; The code was developed and fully tested on Gnu Emacs 24.0.93, partially
+;; tested on Gnu Emacs 22. If you have any compatible problem, please let me
+;; know.
+
+;;; Contributors
+;; Adam Lindberg <eproxus@gmail.com> added a case sensitivity option that can be toggled.
+
+;; Tassilo Horn <tassilo@member.fsf.org> added an option to match only complete
+;; words, not inside words
+
+;; Le Wang <l26wang@gmail.com> proposed to match only complete symbols, not
+;; inside symbols, contributed rectangle support
+
+;;; Code:
+
+(eval-when-compile
+ (require 'cl)
+ (require 'sgml-mode))
+(require 'iedit-lib)
+
+(defcustom iedit-toggle-key-default (kbd "C-;")
+ "If no-nil, the key is inserted into global-map,
+isearch-mode-map, esc-map and help-map."
+ :type 'vector
+ :group 'iedit)
+
+(defvar iedit-mode-hook nil
+ "Function(s) to call after starting up an iedit.")
+
+(defvar iedit-mode-end-hook nil
+ "Function(s) to call after terminating an iedit.")
+
+(defvar iedit-mode nil) ;; Name of the minor mode
+
+(defvar iedit-use-symbol-boundaries t
+ "If no-nil, matches have to start and end at symbol boundaries. Otherwise,
+matches starts and end at word bondaries.")
+
+(defvar iedit-occurrence-type-local 'symbol
+ "This is buffer local variable which indicates the occurrence
+type. It might be (symbol word other).")
+
+(defvar iedit-occurrence-type-global 'symbol
+ "This is global variable which indicates the last global occurrence
+type. It might be (symbol word other).")
+
+(defvar iedit-last-occurrence-local nil
+ "This is buffer local variable which is the occurrence when
+Iedit mode is turned off last time.")
+
+(defvar iedit-last-occurrence-global nil
+ "This is global variable which is the occurrence when
+Iedit mode is turned off last time.")
+
+(defvar iedit-last-initial-string-global nil
+ "This is a global variable which is the last initial occurrence string.")
+
+(defvar iedit-initial-string-local nil
+ "This is buffer local variable which is the initial string to start Iedit mode.")
+(defvar iedit-initial-region nil
+ "This is buffer local variable which is the initial region
+where Iedit mode is started from.")
+
+(defvar iedit-num-lines-to-expand-up 0
+ "This is a global variable indicating how many lines up from
+point should be included in the replacement region.")
+
+(defvar iedit-num-lines-to-expand-down 0
+ "This is a global variable indicating how many lines down from
+point should be included in the replacement region.")
+
+(defvar iedit-default-occurrence-local nil
+ "This is a function which returns a string as occurrence candidate.
+It is called in `iedit-default-occurrence'. This buffer local
+varialbe can be configured in some modes. An example of how to
+use this variable:
+(add-hook 'perl-mode-hook
+ '(lambda ()
+ (setq iedit-default-occurrence-local
+ '(lambda ()
+ (let* ((bound (bounds-of-thing-at-point 'symbol))
+ (prefix-char (char-after (1- (car bound)))))
+ (if (memq prefix-char '(?$ ?% ?@ ?*))
+ (progn
+ (setq iedit-occurrence-type-local 'regexp)
+ (concat (regexp-quote (buffer-substring-no-properties (1- (car bound)) (cdr bound))) \"\\\\_>\"))
+ (buffer-substring-no-properties (car bound) (cdr bound))))))))
+'$%@*' will be included in the occurrences in perl mode.")
+
+(make-variable-buffer-local 'iedit-mode)
+(make-variable-buffer-local 'iedit-use-symbol-boundaries)
+(make-variable-buffer-local 'iedit-occurrence-type-local)
+(make-variable-buffer-local 'iedit-last-occurrence-local)
+(make-variable-buffer-local 'iedit-initial-string-local)
+(make-variable-buffer-local 'iedit-initial-region)
+(make-variable-buffer-local 'iedit-default-occurrence-local)
+
+(or (assq 'iedit-mode minor-mode-alist)
+ (nconc minor-mode-alist
+ (list '(iedit-mode iedit-mode))))
+
+;;; Define iedit help map.
+(eval-when-compile (require 'help-macro))
+
+(defvar iedit-help-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map (vector (event-convert-list `(,help-char))) 'iedit-help-for-help)
+ (define-key map [help] 'iedit-help-for-help)
+ (define-key map [f1] 'iedit-help-for-help)
+ (define-key map "?" 'iedit-help-for-help)
+ (define-key map "b" 'iedit-describe-bindings)
+ (define-key map "k" 'iedit-describe-key)
+ (define-key map "m" 'iedit-describe-mode)
+ (define-key map "q" 'help-quit)
+ map)
+ "Keymap for characters following the Help key for Iedit mode.")
+
+(make-help-screen
+ iedit-help-for-help-internal
+ (purecopy "Type a help option: [bkm] or ?")
+ "You have typed %THIS-KEY%, the help character. Type a Help option:
+\(Type \\<help-map>\\[help-quit] to exit the Help command.)
+
+b Display all Iedit key bindings.
+k KEYS Display full documentation of Iedit key sequence.
+m Display documentation of Iedit mode.
+
+You can't type here other help keys available in the global help map,
+but outside of this help window when you type them in Iedit mode,
+they exit Iedit mode before displaying global help."
+ iedit-help-map)
+
+(defun iedit-help-for-help ()
+ "Display Iedit help menu."
+ (interactive)
+ (let (same-window-buffer-names same-window-regexps)
+ (iedit-help-for-help-internal)))
+
+(defun iedit-describe-bindings ()
+ "Show a list of all keys defined in Iedit mode, and their definitions.
+This is like `describe-bindings', but displays only Iedit keys."
+ (interactive)
+ (let (same-window-buffer-names
+ same-window-regexps
+ (keymap (substitute-command-keys "\\{iedit-mode-keymap}\\{iedit-mode-occurrence-keymap}")))
+ (with-help-window "*Help*"
+ (with-current-buffer standard-output
+ (princ "Iedit Mode Bindings: ")
+ (princ keymap)))))
+
+(defun iedit-describe-key ()
+ "Display documentation of the function invoked by Iedit mode key."
+ (interactive)
+ (let (same-window-buffer-names same-window-regexps)
+ (call-interactively 'describe-key)))
+
+(defun iedit-describe-mode ()
+ "Display documentation of Iedit mode."
+ (interactive)
+ (let (same-window-buffer-names same-window-regexps)
+ (describe-function 'iedit-mode)))
+
+;;; Default key bindings:
+(when (and iedit-toggle-key-default (null (where-is-internal 'iedit-mode)))
+ (let ((key-def (lookup-key (current-global-map) iedit-toggle-key-default)))
+ (if key-def
+ (display-warning 'iedit (format "Iedit default key %S is occupied by %s."
+ (key-description iedit-toggle-key-default)
+ key-def)
+ :warning)
+ (define-key global-map iedit-toggle-key-default 'iedit-mode)
+ (define-key isearch-mode-map iedit-toggle-key-default 'iedit-mode-from-isearch)
+ (define-key esc-map iedit-toggle-key-default 'iedit-execute-last-modification)
+ (define-key help-map iedit-toggle-key-default 'iedit-mode-toggle-on-function)
+ (message "Iedit default key binding is %s" (key-description iedit-toggle-key-default)))))
+
+;; Avoid to restore Iedit mode when restoring desktop
+(add-to-list 'desktop-minor-mode-handlers
+ '(iedit-mode . nil))
+
+;;; Define iedit help map.
+(eval-when-compile (require 'help-macro))
+
+(defvar iedit-mode-occurrence-keymap
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map iedit-occurrence-keymap-default)
+ (define-key map (kbd "M-H") 'iedit-restrict-function)
+ (define-key map (kbd "M-I") 'iedit-restrict-current-line)
+ (define-key map (kbd "M-{") 'iedit-expand-up-a-line)
+ (define-key map (kbd "M-}") 'iedit-expand-down-a-line)
+ (define-key map (kbd "M-p") 'iedit-expand-up-to-occurrence)
+ (define-key map (kbd "M-n") 'iedit-expand-down-to-occurrence)
+ (define-key map (kbd "M-G") 'iedit-apply-global-modification)
+ (define-key map (kbd "M-C") 'iedit-toggle-case-sensitive)
+ map)
+ "Keymap used within overlays in Iedit mode.")
+
+(defvar iedit-mode-keymap
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map iedit-lib-keymap)
+ (define-key map (vector (event-convert-list `(,help-char))) iedit-help-map)
+ (define-key map [help] iedit-help-map)
+ (define-key map [f1] iedit-help-map)
+ (define-key map (kbd "M-;") 'iedit-toggle-selection)
+ map)
+ "Keymap used while Iedit mode is enabled.")
+
+;;; Define Iedit mode map
+(or (assq 'iedit-mode minor-mode-map-alist)
+ (setq minor-mode-map-alist
+ (cons (cons 'iedit-mode iedit-mode-keymap) minor-mode-map-alist)))
+
+;;;###autoload
+(defun iedit-mode (&optional arg)
+ "Toggle Iedit mode.
+This command behaves differently, depending on the mark, point,
+prefix argument and variable `iedit-transient-mark-sensitive'.
+
+If Iedit mode is off, turn Iedit mode on.
+
+When Iedit mode is turned on, all the occurrences of the current
+region in the buffer (possibly narrowed) or a region are
+highlighted. If one occurrence is modified, the change are
+propagated to all other occurrences simultaneously.
+
+If region is not active, `iedit-default-occurrence' is called to
+get an occurrence candidate, according to the thing at point. It
+might be url, email address, markup tag or current symbol(or
+word) .
+
+In the above two situations, with digit prefix argument 0, only
+occurrences in current function are matched. This is good for
+renaming refactoring in programming.
+
+You can also switch to Iedit mode from isearch mode directly. The
+current search string is used as occurrence. All occurrences of
+the current search string are highlighted.
+
+With an universal prefix argument, the occurrence when Iedit mode
+is turned off last time in current buffer is used as occurrence.
+This is intended to recover last Iedit mode which is turned off.
+If region active, Iedit mode is limited within the current
+region.
+
+With repeated universal prefix argument, the occurrence when
+Iedit mode is turned off last time (might be in other buffer) is
+used as occurrence. If region active, Iedit mode is limited
+within the current region.
+
+With digital prefix argument 1, Iedit mode is limited on the
+current symbol or the active region, which means just one
+instance is highlighted. This behavior serves as a start point
+of incremental selection work flow.
+
+If Iedit mode is on and region is active, Iedit mode is
+restricted in the region, e.g. the occurrences outside of the
+region is excluded.
+
+If Iedit mode is on and region is active, with an universal
+prefix argument, Iedit mode is restricted outside of the region,
+e.g. the occurrences in the region is excluded.
+
+Turn off Iedit mode in other situations.
+
+Commands:
+\\{iedit-mode-keymap}
+Keymap used within overlays:
+\\{iedit-mode-occurrence-keymap}"
+ (interactive "P")
+ (if iedit-mode
+ (iedit-mode-on-action arg)
+ (iedit-barf-if-lib-active)
+ (let (occurrence
+ (beg (if (eq major-mode 'occur-edit-mode) ; skip the first occurrence
+ (next-single-char-property-change 1 'read-only)
+ (point-min)))
+ (end (point-max)))
+ ;; Get the occurrence and iedit-occurrence-type-local
+ (cond ((and arg
+ (= 4 (prefix-numeric-value arg))
+ iedit-last-occurrence-local)
+ (setq occurrence iedit-last-occurrence-local))
+ ((and arg
+ (= 16 (prefix-numeric-value arg))
+ iedit-last-initial-string-global)
+ (setq occurrence iedit-last-initial-string-global)
+ (setq iedit-occurrence-type-local iedit-occurrence-type-global))
+ ((iedit-region-active)
+ (setq occurrence (buffer-substring-no-properties
+ (mark) (point)))
+ (setq iedit-occurrence-type-local 'selection))
+ (t (setq occurrence (iedit-default-occurrence))
+ (unless occurrence
+ (error "No candidate of the occurrence, cannot enable Iedit mode"))))
+ ;; Get the scope
+ (when arg
+ (cond ((= 0 (prefix-numeric-value arg))
+ (save-excursion
+ (mark-defun)
+ (setq beg (region-beginning))
+ (setq end (region-end))))
+ ((and (= 1 (prefix-numeric-value arg))
+ (not (iedit-region-active)))
+ (let ((region (bounds-of-thing-at-point 'symbol)))
+ (setq beg (car region))
+ (setq end (cdr region))))
+ ((iedit-region-active)
+ (setq beg (region-beginning))
+ (setq end (region-end)))))
+ (setq mark-active nil)
+ (run-hooks 'deactivate-mark-hook)
+ (setq iedit-initial-string-local occurrence)
+ (iedit-start (iedit-regexp-quote occurrence) beg end)
+ (unless iedit-occurrences-overlays
+ ;; (message "No matches found for %s" (iedit-regexp-quote occurrence))
+ (iedit-done)))))
+
+(defun iedit-mode-from-isearch (regexp)
+ "Start Iedit mode using last search string as the regexp."
+ (interactive
+ (let ((regexp (cond
+ ((functionp isearch-regexp-function)
+ (funcall isearch-regexp-function isearch-string))
+ (isearch-regexp-function (word-search-regexp isearch-string))
+ (isearch-regexp isearch-string)
+ (t (regexp-quote isearch-string)))))
+ (list regexp)))
+ (or isearch-success
+ (error "No match" ))
+ (if (or isearch-regexp isearch-regexp-function)
+ nil
+ (setq iedit-initial-string-local isearch-string))
+ (let ((iedit-case-sensitive (not isearch-case-fold-search)))
+ (isearch-exit)
+ (setq mark-active nil)
+ (run-hooks 'deactivate-mark-hook)
+ (when iedit-mode
+ (iedit-cleanup))
+ (iedit-start regexp (point-min) (point-max))
+ ;; TODO: reconsider how to avoid the loop in iedit-same-length
+ (cond ((not iedit-occurrences-overlays)
+ (message "No matches found for %s" regexp)
+ (iedit-done))
+ ((not (iedit-same-length))
+ (message "Matches are not the same length.")
+ (iedit-done)))))
+
+(defun iedit-start (occurrence-regexp beg end)
+ "Start Iedit mode for the `occurrence-regexp' in the current buffer."
+ ;; enforce skip modification once, errors may happen to cause this to be
+ ;; unset.
+ (setq iedit-skip-modification-once t)
+ (setq iedit-initial-region (list beg end))
+ (let ((counter 0))
+ (if (eq iedit-occurrence-type-local 'markup-tag)
+ (progn
+ (setq iedit-occurrence-keymap iedit-occurrence-keymap-default)
+ (iedit-make-markers-overlays iedit-occurrences-overlays)
+ (setq counter 2))
+ (setq iedit-occurrence-keymap iedit-mode-occurrence-keymap)
+ (setq counter (iedit-make-occurrences-overlays occurrence-regexp beg end)))
+ (message "%d matches for \"%s\""
+ counter
+ (iedit-printable occurrence-regexp))
+ (setq iedit-mode
+ (propertize
+ (concat " Iedit:" (number-to-string counter))
+ 'face
+ 'font-lock-warning-face))
+ (force-mode-line-update))
+ (run-hooks 'iedit-mode-hook)
+ (add-hook 'before-revert-hook 'iedit-done nil t)
+ (add-hook 'kbd-macro-termination-hook 'iedit-done nil t)
+ (add-hook 'change-major-mode-hook 'iedit-done nil t)
+ (add-hook 'iedit-aborting-hook 'iedit-done nil t))
+
+(defun iedit-default-occurrence()
+ "This function returns a string as occurrence candidate.
+The candidate depends on the thing at point."
+ (let (occurrence-str)
+ (cond
+ ((thing-at-point 'url)
+ (setq occurrence-str (thing-at-point 'url))
+ (setq iedit-occurrence-type-local 'url))
+
+ ((thing-at-point 'email)
+ (setq occurrence-str (thing-at-point 'email))
+ (setq iedit-occurrence-type-local 'email))
+
+ (iedit-default-occurrence-local
+ (setq occurrence-str (funcall iedit-default-occurrence-local)))
+ ;; Try to mark sgml pair anyway
+ ((and (not (bound-and-true-p sgml-electric-tag-pair-mode))
+ (setq occurrence-str (iedit-mark-sgml-pair)))
+ (setq iedit-occurrence-type-local 'markup-tag))
+
+ ((and iedit-use-symbol-boundaries ;option
+ (thing-at-point 'symbol))
+ (setq occurrence-str (thing-at-point 'symbol))
+ (setq iedit-occurrence-type-local 'symbol))
+
+ ((thing-at-point 'word)
+ (setq occurrence-str (thing-at-point 'word))
+ (setq iedit-occurrence-type-local 'word)))
+ occurrence-str))
+
+(defun iedit-regexp-quote (exp)
+ "Return a regexp string."
+ (cl-case iedit-occurrence-type-local
+ ('symbol (concat "\\_<" (regexp-quote exp) "\\_>"))
+ ('word (concat "\\<" (regexp-quote exp) "\\>"))
+ ('regexp exp)
+ ( t (regexp-quote exp))))
+
+(defun iedit-mark-sgml-pair ()
+ "Check if the cursor is on a markup tag.
+If the cursor is on a markup tag, the postion of the opening and
+closing markup tags are saved in `iedit-occurrence-overlays'
+temporarily.
+
+The code is adpated from
+`sgml-electric-tag-pair-before-change-function'.
+
+Return the tag if succeeded, nil if failed."
+ (condition-case err
+ (save-excursion
+ (skip-chars-backward "[:alnum:]-_.:")
+ (if (or (eq (char-before) ?<)
+ (and (eq (char-before) ?/)
+ (eq (char-before (1- (point))) ?<)))
+ (let* ((endp (eq (char-before) ?/))
+ (cl-start (point))
+ (cl-end (progn (skip-chars-forward "[:alnum:]-_.:") (point)))
+ (match
+ (if endp
+ (when (sgml-skip-tag-backward 1) (forward-char 1) t)
+ (with-syntax-table sgml-tag-syntax-table
+ (up-list -1)
+ (when (sgml-skip-tag-forward 1)
+ (backward-sexp 1)
+ (forward-char 2)
+ t)))))
+ (when (and match
+ (/= cl-end cl-start)
+ (equal (buffer-substring cl-start cl-end)
+ (buffer-substring (point)
+ (save-excursion
+ (skip-chars-forward "[:alnum:]-_.:")
+ (point))))
+ (or (not endp) (eq (char-after cl-end) ?>)))
+ (push (cons cl-start cl-end) iedit-occurrences-overlays)
+ (push (cons (point) (+ (point) (- cl-end cl-start))) iedit-occurrences-overlays)
+ (buffer-substring cl-start cl-end)))))
+ (error nil)))
+
+(defun iedit-done ()
+ "Exit Iedit mode.
+Save the current occurrence string locally and globally. Save
+the initial string globally."
+ (when iedit-buffering
+ (iedit-stop-buffering))
+ (setq iedit-last-occurrence-local (iedit-current-occurrence-string))
+ (setq iedit-occurrence-type-global iedit-occurrence-type-local)
+ (setq iedit-last-occurrence-global iedit-last-occurrence-local)
+ (setq iedit-last-initial-string-global iedit-initial-string-local)
+ (if iedit-last-occurrence-local
+ (kill-new iedit-last-occurrence-local)) ; Make occurrence the latest kill in the kill ring.
+ (setq iedit-num-lines-to-expand-up 0)
+ (setq iedit-num-lines-to-expand-down 0)
+
+ (iedit-cleanup)
+
+ (setq iedit-initial-string-local nil)
+ (setq iedit-mode nil)
+ (force-mode-line-update)
+ (remove-hook 'before-revert-hook 'iedit-done t)
+ (remove-hook 'kbd-macro-termination-hook 'iedit-done t)
+ (remove-hook 'change-major-mode-hook 'iedit-done t)
+ (remove-hook 'iedit-aborting-hook 'iedit-done t)
+ (run-hooks 'iedit-mode-end-hook))
+
+(defun iedit-mode-on-action (&optional arg)
+ "Turn off Iedit mode or restrict it in a region if region is active."
+ (if (iedit-region-active)
+ (iedit-restrict-region (region-beginning) (region-end) arg)
+ (iedit-done)))
+
+
+;;;###autoload
+(defun iedit-mode-toggle-on-function ()
+ "Toggle Iedit mode on current function."
+ (interactive)
+ (iedit-mode 0))
+
+(defun iedit-execute-last-modification (&optional arg)
+ "Apply last modification in Iedit mode to the current buffer or an active region."
+ (interactive "*P")
+ (or (and iedit-last-initial-string-global
+ (not (string= iedit-last-initial-string-global iedit-last-occurrence-global)))
+ (error "No modification available"))
+ (let ((occurrence-exp (regexp-quote iedit-last-initial-string-global))
+ (replacement iedit-last-occurrence-global)
+ (case-fold-search (not iedit-case-sensitive))
+ beg end)
+ (when case-fold-search
+ (setq occurrence-exp (downcase occurrence-exp))
+ (setq replacement (downcase replacement)))
+ ;; `iedit-regexp-quote' depends on iedit-occurrence-type-local
+ (setq iedit-occurrence-type-local iedit-occurrence-type-global)
+ (setq occurrence-exp (iedit-regexp-quote occurrence-exp))
+ (when (iedit-region-active)
+ (setq beg (region-beginning))
+ (setq end (region-end)))
+ (perform-replace occurrence-exp replacement t t nil nil nil beg end)))
+
+(defun iedit-apply-global-modification ()
+ "Apply last global modification."
+ (interactive "*")
+ (if (and iedit-last-initial-string-global
+ (string= iedit-initial-string-local iedit-last-initial-string-global)
+ (not (string= iedit-last-initial-string-global iedit-last-occurrence-global)))
+ (iedit-replace-occurrences iedit-last-occurrence-global)
+ (message "No global modification available.")))
+
+(defun iedit-toggle-selection ()
+ "Select or deselect the occurrence under point."
+ (interactive)
+ (iedit-barf-if-buffering)
+ (let ((ov (iedit-find-current-occurrence-overlay)))
+ (if ov
+ (iedit-restrict-region (overlay-start ov) (overlay-end ov) t)
+ (let ((current-occurrence-string (iedit-current-occurrence-string)))
+ (when (not (null current-occurrence-string))
+ (save-excursion
+ (goto-char (if (> (point) (length current-occurrence-string))
+ ( - (point) (length current-occurrence-string))
+ (point-min)))
+ (iedit-add-next-occurrence-overlay
+ (iedit-regexp-quote current-occurrence-string)))
+ (setq iedit-mode (propertize
+ (concat " Iedit:" (number-to-string
+ (length iedit-occurrences-overlays)))
+ 'face 'font-lock-warning-face))
+ (force-mode-line-update))))))
+
+(defun iedit-restrict-function(&optional arg)
+ "Restricting Iedit mode in current function."
+ (interactive "P")
+ (save-excursion
+ (mark-defun)
+ (iedit-restrict-region (region-beginning) (region-end) arg))
+ (message "Restricted in current function, %d matches."
+ (length iedit-occurrences-overlays)))
+
+(defun iedit-restrict-current-line ()
+ "Restrict Iedit mode to current line."
+ (interactive)
+ (iedit-restrict-region (iedit-char-at-bol) (iedit-char-at-eol))
+ (setq iedit-num-lines-to-expand-up 0
+ iedit-num-lines-to-expand-down 0)
+ (message "Restricted to current line, %d match%s."
+ (length iedit-occurrences-overlays)
+ (if (= 1 (length iedit-occurrences-overlays)) "" "es")))
+
+(defun iedit-expand-by-a-line (where amount)
+ "Expands the top or bottom of the search region upwards or
+downwards by `amount' lines. The region being acted upon is
+controlled with `where' ('top to act on the top, anything else
+for the bottom). With a prefix, collapses the top or bottom of
+the search region by `amount' lines."
+ (interactive "P")
+ (let ((occurrence (iedit-current-occurrence-string)))
+ (iedit-cleanup)
+ (if (eq where 'top)
+ (setq iedit-num-lines-to-expand-up
+ (max 0 (+ amount iedit-num-lines-to-expand-up)))
+ (setq iedit-num-lines-to-expand-down
+ (max 0 (+ amount iedit-num-lines-to-expand-down))))
+ (iedit-start (iedit-regexp-quote occurrence)
+ (iedit-char-at-bol (- iedit-num-lines-to-expand-up))
+ (iedit-char-at-eol iedit-num-lines-to-expand-down))
+ (message "Now looking -%d/+%d lines around current line, %d match%s."
+ iedit-num-lines-to-expand-up
+ iedit-num-lines-to-expand-down
+ (length iedit-occurrences-overlays)
+ (if (= 1 (length iedit-occurrences-overlays)) "" "es"))))
+
+(defun iedit-expand-up-a-line (&optional arg)
+ "After start iedit-mode only on current symbol or the active
+region, this function expands the search region upwards by one
+line. With a prefix, bring the top of the region back down one
+line."
+ (interactive "P")
+ (iedit-expand-by-a-line 'top
+ (if arg -1 1)))
+
+(defun iedit-expand-down-a-line (&optional arg)
+ "After start iedit-mode only on current symbol or the active
+region, this function expands the search region downwards by one
+line. With a prefix, bring the bottom of the region back up one
+line."
+ (interactive "P")
+ (iedit-expand-by-a-line 'bottom
+ (if arg -1 1)))
+
+(defun iedit-expand-down-to-occurrence (&optional arg)
+ "Expand the search region downwards until reaching a new occurrence.
+If no such occurrence can be found, throw an error. With a
+prefix, bring the bottom of the region back up one occurrence."
+ (interactive "P")
+ (if arg
+ (progn (iedit-restrict-region
+ (iedit-first-occurrence)
+ (1- (iedit-last-occurrence)))
+ (when iedit-mode
+ (goto-char (iedit-last-occurrence))))
+ (iedit-expand-to-occurrence t)))
+
+(defun iedit-expand-up-to-occurrence (&optional arg)
+ "Expand the search region upwards until reaching a new occurrence.
+If no such occurrence can be found, throw an error. With a
+prefix, bring the top of the region back down one occurrence."
+ (interactive "P")
+ (if arg
+ (progn (iedit-restrict-region
+ (+ (iedit-occurrence-string-length) (iedit-first-occurrence))
+ (+ (iedit-occurrence-string-length) (iedit-last-occurrence)))
+ (when iedit-mode
+ (goto-char (iedit-first-occurrence))))
+ (iedit-expand-to-occurrence nil)))
+
+(defun iedit-expand-to-occurrence (forward)
+ "Expand to next or previous occurrence."
+ (let ((pos (iedit-add-occurrence-overlay
+ (iedit-regexp-quote (iedit-current-occurrence-string))
+ (if forward
+ (1+ (iedit-last-occurrence))
+ (iedit-first-occurrence))
+ forward)))
+ (when pos
+ (goto-char pos)
+ (setq iedit-mode (propertize
+ (concat " Iedit:" (number-to-string
+ (length iedit-occurrences-overlays)))
+ 'face 'font-lock-warning-face))
+ (force-mode-line-update))))
+
+(defun iedit-restrict-region (beg end &optional inclusive)
+ "Restricting Iedit mode in a region."
+ (if (null (iedit-find-overlay beg end 'iedit-occurrence-overlay-name inclusive))
+ (iedit-done)
+ (when iedit-buffering
+ (iedit-stop-buffering))
+ (setq iedit-last-occurrence-local (iedit-current-occurrence-string))
+ (setq mark-active nil)
+ (run-hooks 'deactivate-mark-hook)
+ (iedit-show-all)
+ (iedit-cleanup-occurrences-overlays beg end inclusive)
+ (if iedit-unmatched-lines-invisible
+ (iedit-hide-unmatched-lines iedit-occurrence-context-lines))
+ (setq iedit-mode (propertize
+ (concat " Iedit:" (number-to-string
+ (length iedit-occurrences-overlays)))
+ 'face 'font-lock-warning-face))
+ (force-mode-line-update)))
+
+(defun iedit-toggle-case-sensitive ()
+ "Toggle case-sensitive matching occurrences. "
+ (interactive)
+ (setq iedit-case-sensitive (not iedit-case-sensitive))
+ (if iedit-buffering
+ (iedit-stop-buffering))
+ (setq iedit-last-occurrence-local (iedit-current-occurrence-string))
+ (when iedit-last-occurrence-local
+ (remove-overlays nil nil iedit-occurrence-overlay-name t)
+ (iedit-show-all)
+ (let* ((occurrence-regexp (iedit-regexp-quote iedit-last-occurrence-local))
+ (begin (car iedit-initial-region))
+ (end (cadr iedit-initial-region))
+ (counter (iedit-make-occurrences-overlays occurrence-regexp begin end)))
+ (message "iedit %s. %d matches for \"%s\""
+ (if iedit-case-sensitive
+ "is case sensitive"
+ "ignores case")
+ counter
+ (iedit-printable occurrence-regexp))
+ (setq iedit-mode
+ (propertize
+ (concat " Iedit:" (number-to-string counter))
+ 'face
+ 'font-lock-warning-face))
+ (force-mode-line-update))))
+
+(provide 'iedit)
+
+;;; iedit.el ends here
+
+;; LocalWords: iedit el MERCHANTABILITY kbd isearch todo ert Lindberg Tassilo
+;; LocalWords: eval defgroup defcustom boolean defvar assq alist nconc
+;; LocalWords: substring cadr keymap defconst purecopy bkm defun princ prev
+;; LocalWords: iso lefttab backtab upcase downcase concat setq autoload arg
+;; LocalWords: refactoring propertize cond goto nreverse progn rotatef eq elp
+;; LocalWords: dolist pos unmatch args ov sReplace iedit's cdr quote'ed