In that case, the patch becomes much more complicated. We have to modify the query-replace-map in replace.el itself as we cannot access the internal variables required to printed this message in isearch-style with (sit-for 1): (message query-replace-in-progress-message (query-replace-descr from-string) (query-replace-descr replacement-presentation) query-message-momentary) Here: from-string, replacement-presentation are internal variables and cannot be used in a function defined outside that (cond ..) form. So the earlier approach to define a function externally to toggle the case and to bind that to query-replace-map from outside does not apply (if we want to flash the case fold toggle info momentarily as done in isearch). Even the replacement-presentation was in a (let .. ) form not accessible to the (cond ..) form and so I moved it to an outer (let ..) form as seen in the below patch. I tested this out and the M-c and M-r bindings work great. It now also gives clear info on what the user should expect after that binding is used. Please give it a try. I have still kept this line (def (call-interactively def)) ; User-defined key, invoke it. as it could be useful to bind any other function from outside that does not need internal variables. --- replace.el 2015-06-02 23:21:42.631715000 -0400 +++ replace-editted.el 2015-06-02 23:32:47.754001000 -0400 @@ -1834,6 +1834,8 @@ (define-key map [M-next] 'scroll-other-window) (define-key map [?\C-\M-\S-v] 'scroll-other-window-down) (define-key map [M-prior] 'scroll-other-window-down) + (define-key map "\M-c" 'toggle-query-case) + (define-key map "\M-r" 'toggle-replace-preserve-case) ;; Binding ESC would prohibit the M-v binding. Instead, callers ;; should check for ESC specially. ;; (define-key map "\e" 'exit-prefix) @@ -2100,12 +2102,14 @@ ;; (match-data); otherwise it is t if a match is possible at point. (match-again t) - (message + (query-replace-in-progress-message (if query-flag (apply 'propertize (substitute-command-keys - "Query replacing %s with %s: (\\\\[help] for help) ") - minibuffer-prompt-properties)))) + (concat "Query replacing %s with %s: " + "(\\\\[help] for help) %s ")) + minibuffer-prompt-properties))) + (query-message-momentary "")) ;; If region is active, in Transient Mark mode, operate on region. (if backward @@ -2251,7 +2255,7 @@ noedit real-match-data backward) replace-count (1+ replace-count))) (undo-boundary) - (let (done replaced key def) + (let (done replaced key def replacement-presentation) ;; Loop reading commands until one of them sets done, ;; which means it has finished handling this ;; occurrence. Any command that sets `done' should @@ -2266,17 +2270,18 @@ regexp-flag delimited-flag case-fold-search backward) ;; Bind message-log-max so we don't fill up the message log ;; with a bunch of identical messages. - (let ((message-log-max nil) - (replacement-presentation - (if query-replace-show-replacement - (save-match-data - (set-match-data real-match-data) - (match-substitute-replacement next-replacement - nocasify literal)) - next-replacement))) - (message message + (let ((message-log-max nil)) + (setq replacement-presentation + (if query-replace-show-replacement + (save-match-data + (set-match-data real-match-data) + (match-substitute-replacement next-replacement + nocasify literal)) + next-replacement)) + (message query-replace-in-progress-message (query-replace-descr from-string) - (query-replace-descr replacement-presentation))) + (query-replace-descr replacement-presentation) + query-message-momentary)) (setq key (read-event)) ;; Necessary in case something happens during read-event ;; that clobbers the match data. @@ -2404,6 +2409,51 @@ (replace-dehighlight) (save-excursion (recursive-edit)) (setq replaced t)) + + ((eq def 'toggle-query-case) + (setq case-fold-search (not case-fold-search)) + (let ((message-log-max nil) + (query-message-momentary + (concat "[" + (if case-fold-search + "case insensitive search" + "Case Sensitive Search") + "]"))) + (message query-replace-in-progress-message + (query-replace-descr from-string) + (query-replace-descr replacement-presentation) + query-message-momentary) + (sit-for 1))) + + ((eq def 'toggle-replace-preserve-case) + (let ((message-log-max nil) + (nocasify-value-reason "") + query-message-momentary) + (setq nocasify (not nocasify)) + (cond + ((null case-fold-search) + (setq nocasify nil) + (setq nocasify-value-reason ", as case-fold-search is nil")) + ((null (isearch-no-upper-case-p from-string regexp-flag)) + (setq nocasify nil) + (setq nocasify-value-reason ", as FROM-STRING has an upper case char.")) + ((null (isearch-no-upper-case-p next-replacement regexp-flag)) + (setq nocasify t) + (setq nocasify-value-reason ", as REPLACEMENT has an upper case char."))) + (setq query-message-momentary + (concat "[Replaced text case will " + (if nocasify "NOT " "") + "be preserved" + nocasify-value-reason + "]")) + (message query-replace-in-progress-message + (query-replace-descr from-string) + (query-replace-descr replacement-presentation) + query-message-momentary) + (sit-for 1.5))) + + (def (call-interactively def)) ; User-defined key, invoke it. + ;; Note: we do not need to treat `exit-prefix' ;; specially here, since we reread ;; any unrecognized character. On Tue, Jun 2, 2015 at 6:51 PM Drew Adams wrote: > > > + ;; Show whether `case-fold-search' is `t' or `nil' > > > + (if case-fold-search "[case] " "[CaSe] ") > > > > Maybe we should use the same message about case-folding like in > > isearch? > > The msg should somehow indicate that what is involved here is (only) > case-sensitivity wrt FROM (i.e., wrt search, not replacement). Not > sure what the best way to do that would be. > > IOW, there is more than one use of case sensitivity here, unlike > the case for search. There is what `case-fold-search' controls (the > search), and there is what `case-replace' controls (the replacement). > And then there is what happens for the replacement according to the > case of FROM. > > --- > > BTW, we might consider binding a key to toggle case sensitivity for > search as part of this bug fix (i.e., not just fixing `perform-replace' > so it respects keys that user might bind). In that case, maybe the > same key we use in Isearch (`M-c') would be a good choice. > > --- > > BTW2, I think that Emacs manual node `Replacement and Case' is confusing. > The first three paragraphs (2/3 of the node), for instance: > > If the first argument of a replace command is all lower case, the > command ignores case while searching for occurrences to > replace--provided `case-fold-search' is non-`nil'. If > `case-fold-search' is set to `nil', case is always significant in all > searches. > > An upper-case letter anywhere in the incremental search string makes > the search case-sensitive. Thus, searching for `Foo' does not find > `foo' or `FOO'. This applies to regular expression search as well as > to string search. The effect ceases if you delete the upper-case > letter from the search string. > > If you set the variable `case-fold-search' to `nil', then all > letters must match exactly, including case. This is a per-buffer > variable; altering the variable normally affects only the current > buffer, unless you change its default value. *Note Locals::. This > variable applies to nonincremental searches also, including those > performed by the replace commands (*note Replace::) and the minibuffer > history matching commands (*note Minibuffer History::). > > These paragraphs really say only that the search part of replace commands > acts normally: `case-fold-search' governs. They should be removed or > changed to say just that. Leaving them as they are just confuses readers, > IMO. >