Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

executable file 93 lines (84 sloc) 3.533 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
;;;; -*- Mode: Emacs-Lisp -*-

;;; This file implements a set of functions for replacing symbols
;;; within a sexp or a buffer. A symbol for this purpose is anything
;;; for which (progn (forward-sexp) (backward-sexp)) is idempotent and
;;; for which (progn (down-list) (backward-up-list)) is *not*
;;; idempotent. It is case sensitive at the moment, but that may
;;; change in the future.

;;; I have used this to rename variables, functions, types, &c. in
;;; both Lisp and C. Your mileage may of course vary.

;;; This file was written by Brian Mastenbrook (brian AT mastenbrook
;;; DOT net) and is placed in the public domain.

;;; M-x replace-symbol-in-sexp from to
;;; M-x replace-symbol-in-buffer from to

(defun replace-symbol-in-sexps-until-error (from to)
  ;; used for replacing all the sexps inside of a list. when a
  ;; scan-error is caught, we return.
  (condition-case c
      (while t
        (replace-symbol-in-sexp from to t)
        (forward-sexp))
    (scan-error nil)))

(defun beginning-of-list-p ()
  (save-excursion
    (condition-case c
        (progn
          (forward-sexp)
          (backward-sexp)
          (let ((point-1 (point)))
           (down-list)
           (backward-up-list)
           (forward-sexp)
           (backward-sexp)
           (eq (point) point-1)))
      (scan-error nil))))

(defun replace-symbol-in-sexp (from to &optional recursive)
  (interactive "sReplace symbol: \nsReplace symbol %s with: ")
  (let ((do-replace
         (lambda ()
           (save-excursion
             (forward-sexp)
             (backward-sexp)
             ;; the combination of those two puts us on the first character
             ;; of the sexp
             (cond
              ((beginning-of-list-p)
               ;; we're sitting on the beginning of a list
               (down-list) ; travel into the sexp and replace inside
               (replace-symbol-in-sexps-until-error from to))
              (t (let ((beginning-of-sexp (point))
                       (end-of-sexp 0))
                   (forward-sexp)
                   (setq end-of-sexp (point))
                   (backward-sexp)
                   ;; we get these values for the beginning and end of the
                   ;; sexp so we can compare and delete it
                   (if (string-equal (buffer-substring beginning-of-sexp
                                                       end-of-sexp) from)
                       (progn
                         (delete-region beginning-of-sexp end-of-sexp)
                         (insert to)
                         (setq replaced-in-sexp (1+ replaced-in-sexp)))
                     nil))))))))
    (if recursive
        (funcall do-replace)
      (let ((replaced-in-sexp 0))
        (funcall do-replace)
        (unless recursive
          (message "Replaced %s occurrence%s"
                   replaced-in-sexp
                   (if (eq replaced-in-sexp 1) "" "s")))))))

(defun replace-symbol-in-buffer (from to)
  (interactive "sReplace symbol: \nsReplace symbol %s with: ")
  (let ((replaced-in-sexp 0))
    (save-excursion
      (goto-char (point-min))
      (condition-case c
          (while (not (eq (point-max) (point)))
            (replace-symbol-in-sexp from to t)
            (forward-sexp))
        (scan-error nil)))
    (message "Replaced %s occurrence%s"
             replaced-in-sexp
             (if (eq replaced-in-sexp 1) "" "s"))))

(provide 'refactor)
Something went wrong with that request. Please try again.