abo-abo / swiper

Ivy - a generic completion frontend for Emacs, Swiper - isearch with an overview, and more. Oh, man!
https://oremacs.com/swiper/
2.29k stars 338 forks source link

Point and mark moved after minibuffer-setup-hook run #2326

Open rschmidlin opened 4 years ago

rschmidlin commented 4 years ago

My use case is to automatically input and select the word under the cursor when calling Swiper. This is an often case for me and if I want to search for something else I can type away and my previous input gets automatically deleted.

The implementation below was working in release 0.11. and not anymore in 0.12.

It looks as if the positions of point and mark have been shifted after the execution of my function in the minibuffer-setup-hook. The shift is not consistent but often by 10 characters. Maybe it gets shifted by some of the automatic input ((1/100) Swiper: ) that is added to the beginning of the minibuffer later on?

I have tried to debug further but I'm not very proficient with Edebug.

`(defvar auto-insert-search-or-replace-commands '(query-replace query-replace-regexp swiper grep-find) "Commands to automatically insert selected \"symbol-at-point\".")

(defvar auto-insert-search-or-replace-command-strings (mapcar #'symbol-name auto-insert-search-or-replace-commands) "String of commands to automatically insert selected \"symbol-at-point\".")

(defun auto-insert-search-or-replace-insert-symbol-at-point-hook () "Insert symbol at point and select it to be immediately substitutable by the user." (when (memq (symbol-name this-command) auto-insert-search-or-replace-command-strings) (auto-insert-search-or-replace-insert-symbol-at-point-to-minibuffer)))

(defun auto-insert-search-or-replace-insert-symbol-at-point-to-minibuffer () "Get word at point in original buffer and insert it to minibuffer." (interactive) (let ((symbol nil)) (with-current-buffer (window-buffer (minibuffer-selected-window)) (setq symbol (thing-at-point 'symbol))) (insert-and-select symbol)))

(defun insert-and-select (text) "Insert TEXT and selects it." (when text (let ((begin (point))) (insert text) (set-mark begin) (setq deactivate-mark nil))))

(add-hook 'minibuffer-setup-hook 'auto-insert-search-or-replace-insert-symbol-at-point-hook)`

abo-abo commented 4 years ago

What's the difference between your code and swiper-thing-at-point or swiper-isearch-thing-at-point?

rschmidlin commented 4 years ago

Swiper-thing-at-point does not select the text it inputs--the region is not around the input text. With the text selected, as soon as I input a new character, it replaces the previous input. Hence, swiper-thing-at-point costs me a a C-backspace (or C-a C-k) more in case I want to Swiper for something else.

abo-abo commented 4 years ago

You can make use of a keyboard macro for this kind of automation:

Something like this (using https://github.com/ernstvanderlinden/emacs-dokey):

(global-set-key
 (kbd "C-c S")
 (dokey "C-s M-n C-x h C-x C-x"))
rschmidlin commented 4 years ago

Thanks for the suggestion. It is valid and I think I will go with it. However, I am curious to know what change created this issue?

abo-abo commented 4 years ago

However, I am curious to know what change created this issue?

I'm still not sure what the issue is. The behavior of swiper and swiper-isearch w.r.t. the point and the mark looks correct to me.

Could you please add a reproduction scenario with make plain and some minimal code, and key steps?

Also, you should be using ivy-hooks-alist in place of the generic minibuffer-setup-hook.

rschmidlin commented 4 years ago

Copy-and-paste the following to the scratch buffer: `(defun auto-insert-search-or-replace-insert-symbol-at-point-to-minibuffer () "Get word at point in original buffer and insert it to minibuffer." (interactive) (let ((symbol nil)) (with-current-buffer (window-buffer (minibuffer-selected-window)) (setq symbol (thing-at-point 'symbol t))) (set-mark (point)) (insert symbol) (setq deactivate-mark nil)))

(setq ivy-hooks-alist '((swiper . auto-insert-search-or-replace-insert-symbol-at-point-to-minibuffer)))`

Move the cursor to deactivate-mark. Hit C-S. You should see: 1 Swi/per: deactivate-mark/ with the text between slashes highlighted. I would expect that deactivate-mark only is selected instead.