

(defvar last-search "")
(defvar last-replace "")
(defvar last-wordonly nil)
(defvar last-noask nil)

(defun mqr-read-default (prompt old)
  (let ((new (read-string (format "%s [%s]: " prompt old))))
    (if (string-equal "" new)
	old new)))


(defun my-query-replace ()
  (interactive)
  (setq last-search (mqr-read-default "Search for" last-search))
  (setq last-replace (mqr-read-default "Replace with" last-replace))
  (let* ((options (mqr-read-default "Options" ""))
	 (noask (string-match "n" options))
	 (global (string-match "g" options))
	 (wordonly (string-match "w" options))
	 (count (if (string-match "[0-9]+" options)
		    (string-to-int (substring options (match-beginning 0) (match-end 0)))
		  nil)))
    (setq last-wordonly wordonly)
    (setq last-noask noask)
    (if global
	(progn
	  (push-mark)
	  (goto-char (point-min))))
    (my-do-replace count)))

(defun my-do-replace (count)
  (interactive "p")
  (catch 'quit 
    (let (p
	  (noask last-noask))
      (while (or (not count) (> count 0))
	(while (progn
		 (search-forward last-search)
		 (setq p (point))
		 (goto-char (- (point) (length last-search)))
		 (if (and last-wordonly (not (looking-at "\\b")))
		     (goto-char p)
		   nil)))
	(if
	    (if noask
		(progn (sit-for 0) t)
	      (let (ch)
		(while (progn
			 (message "Replace? (y/n/q/g) ")
			 (setq ch (read-char))
			 (if (eq ch ? ) (setq ch ?y))
			 (not (or (eq ch ?y) (eq ch ?n) (eq ch ?q) (eq ch ?g)))))
		(cond
		 ((eq ch ?y) t)
		 ((eq ch ?n) nil)
		 ((eq ch ?g) (setq noask t) t)
		 ((eq ch ?q) (throw 'quit nil)))))
	    (progn
	      (delete-region (point) p)
	      (insert last-replace))
	  (goto-char p))
	(if count (setq count (1- count)))))))

