5

Being fairly new to GNU Emacs and intend to use it as a replacement to vi/vim where possible, I came across an obstacle, I seem not be able to overcome.

In vim (similar to less) you can provide a command line argument to open the editor already highlighting the first occurrence of a search.

Searching my ways through man pages, reading help files, going through the built-in tutorial and looking on the net, all I found was specific line numbers (and columns) to jump to. However, what I am typically looking for is not at a line number I know of when opening files.

Is there an Emacs way to invoke an (incremental) search right at the start when opening a file, something along the way of emacs --search <search_term> <file>?

  • 1
    It doesn't seem like Emacs implements such options, but it has --eval, which can take a script to start isearch, and that can be put into a wrapper script. – DoMiNeLa10 Apr 26 at 19:20
  • Thanks. Having seen that --eval states "evaluate Emacs Lisp expression EXPR". Do you have an example for this (or a link to examples I can dive into)? I am still getting used to the editor and scripting in lisp is something I have never seen before I touched Emacs. I did manage (somehow) the startup configuration, so Emacs opens in a way I want and I understood most of what I did there. – Phoenix Apr 26 at 19:24
  • I've been trying to write such an expression, but it seems it involves some trickery with calling commands interactively. If you want some pointers, Emacs ships with info manuals for elisp. Here are online versions of these: gnu.org/software/emacs/manual/html_node/elisp/index.html gnu.org/software/emacs/manual/html_node/eintr/index.html – DoMiNeLa10 Apr 26 at 19:30
  • Thanks a lot! I will try my luck with that. If it gets too complicated (for now), I can always use emacs +$(grep -hn "<search>" <file> | head -n 1 | cut -d":" -f1) <file>. Just wanted to avoid the extra commands to get the line numbers if it would work within Emacs natively. – Phoenix Apr 26 at 19:33
4

The eval solution will work, but this is a lot of stuff to type on the command-line if you use this search frequently. We can actually change the command-line parameters so that --search <string> starts up with Emacs. Just modify your initialization file with this (if you are using lexical-binding):

(add-to-list 'command-switch-alist '("--search"  . command-line-search))

(defun command-line-search (_switch)
  (let ((search-text (pop command-line-args-left)))
    (add-hook ; Use a hook that runs after files load.  Otherwise, your CLI
              ; option will have to be given AFTER any buffers that you wish to
              ; search, which is not great.
     'window-setup-hook
     #'(lambda ()
         (isearch-forward
          nil ; This should be t if you want regex searching.
          t)  ; This must be t, or the call will block, preventing the next
              ; line.
         (isearch-yank-string search-text)))))

If you have not set lexical-binding (the default), you have to live with a global variable, but this will do the trick:

(add-to-list 'command-switch-alist '("--search"  . command-line-search))

(defvar search-text nil
  "Initial text given from the CLI that will be searched.")
(defun command-line-search (_switch)
  (setq search-text (pop command-line-args-left))
  (add-hook ; Use a hook that runs after files load.  Otherwise, your CLI option
            ; will have to be given AFTER any buffers that you wish to search,
            ; which is not great.
   'window-setup-hook
   #'(lambda ()
     (isearch-forward
      nil ; This should be t if you want regex searching.
      t)  ; This must be t, or the call will block, preventing the next line.
     (isearch-yank-string search-text))))

Now all you have to do is emacs --search <search_term> <file> like you wanted.

  • 1
    I tried your solution. After opening the file, it states Failing I-search: <pattern> and remains at the first line. I can, however, just press C-s once without entering <pattern> again and it will find the word immediately. So, it works half way. Not sure why it states initially that it fails though. I tried isearch-backward in case the search was already past the word within the file, but I had the same result when opening again. The function to add this as a command-line switch is absolutely stunning though. Would like to see it work for me. – Phoenix Apr 27 at 16:49
  • Hmm, I will try some debugging a bit later. Does it show the correct search term when it fails at first? – cyberbisson Apr 27 at 16:59
  • Yep. It does. That is why it puzzles me. It highlights the search term in red (as if the word was not found in its entirety). And when I press C-s, it just finds and highlights the word inside the file. The echo area states Overwrapped I-search: <pattern>, however, which is why I tried isearch-backward as I assumed that point was past the word I searched for (but same result there). – Phoenix Apr 27 at 17:04
  • It's an ordering problem. I'll update the code. Basically, the search is running before the buffer loads if you specify the parameter before it on the CLI. We'll delay the execution of the search until emacs fully starts... – cyberbisson Apr 27 at 17:17
  • 1
    Let us continue this discussion in chat. – Phoenix Apr 27 at 17:43
3

According to Preset search isearch-string from command line, you can search for PATTERN with Isearch programmatically using:

(isearch-forward nil t)
(isearch-yank-string "PATTERN")

So open FILE and search for PATTERN:

$ emacs FILE --eval '(isearch-forward nil t)'  --eval '(isearch-yank-string "PATTERN")'

And if you put the following in your init file

(defun my-search-for (pattern)
  "Search for PATTERN with Isearch."
  (interactive "sSearch for: ")
  (isearch-forward nil t)
  (isearch-yank-string pattern))

you can also type less from the command line

$ emacs FILE --eval '(my-search-for "also")'
  • Trying your second part of it: While initially working (it finds the item of interest), when closing FILE, it opens a buffer for pattern. So, something is off and I cannot pin-point it. Do you have any idea of what is happening? – Phoenix Apr 27 at 16:35
  • Correction: I made a mistake in the script calling it. Using your example, it opens the scratch buffer (default for me) with the message in the echo area Symbol’s value as variable is void: <pattern> where <pattern> is the word I was looking for. – Phoenix Apr 27 at 16:42
  • @Phoenix You missed the double-quotes around <pattern>. The right command line in your case is: emacs FILE --eval '(my-search-for "<pattern>")' – Tobias Apr 27 at 23:10
  • Thanks! I will give it another try once back at that computer. As my pattern can be provided through a variable, I will try not to use the single quotations and instead see about escaping the ones around the variable. – Phoenix Apr 27 at 23:17
  • @Tobias, just tested it and I can now confirm that with (escaped) quotations around the pattern, it will work. While I like the other provided solution better and will keep it as accepted answer, I still added this to my Emacs init file, so I can use this alternative as well. Thanks for pointing out the missing quotations! – Phoenix Apr 28 at 0:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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