Xah Talk Show 2024-09-12 Ep585, Emacs Lisp, Find and Replace in a Dir, and Undo All

emacs girl grok 2024-09-12 NwxyM
emacs girl grok 2024-09-12 NwxyM

Write a command to do find and replace all files in a dir, and a command to undo it

(defvar xx-find-replace-last-record nil "
A list, like this
(‹full-path-of-dir› ‹timestamp-string›)
both are strings.")

(defun xx-find-replace
    (FindString RelpaceString Rootdir FinenameExtRegex)
  "Find and replace all files in a dir.
Created: 2024-09-12
Version: 2024-09-12"
  (interactive)
  (let (xfilelist
        (xbackupTimestamp (format-time-string "~xfp%Y%m%d_%H%M%S~")))
    ;; algo
    ;; get a list of files in root dir
    ;; for each, open it, do find and replace
    ;; make a backup

    (setq xfilelist
          (directory-files-recursively
           Rootdir FinenameExtRegex
           nil
           (lambda (x) (not (string-match-p "/\\." x)))))

    ;; open each file
    (mapc
     (lambda (xfpath)
       (let (xfound-p)
         (with-temp-buffer
           (insert-file-contents xfpath)
           ;; do find replace
           (goto-char (point-min))
           (while (search-forward FindString nil t)
             (replace-match RelpaceString t t)
             (setq xfound-p t))

           (when xfound-p
             ;; backup
             (setq xx-find-replace-last-record (list Rootdir xbackupTimestamp))
             (copy-file xfpath (concat xfpath xbackupTimestamp) t)
             ;; save
             (write-region (point-min) (point-max) xfpath)))))
     xfilelist)))

;; HHHH---------------------------------------------------

(defun xx-find-replace-undo-last ()
  "Undo last call of `xx-find-replace'
Created: 2024-09-12
Version: 2024-09-12"
  (interactive)
  (let (xfilelist xrootdir xtimestamp)

    ;; first we need is to get the unique timestamped file names
    ;; and the root dir
    ;; then, get a list of such file names
    ;; foreach, just rename the original with it.

    (setq xrootdir (nth 0 xx-find-replace-last-record))
    (setq xtimestamp (nth 1 xx-find-replace-last-record))

    (setq xfilelist
          (directory-files-recursively
           xrootdir (regexp-quote xtimestamp)
           nil
           (lambda (x) (not (string-match-p "/\\." x)))))

    (mapc
     (lambda (x)
       (let (xorig-name)
         ;; Abbrev-Expansion.html~2024-09-12_131822_xf~
         (setq xorig-name (substring x 0 (string-match "~" x)))
         (rename-file x xorig-name t)))
     xfilelist)))

;; HHHH---------------------------------------------------
;; test

(xx-find-replace
"Manual" "xmm"
"c:/Users/xah/web/xahlee_info/talk_show/xxtest/elisp/elisp/"
"\\.html$"
)

(xx-find-replace-undo-last)