From 5712613c5d79ec8a38954043768df02292f282bb Mon Sep 17 00:00:00 2001 From: Michael Heerdegen Date: Sat, 21 May 2016 00:34:46 +0200 Subject: [PATCH] Factor out `el-search--replace-hunk' --- packages/el-search/el-search.el | 89 ++++++++++++++++++++++++--------- 1 file changed, 64 insertions(+), 25 deletions(-) diff --git a/packages/el-search/el-search.el b/packages/el-search/el-search.el index b3c58910e..d267be11e 100644 --- a/packages/el-search/el-search.el +++ b/packages/el-search/el-search.el @@ -214,6 +214,14 @@ ;; variable). The state in the current buffer is just (buffer ;; . marker). Or should this be abstracted into an own lib? Could ;; be named "files-session" or so. +;; +;; - Make `el-search--format-replacement' work non-heuristically. +;; Idea: When replacing, for every variable V bound by the search +;; pattern that directly corresponds to some text T, provide some +;; "match data" V -> T. Use this when formatting the replacement. +;; Maybe use a special marker to "paste" in expressions, like (paste +;; V), whereby the `paste' flag lands in the replacement and can be +;; replaced textually afterwards. @@ -528,6 +536,45 @@ point. Optional second argument, if non-nil, means if fail just return nil (no error)." (el-search--search-pattern-1 (el-search--matcher pattern) noerror)) +(defun el-search--replace-hunk (region to-insert) + "Replace the text in REGION in current buffer with string TO-INSERT. +Add line breaks before and after TO-INSERT when appropriate and +reindent." + (atomic-change-group + (let* ((inhibit-message t) + (opoint (point)) + (original-text (prog1 (apply #'buffer-substring-no-properties region) + (goto-char (car region)) + (apply #'delete-region region))) + ;; care about other sexps in this line + (sexp-before-us (not (looking-back "\(\\|^\\s-*" (line-beginning-position)))) + (sexp-after-us (not (looking-at "\\s-*[;\)]\\|$"))) + (insert-newline-before + (or + (and (string-match-p "\n" to-insert) + (not (string-match-p "\n" original-text)) + (or (and sexp-before-us sexp-after-us) + (looking-back + (rx (or (syntax word) (syntax symbol)) + (+ blank) + (or (syntax word) (syntax symbol)) + (* any)) + (line-beginning-position)))) + ;; (and sexp-before-us + ;; (> (+ (apply #'max (mapcar #'length (split-string to-insert "\n"))) + ;; (- (point) (line-beginning-position))) + ;; fill-column)) + )) + (insert-newline-after (and insert-newline-before sexp-after-us))) + (when insert-newline-before + (when (looking-back "\\s-+" (line-beginning-position)) + (delete-region (match-beginning 0) (match-end 0))) + (insert "\n")) + (insert to-insert) + (when insert-newline-after + (insert "\n")) + (indent-region opoint (1+ (point)))))) + (defun el-search--format-replacement (replacement original replace-expr-input splice) ;; Return a printed representation of REPLACEMENT. Try to reuse the ;; layout of subexpressions shared with the original (replaced) @@ -576,26 +623,21 @@ return nil (no error)." ((invalid-read-syntax end-of-buffer end-of-file) nil))) (setq end (point)) (setq done t))) + ;; FIXME: there could be another occurrence of THIS-SEXP in ORIG-BUFFER with more + ;; subsequent equal expressions after it (if orig-match-start - (let ((match (with-current-buffer orig-buffer - (buffer-substring-no-properties orig-match-start - orig-match-end)))) - (delete-region start end) - (goto-char start) - (when (string-match-p "\n" match) - (unless (looking-back "^[[:space:]\(]*" (line-beginning-position)) - (insert "\n")) - (unless (looking-at "[[:space:]\)]*$") - (insert "\n") - (backward-char))) - (insert match)) + (el-search--replace-hunk + (list start end) + (with-current-buffer orig-buffer + (buffer-substring-no-properties orig-match-start orig-match-end))) (goto-char start) (el-search--skip-expression nil t)) (condition-case nil (el-search--ensure-sexp-start) (end-of-buffer (goto-char (point-max)))))) - (delete-trailing-whitespace (point-min) (point-max)) ;FIXME: this should not be necessary - (let ((result (buffer-substring (point-min) (point-max)))) + (goto-char 1) + (forward-sexp) + (let ((result (buffer-substring 1 (point)))) (if (equal replacement (read result)) result (error "Error in `el-search--format-replacement' - please make a bug report")))) @@ -1062,17 +1104,14 @@ Hit any key to proceed." (progn (el-search--ensure-sexp-start) (el-search--search-pattern pattern t)) (end-of-buffer nil)))) - (do-replace (lambda () - (atomic-change-group - (apply #'delete-region region) - (let ((inhibit-message t) - (opoint (point))) - (insert to-insert) - (indent-region opoint (point)) - (el-search-hl-sexp (list opoint (point))) - (goto-char opoint))) - (cl-incf nbr-replaced) - (setq replaced-this t)))) + (do-replace + (lambda () + (save-excursion + (el-search--replace-hunk (list (point) (el-search--end-of-sexp)) to-insert)) + (el-search--ensure-sexp-start) ;skip potentially newly added whitespace + (el-search-hl-sexp (list opoint (point))) + (cl-incf nbr-replaced) + (setq replaced-this t)))) (if replace-all (funcall do-replace) (while (not (pcase (if replaced-this -- 2.39.2