gnu-emacs-sources
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

igrep-find-replace.el --- igrep interface for query-replace


From: Kevin A. Burton
Subject: igrep-find-replace.el --- igrep interface for query-replace
Date: 29 Oct 2001 19:06:57 -0800
User-agent: Gnus/5.0808 (Gnus v5.8.8) Emacs/21.1

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1


... Modernization and misc bug fixes.

;;; igrep-find-replace.el --- igrep interface for query-replace

;; $Id: igrep-find-query-replace.el,v 1.4 2001/10/26 06:19:59 burton Exp $

;; Copyright (C) 2000-2003 Free Software Foundation, Inc.
;; Copyright (C) 2000-2003 Kevin A. Burton (address@hidden)

;; Author: Kevin A. Burton (address@hidden)
;; Maintainer: Kevin A. Burton (address@hidden)
;; Location: http://relativity.yi.org
;; Keywords:
;; Version: 1.0.0

;; This file is [not yet] part of GNU Emacs.

;; This program 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 2 of the License, or any later version.
;;
;; This program 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
;; this program; if not, write to the Free Software Foundation, Inc., 59 Temple
;; Place - Suite 330, Boston, MA 02111-1307, USA.

;;; Commentary:
;;
;; This is a utility for igrep.  It allows you to run igrep-find and
;; 'query-replace' within all matched files.  This allows you to make major
;; changes to multiple files at once.
;;
;; The interface behaves just like 'igrep' and 'query-replace' and shouldn't
;; confuse the user with any new UI metaphor.
;;

;;; History

;; - Sat Oct 27 2001 08:32 PM (address@hidden): we are now using an
;; 'overlay-arrow' in the igrep buffer.
;;
;; - Sat Oct 27 2001 07:15 PM (address@hidden): message stating that
;; igrep-find-query-will start when igrep finishes.
;;
;; - Thu Oct 25 2001 01:15 AM (address@hidden): need a "y or n" question
;;   on the query prompt.
;;

;;; TODO:
;;
;;
;;; HIGH PRIORITY...

;; - when the file buffer (not the *igrep* buffer) shows the match near the end
;;   of beginning of the buffer, center the window so that it is more obvious 
what
;;   we are replacing.
;;
;;    - is there an easy function to do this?  maybe -recenter or something?
;; 
;;
;; - Make sure that the it is obvious what buffer we are in in the *igrep*
;;   buffer.
;;
;;     - use the secondary selection face to highlight the current line (in the
;;       *igrep* buffer) I am replacing.
;; 
;; - support the ability to replace multi-line text..
;; 
;;
;; - we need to display a NICE message if no matches were found.

;;; LOW PRIORITY...

;; - implement igrep-query-replace as well as igrep-find-query-replace.  Any
;;   other functions I should implement??  agrep, fgrep, etc?
;;
;; - for some reason I am getting this error:
;;
;;     error in process sentinel: Args out of range: 0, 6 [2 times]
;;
;; - Use an italic overlay to highlight the current line/file.
;;
;; - In long buffers, keep the current line near the top of the buffer.

(require 'igrep)

;;; Code:
(defvar ifqr-from nil "String to search and replace from.")
(make-variable-buffer-local 'ifqr-from)

(defvar ifqr-with nil "String to search and replace with.")
(make-variable-buffer-local 'ifqr-with)

(defvar ifqr-replacement-count 0 "Number of replacements for the last 
`query-replace'.")

(defvar ifqr-text-buffer-name "*ifqr-text*" "Buffer used for reading and writing
text/multiline string")

(defvar ifqr-text-replace-from nil "Search for the given text.")

(defvar ifqr-text-replace-with nil "Replace the given text.")

(defvar ifqr-text-replace-var-name nil "Var name to set.")

(defvar ifqr-text-replace-function nil "Function to eval after completion.")

(defface ifqr-line-overlay-face nil "Overlay used to highlight the current 
match.")
(set-face-background 'ifqr-line-overlay-face (face-background 
'secondary-selection))

(defvar ifqr-line-overlay (make-overlay 0 0) "Overlay used to highlight this 
match.")

(defun igrep-find-query-replace(replace-from replace-with files)
  "Use igrep-find to query and replace strings within buffers."
  (interactive

   (let(from to files)
     (setq from (read-string "Query replace: "))

     (setq to (read-string (format "Query replace %s with: " from )))

     (setq files (igrep-read-files))

     (list from to files)))

  (delete-other-windows)
  
  (let ((igrep-find t)
        igrep-args
        filename
        process)
    
    (setq igrep-args (list "grep" replace-from files))

    ;;run igrep-find...
    (igrep (elt igrep-args 0)
           (elt igrep-args 1)
           (elt igrep-args 2))
    
    (message "igrep-find-query-replace will start when igrep finishes...")

    ;;get the process created by igrep
    (setq process (get-process "igrep"))

    ;;if the process is nil... it exited quickly... process the output.
    (if process
        ;; use a process sentinel to find it.
        (progn

          ;;update buffer local variables for from/width
          (save-excursion

            (set-buffer (process-buffer process))

            (setq ifqr-from replace-from)

            (setq ifqr-with replace-with))
          
          (set-process-sentinel process 'ifqr-sentinel))

      ;;this should never happen... I think... maybe we shouldn't signal an
      ;;error though.
      (error "Unable to find process"))))

(defun ifqr-do()
  "Do the query/replace after igrep has ran saving.  Show the number of
replacements when complete. "

  ;;reset the count
  (setq ifqr-replacement-count 0)
    
  (let(filename line-number replace-from replace-with quit)
      
    (set-buffer "*igrep*")
      
    (display-buffer "*igrep*")
      
    ;;get the local replacement vars..
    (setq replace-from ifqr-from)

    (setq replace-with ifqr-with)
      
    (beginning-of-buffer)

    (forward-line 2)

    (ifqr-highlight-line (point))
    
    ;;navigate forward though the igrep buffer.
    (while (and (not quit)
                (re-search-forward "\\(^/[^:]+\\):\\([0-9]+\\):" nil t))

      (ifqr-highlight-line (point))
        
      (setq filename (match-string 1))

      (setq line-number (string-to-number (match-string 2)))
      
      (setq quit (ifqr-do-replace filename line-number replace-from 
replace-with))

      ;;return to the igrep buffer just in case.
      (set-buffer "*igrep*")

      (forward-line 1)
      (beginning-of-line)))

  (message "Replaced %i occurrences...done" ifqr-replacement-count))

(defun ifqr-do-replace(filename line-number replace-from replace-with)
  "Do a replacement on the given line number, keep doing until we are complete.
If the user select 'q' (for quit) return true, else nil. "

  ;;valid options are y/n/q
  (let(source-buffer result)

    (setq source-buffer (find-file-noselect filename))

    (set-window-buffer (other-window 0) source-buffer)
    
    (set-buffer source-buffer)
    
    (goto-line line-number)

    (beginning-of-buffer)

    (assert (search-forward replace-from nil t)
            nil (format "Could not find %s" replace-from))

    ;;highlight the match...
    (ifqr-highlight (match-beginning 0) (match-end 0))

    ;;if an error is signaled... catch it... this can happen from mouse
    ;;events/etc..
    
    (condition-case nil
        (progn

          ;;should we replace
          (if (yes-or-no-p (format "Query replacing '%s' with '%s' in %s: " 
replace-from replace-with filename))
              (progn

                (replace-match replace-with)

                ;;increment the match count...
                (setq ifqr-replacement-count (1+ ifqr-replacement-count))
                
                ;;important to save the buffer when we are done.
                (save-buffer))))
      nil)
    result))

(defun ifqr-highlight(region-start region-end)
  "Setup the mark within the given region."

  (goto-char region-start)
  (push-mark nil t t)
  (goto-char region-end))

(defun ifqr-sentinel(process event)
  "Process sentinel which detects if the igrep process is done."
  
  (if (and (string-equal (process-name process) "igrep")
           (string-match "^finished\n$" event))
      (ifqr-do)
    (message "")))

(defun igrep-find-query-replace-text()
  "Run query replace on long/text strings."
  (interactive)

  (ifqr-text-step-1))

(defun ifqr-text-step-1()
  "Get the from variable."
  
  (ifqr-read-text-string 'ifqr-text-replace-from
                         'ifqr-text-step-2
                         "(Step one) Enter the text you would like to search 
for."))

(defun ifqr-text-step-2()

  (ifqr-read-text-string 'ifqr-text-replace-with
                         'ifqr-text-do
                         "(Step two) Enter the text you would like to use as a 
replacement."))

(defun ifqr-read-text-string(var-name function message)
  "Read a text string from a buffer."

  (setq ifqr-text-replace-var-name var-name)

  (setq ifqr-text-replace-function function)
  
  (save-excursion

    (set-buffer (get-buffer-create ifqr-text-buffer-name))

    (erase-buffer)
    
    (insert (format "//REPLACE-TEXT: %s\n" message))

    (ifqr-text-entry-mode))

  (pop-to-buffer ifqr-text-buffer-name)
    
  (message message))

(defun ifqr-read-text-complete()
  "Complete text entry and continue."
  (interactive)

  (ifqr-text-cleanse-buffer)

  (delete-window (get-buffer-window ifqr-text-buffer-name))

  (funcall ifqr-text-replace-function))

(defun ifqr-text-cleanse-buffer()
  
  (save-excursion
    (set-buffer ifqr-text-buffer-name)

    (beginning-of-buffer)

    (while (re-search-forward "^//REPLACE-TEXT: .*$" nil t)
      (delete-region (match-beginning 0)
                     (1+ (match-end 0))))))

(defun ifqr-highlight-line(point)
  "Highlight the current line so that people know what the heck is going on..."
  (interactive
   (list
    (point)))
  
  (save-excursion

    (set-buffer "*igrep*")

    (let(begin end)

      (goto-char point)                 

      (setq begin (point-at-bol))

      (setq end (1+ (point-at-eol)))

      ;;update the Emacs 21 arrow...
      (let(m)
        (setq m (make-marker))

        (set-marker m begin)

        (setq overlay-arrow-position m))
      
      (move-overlay ifqr-line-overlay begin end (current-buffer))
      
      (overlay-put ifqr-line-overlay 'face 'ifqr-line-overlay-face)
      
      (overlay-put ifqr-line-overlay 'window (selected-window))

      (overlay-put ifqr-line-overlay 'priority 1)))

  (let((redisplay-dont-pause t))
    (sit-for 0)
    (redraw-frame (selected-frame))))

(define-derived-mode ifqr-text-entry-mode fundamental-mode "IGrepTextEntry"
  "Major mode with key bindings to jump to files."
  (interactive)

  (font-lock-mode 1))

;;comments
(font-lock-add-keywords 'ifqr-text-entry-mode '(("^//.*$"
                                                 (0 'font-lock-comment-face 
t))))

(define-key ifqr-text-entry-mode-map "\C-c\C-c" 'ifqr-read-text-complete)

(provide 'igrep-find-query-replace)

;;; igrep-find-replace.el ends here

- -- 
  Need a good Engineer?  Hire me!  ( Java | P2P | XML | Linux | Open Source )

                      http://relativity.yi.org/bio/

Kevin A. Burton ( address@hidden, address@hidden, address@hidden )
             Location - San Francisco, CA, Cell - 415.595.9965
        Jabber - address@hidden,  Web - http://relativity.yi.org

,@b=map{xB8,unxb8,chr($_^$a[--$h+84])address@hidden;s/...$/1$&/;$d=
unxV,xb25,$_;$b=73;$e=256|(ord$b[4])<<9|ord$b[3];$d=$d>>8^($f=($t=255)&($d
>>12^$d>>4^$d^$d/8))<<17,$e=$e>>8^($t&($g=($q=$e>>14&7^$e)^$q*8^$q<<6))<<9
,$_=(map{$_%16or$t^=$c^=($m=(11,10,116,100,11,122,20,100)[$_/16%8])&110;$t
^=(72,@z=(64,72,$a^=12*($_%16-2?0:$m&17)),$b^=$_%64?12:0,@z)[$_%8]}(16..271))
[$_]^(($h>>=8)+=$f+(~$g&$t))address@hidden"C*",@a}';s/x/pack+/g;eval

 -- Perl version of DeCSS.  

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.6 (GNU/Linux)
Comment: Get my public key at: http://relativity.yi.org/pgpkey.txt

iD8DBQE73hlRAwM6xb2dfE0RApNUAKCwSQScEaCr4LkSXlzdCyRuXBE4uwCfee4+
Wgvxb3E6FqwCfGw1oWh+ZCE=
=CoWw
-----END PGP SIGNATURE-----



reply via email to

[Prev in Thread] Current Thread [Next in Thread]