[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/iedit e9a94852d8 001/301: updates
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/iedit e9a94852d8 001/301: updates |
Date: |
Mon, 10 Jan 2022 22:58:44 -0500 (EST) |
branch: elpa/iedit
commit e9a94852d8331291c8742bfa446061e2511463a8
Author: anybody <anybody@emacswiki.org>
Commit: Jonas Bernoulli <jonas@bernoul.li>
updates
---
iedit.el | 319 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 319 insertions(+)
diff --git a/iedit.el b/iedit.el
new file mode 100644
index 0000000000..6a3052379a
--- /dev/null
+++ b/iedit.el
@@ -0,0 +1,319 @@
+;;; iedit.el --- Edit multiple regions with the same content simultaneously.
+
+;; Copyright (C) 2010 Victor Ren
+
+;; Time-stamp: <2010-03-07 22:48:30 Victor Ren>
+;; Author: Victor Ren <victorhge@gmail.com>
+;; Keywords: occurrence region replace simultaneous
+;; Version: 0.60
+;; X-URL:
+;; Compatibility: GNU Emacs: 22.x, 23.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 provides a more intuitive way of replace-string operation:
+;;
+;; - Select the occurrence in the buffer
+;; In Transient Mark mode, just mark a region, the content of the
+;; region will be used as the occurrence. (if Transient Mark mode is
disabled,
+;; using C-u C-x C-x or C-SPC C-SPC to activate it just for this one time).
+;;
+;; - Start iedit minor mode - by press C-;
+;; All occurrences of the content in the buffer are highlighted
+;;
+;; - Edit one of the contents
+;; The change is applied to other contents simultaneously
+;;
+;; - Finish - by pressing C-; again
+
+;; If Transient Mark mode is disabled or the region is not active,
+;; the `current-word' is used as the occurrence by default.
+
+;; You can also switch to iedit mode from isearch mode directly. The current
+;; search string is used as the occurrence.
+
+;; If you would like to replace-string on certain region, use "narrowing"
first.
+
+;;; Suggested key bindings:
+;;
+;; (define-key global-map (kbd "C-;") 'iedit-mode)
+;; (define-key isearch-mode-map (kbd "C-;") 'iedit-mode)
+
+;;; todo:
+;; - wrapping around navigating
+;; - Lazy highlight feature (from isearch)
+;; - Help information
+;; - Option of enabling linum-mode when unmatched lines are hided.
+;; - face for current occurrence
+;; - blank line between matched lines
+;; - fix problem of iedit-next-occurrence with linum-mode
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(defgroup iedit nil
+ "Edit multiple regions with the same content simultaneously."
+ :prefix "iedit-"
+ :group 'replace
+ :group 'convenience)
+
+(defcustom iedit-occurrence-face 'highlight
+ "*Face used for the occurrences' default values."
+ :type 'face
+ :group 'iedit)
+
+(defcustom iedit-current-word-default 't
+ "If no-nil, use current word by default for the occurrence."
+ :type 'boolean
+ :group 'iedit)
+
+(defcustom iedit-unmatched-lines-invisible-default nil
+ "If no-nil, hide lines that do not cover any occurrences by default."
+ :type 'boolean
+ :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
+
+(make-variable-buffer-local 'iedit-mode)
+
+(or (assq 'iedit-mode minor-mode-alist)
+ (nconc minor-mode-alist
+ (list '(iedit-mode iedit-mode))))
+
+(defvar iedit-occurrences-overlays nil
+ "The occurrences slot contains a list of overlays used to indicate
+the position of each occurrence. In addition, the occurrence overlay is
+used to provide a different face configurable via
+`iedit-occurrence-face'." )
+
+(defvar iedit-unmatched-lines-invisible nil
+ "This is buffer local variable which indicates whether unmatched
+lines are hided.")
+
+(defvar iedit-last-occurrence-in-history nil
+ "This is buffer local variable which is the occurrence when
+ iedit mode is turned off last time.")
+
+(make-variable-buffer-local 'iedit-occurrences-overlays)
+(make-variable-buffer-local 'iedit-unmatched-lines-invisible)
+
+(defconst iedit-occurrence-overlay-name 'iedit-occurrence-overlay-name)
+(defconst iedit-invisible-overlay-name 'iedit-invisible-overlay-name)
+
+(defvar iedit-mode-map nil
+ "Keymap used while iedit mode is enabled.")
+
+(if iedit-mode-map
+ nil
+ (setq iedit-mode-map (make-sparse-keymap))
+ ;; Default key bindings
+ (define-key iedit-mode-map (kbd "TAB") 'iedit-next-occurrence)
+ (define-key iedit-mode-map (kbd "<S-tab>") 'iedit-prev-occurrence)
+ (define-key iedit-mode-map (kbd "<S-iso-lefttab>") 'iedit-prev-occurrence)
+ (define-key iedit-mode-map (kbd "C-'")
'iedit-toggle-unmatched-lines-visible))
+
+(or (assq 'iedit-mode minor-mode-map-alist)
+ (setq minor-mode-map-alist
+ (cons (cons 'iedit-mode iedit-mode-map) minor-mode-map-alist)))
+
+;;;###autoload
+(defun iedit-mode (&optional arg)
+ "Toggle iedit mode.
+If iedit mode is off, turn iedit mode on, off otherwise.
+
+In Transient Mark mode, when iedit mode is turned on, all the
+occurrences of the current region are highlighted. If one
+occurrence is modified, the change are propagated to all other
+occurrences simultaneously.
+
+If Transient Mark mode is disabled or the region is not active,
+the `current-word' is used as occurrence. All the occurrences of
+the `current-word' are highlighted.
+
+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 a prefix argument, the occurrence when iedit is turned off
+last time is used as occurrence. This is intended to recover
+last iedit which is turned off by mistake.
+
+Commands:
+\\{iedit-mode-map}"
+ (interactive "P")
+ (if iedit-mode
+ (iedit-done)
+ (let ((occurrence nil))
+ (cond ((and arg iedit-last-occurrence-in-history)
+ (setq occurrence iedit-last-occurrence-in-history))
+ ((and transient-mark-mode mark-active (not (equal (mark) (point))))
+ (setq occurrence (buffer-substring (mark) (point))))
+ ((and isearch-mode (not (string= isearch-string "")))
+ (setq occurrence isearch-string)
+ (isearch-exit))
+ ((and iedit-current-word-default (current-word t))
+ (setq occurrence (current-word)))
+ (t (error "No candidate of the occurrence, cannot enable iedit
mode.")))
+ (deactivate-mark)
+ (iedit-start occurrence))))
+
+(defun iedit-start (occurrence-exp)
+ "Start an iedit for the occurrence-exp in the current buffer."
+ (setq iedit-mode " Iedit")
+ (setq iedit-occurrences-overlays nil)
+ (setq iedit-unmatched-lines-invisible
iedit-unmatched-lines-invisible-default)
+ (force-mode-line-update)
+ (run-hooks 'iedit-mode-hook)
+ (add-hook 'mouse-leave-buffer-hook 'iedit-done)
+ (add-hook 'kbd-macro-termination-hook 'iedit-done)
+ ;; Find and record each occurrence's markers and add the overlay to the
occurrences
+ (let ((counter 0))
+ (save-excursion
+ (goto-char (point-min))
+ (while (search-forward occurrence-exp nil t)
+ (push (iedit-make-occurrence-overlay (match-beginning 0) (match-end 0))
+ iedit-occurrences-overlays)
+ (setq counter (1+ counter))) ; at less 1
+ (setq iedit-occurrences-overlays (nreverse iedit-occurrences-overlays))
+ (if iedit-unmatched-lines-invisible
+ (iedit-hide-unmatched-lines))
+ (message "%d matches for \"%s\""
+ counter
+ (if (> (length occurrence-exp) 50)
+ (concat (substring occurrence-exp 0 50) "...")
+ occurrence-exp)))))
+
+(defun iedit-hide-unmatched-lines ()
+ "Hide unmatched lines using invisible overlay."
+ (let ((prev-occurrence-end 0)
+ (unmatched-lines nil))
+ (save-excursion
+ (dolist (overlay iedit-occurrences-overlays)
+ (let ((match-start (overlay-start overlay))
+ (match-end (overlay-end overlay)))
+ (goto-char match-start)
+ (if (> (line-beginning-position) (1+ prev-occurrence-end))
+ (let ((unmatch-start (1+ prev-occurrence-end))
+ (unmatch-end (1- (line-beginning-position))))
+ (push (list unmatch-start unmatch-end) unmatched-lines)))
+ (goto-char match-end)
+ (setq prev-occurrence-end (line-end-position))))
+ (if (< prev-occurrence-end (point-max))
+ (push (list (1+ prev-occurrence-end) (point-max)) unmatched-lines))
+ (when unmatched-lines
+ (dolist (unmatch unmatched-lines)
+ (iedit-make-unmatched-lines-overlay (car unmatch) (cadr
unmatch)))))))
+
+(defun iedit-done ()
+ "Exit iedit mode."
+ (let ((ov (car iedit-occurrences-overlays)))
+ (if ov
+ (setq iedit-last-occurrence-in-history
+ (buffer-substring (overlay-start ov) (overlay-end ov)))))
+ (remove-overlays (point-min) (point-max) iedit-occurrence-overlay-name t)
+ (remove-overlays (point-min) (point-max) iedit-invisible-overlay-name t)
+ (setq iedit-occurrences-overlays nil)
+ (remove-hook 'mouse-leave-buffer-hook 'iedit-done)
+ (remove-hook 'kbd-macro-termination-hook 'iedit-done)
+ (setq iedit-mode nil)
+ (force-mode-line-update)
+ (run-hooks 'iedit-mode-end-hook))
+
+(defun iedit-make-occurrence-overlay (begin end)
+ "Create an overlay for an occurrence in iedit mode.
+Add the properties for the overlay: a face used to display a
+occurrence's default value, and modification hooks to update
+occurrences if the user starts typing."
+ (let ((occurrence (make-overlay begin end (current-buffer) nil t)))
+ (overlay-put occurrence iedit-occurrence-overlay-name t)
+ (overlay-put occurrence 'face iedit-occurrence-face)
+ (overlay-put occurrence 'insert-in-front-hooks '(iedit-occurrence-update))
+ (overlay-put occurrence 'insert-behind-hooks '(iedit-occurrence-update))
+ (overlay-put occurrence 'modification-hooks '(iedit-occurrence-update))
+ occurrence))
+
+(defun iedit-make-unmatched-lines-overlay (begin end)
+ "Create an overlay for lines between two occurrences in iedit mode."
+ (let ((unmatched-lines-overlay (make-overlay begin end (current-buffer) nil
t)))
+ (overlay-put unmatched-lines-overlay iedit-invisible-overlay-name t)
+ (overlay-put unmatched-lines-overlay 'invisible t)
+ (overlay-put unmatched-lines-overlay 'intangible t)
+ unmatched-lines-overlay))
+
+(defun iedit-occurrence-update (occurrence after beg end &optional change)
+ "Update all occurrences.
+This modification hook is triggered when a user edits any occurrence
+and is responsible for updating all other occurrences."
+ (when (and after (not undo-in-progress)) ; undo will do all the work
+ (let ((value (buffer-substring (overlay-start occurrence) (overlay-end
occurrence)))
+ (inhibit-modification-hooks t))
+ (save-excursion
+ (dolist (like-occurrence iedit-occurrences-overlays)
+ (if (not (eq like-occurrence occurrence))
+ (progn
+ (goto-char (overlay-start like-occurrence))
+ (delete-region (overlay-start like-occurrence)
+ (overlay-end like-occurrence))
+ (insert value))))))))
+
+(defun iedit-next-occurrence ()
+ "Move point forward to the next occurrence in the `iedit'.
+If there are no more occurrences, point stays at the last
+occurrence."
+ (interactive)
+ (let* ((occurrences iedit-occurrences-overlays)
+ (next-pos (loop for occurrence in occurrences
+ for start = (overlay-start occurrence)
+ when (< (point) start)
+ return start)))
+ (if (not (null next-pos))
+ (goto-char next-pos)
+ )))
+
+(defun iedit-prev-occurrence ()
+ "Move point backward to the previous occurrence in the `iedit'.
+If there are no more occurrences, point stays at the first
+occurrence."
+ (interactive)
+ (let* ((occurrences iedit-occurrences-overlays)
+ (prev-pos (loop for occurrence in (reverse occurrences)
+ for end = (overlay-end occurrence)
+ when (> (point) end)
+ return (overlay-start occurrence))))
+ (if (not (null prev-pos))
+ (goto-char prev-pos))))
+
+(defun iedit-toggle-unmatched-lines-visible ()
+ "Toggle whether to display unmatched lines."
+ (interactive)
+ (setq iedit-unmatched-lines-invisible (not iedit-unmatched-lines-invisible))
+ (if iedit-unmatched-lines-invisible
+ (iedit-hide-unmatched-lines)
+ (remove-overlays (point-min) (point-max) iedit-invisible-overlay-name t)))
+
+(provide 'iedit)
+
+;;; iedit.el ends here
- [nongnu] branch elpa/iedit created (now 3bd4c15e3d), ELPA Syncer, 2022/01/10
- [nongnu] elpa/iedit e9a94852d8 001/301: updates,
ELPA Syncer <=
- [nongnu] elpa/iedit 69d6c03e06 009/301: Fix syntax error, ELPA Syncer, 2022/01/10
- [nongnu] elpa/iedit 9a891d7abf 002/301: updates, ELPA Syncer, 2022/01/10
- [nongnu] elpa/iedit ec6785b0d2 008/301: host on git, ELPA Syncer, 2022/01/10
- [nongnu] elpa/iedit f808bf1ce9 012/301: Merge from lewang/master and update comments, ELPA Syncer, 2022/01/10
- [nongnu] elpa/iedit 02946e07b6 013/301: Update contributors and spell check, ELPA Syncer, 2022/01/10
- [nongnu] elpa/iedit af6d0ef70b 007/301: host on github, ELPA Syncer, 2022/01/10
- [nongnu] elpa/iedit 17e8fca7e6 011/301: Merge from tsdh/master, ELPA Syncer, 2022/01/10
- [nongnu] elpa/iedit 6d96992291 015/301: Remove duplicated comments, ELPA Syncer, 2022/01/10
- [nongnu] elpa/iedit 011e8d354c 016/301: Performance optimization of iedit-occurrence-update, ELPA Syncer, 2022/01/10
- [nongnu] elpa/iedit c8dac6bee8 020/301: exit iedit mode when change is not inside of occurrence., ELPA Syncer, 2022/01/10