0

Say I have this text:

|Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Where the | is the cursor, at the beginning of the line. I want to jump to the next occurrence of the sequence "met", so I do an isearch-forward (C-s). If I type "met" and then RET, the text is found, but the cursor is left in this position:

Lorem ipsum dolor sit amet|, consectetur adipiscing elit.

Instead, I want it to be at the beginning of the matched text (like with Avy), so

Lorem ipsum dolor sit a|met, consectetur adipiscing elit.

Is this possible? How?


EDIT: I have been noticed that is not desirable to change the behavior of a so basic function, so that I would have needed to explain my original question to avoid the XY problem. I want to jump to the next occurrence of some substring in text to insert LaTeX macros. For this purpose, I need to be left at the beginning of the text, not the end. Avy brilliantely solves the problem, but I always need to select what occurrence I am referring to: in my case, I want to go to the next occurrence of the string after point. I need, in a sense, to combine the functionalities of Isearch and Avy.

7
  • 5
    You can do a C-r before the RET.
    – NickD
    Commented Oct 30, 2022 at 16:36
  • I suspect this question is a dup...
    – Drew
    Commented Oct 30, 2022 at 22:19
  • @NickD thanks! But how can I make it automatic? I've tried advice-add and defining a new function, but it doesn't work. Maybe am I doing something wrong with isearch-mode-map? @Drew sorry if it's a dup, my Google-fu couldn't provide an answer. Can you point me to an already existing answer source? Commented Oct 30, 2022 at 23:09
  • 1
    (defun _isearch-repeat-backward (&rest _) (isearch-repeat-backward)) and then (advice-add 'isearch-exit :before #'_isearch-repeat-backward) works (for some value of "works"), It works in the simple case where the search is successful, but It gets really confusing when you try to exit from an unsuccessful search. My question is: why do you want this behavior? The standard behavior is carefully thought out and I think you are better off NOT changing it. But if you can describe the use case, somebody might have a better idea of how to do what you want.
    – NickD
    Commented Oct 31, 2022 at 1:22
  • You're right, I have updated the question, so that's more clear Commented Oct 31, 2022 at 10:42

1 Answer 1

0

Keep cursor at beginning of isearch result

Here's what I use. It moves the cursor to the beginning of the result every time the result is updated. That way, you can always move to a precise location when searching forward. The cursor will always be at the beginning of your search result, and typing more characters to narrow the result won't change where the cursor lands.

Source: Endless Parentheses

(defun endless/goto-match-beginning ()
  "Go to the start of current isearch match.
Use in `isearch-mode-end-hook'."
  (when (and (not (eq this-command 'isearch-exit))
         isearch-forward
             (number-or-marker-p isearch-other-end)
             (not mark-active)
             (not isearch-mode-end-hook-quit))
    (goto-char isearch-other-end)))

;; Keep cursor at start of search result.
(add-hook 'isearch-update-post-hook
          #'endless/goto-match-beginning)

Exiting the search with <return> or an edit command

Once your cursor reaches the desired location, you can exit isearch with the "<return>" key and make whatever changes you wanted to make there. In addition, the use of any keybinding which is not in isearch-mode-map will exit isearch without you having to press "<return>" at all. So you can jump to a spot and use "C-d", "C-t", "C-k", etc. without having to explicitly exit isearch-mode first.

One thing I noticed was that "M-c" is bound to isearch-toggle-case-fold in isearch-mode-map, but that command has a duplicate binding at "M-s c". "M-c" conflicts with capitalize-word (or capitalize-dwim if you prefer). So I removed the "M-c" binding, and now I can exit isearch with any of the letter-case bindings ("M-u", "M-l" and "M-c").

(define-key isearch-mode-map (kbd "M-c") nil)

As far as I can tell, this leaves "C-w" and "C-y" as the only keys left in isearch-mode-map that conflict with editing commands bound in the global-map. So if you want to cut or paste, you'll have to exit isearch-mode first. But you can do any other type of edit as soon as the cursor lands there.

Exiting at the beginning or end of the search result

But what if you do want to explicitly exit isearch-mode before proceeding? And what if sometimes you want to exit with point at the beginning of the result (which we just ensured), but also sometimes you want to exit at the end?

Emacs's default approach requires moving to the other end of the result before exiting the search. But why not do that in one keypress instead of two?

(defun my-isearch-bor-exit ()
  "Ensure point is at beginning of isearch result and exit."
  (interactive)
  (when (< isearch-other-end (point))
    (goto-char isearch-other-end))
  (call-interactively 'isearch-exit))

(defun my-isearch-eor-exit ()
  "Ensure point is at end of isearch result and exit."
  (interactive)
  (when (>= isearch-other-end (point))
    (goto-char isearch-other-end))
  (call-interactively 'isearch-exit))

(define-key isearch-mode-map (kbd "C-m") 'my-isearch-bor-exit) ; left
(define-key isearch-mode-map (kbd "<return>") 'my-isearch-eor-exit) ; right

The "<return>" keybinding will probably not work if you use Emacs in a terminal, though it works fine in the GUI. In a terminal, "C-m" represents the return key. So if you will ever use Emacs in a terminal, pick a different key besides "<return>" for exiting at the end of the result.

2
  • 1
    Thanks! Following your link to Endless Parentheses I also found that the shorter (defun isearch-exit-other-end () "Exit isearch, at the opposite end of the string." (interactive) (goto-char isearch-other-end) (isearch-exit)) is good for my use case, so I'll directly use that. I don't know if that is less robust. In case it's not (and so it's also useful for others) could you please add it to your answer? Commented Oct 31, 2022 at 11:14
  • 1
    It's just a matter of preference and flexibility. The command you are using is a toggle. But if you're sure you'll keep using the method that keeps the cursor at the beginning while you search, then functionally the result will be the same. I wanted the two solutions to be independent of each other. In case I changed my mind about the first feature, I'd still be able to use the new commands without retraining myself. Commented Oct 31, 2022 at 12:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.