dajva / rg.el

Emacs search tool based on ripgrep
https://rgel.readthedocs.io
GNU General Public License v3.0
465 stars 38 forks source link

Any reason of adding `.` at the end of command on Windows? #169

Open chansey97 opened 2 months ago

chansey97 commented 2 months ago

I saw in rg.el there are the following lines

(when (member system-type '(darwin windows-nt))
  (list ".")))))

Anyone know why need this . thing on Windows (and Mac OS)?

First of all, it seems that at the moment we have to use the . on Windows, otherwise rg.el won't display anything. It has little to do with rg.el though, I still want to discuss.

Let's do some experiments via clean Emacs interface:

  1. Try the following three commands (no .) in Windows standard console

    ...> "C:/env/ripgrep/ripgrep-14.1.0-x86_64-pc-windows-msvc/rg.exe" SomeTextInFiles
    ...> "cmd.exe" /c "C:/env/ripgrep/ripgrep-14.1.0-x86_64-pc-windows-msvc/rg.exe SomeTextInFiles"
    ...> "C:/green/emacs/libexec/emacs/28.2/x86_64-w64-mingw32/cmdproxy.exe" -c "C:/env/ripgrep/ripgrep-14.1.0-x86_64-pc-windows-msvc/rg.exe SomeTextInFiles"

    All work, i.e. they can display results in the console.

  2. Try the same command (no .) in Emacs with start-process

    (apply 'start-process "rg" "newbuffer123"
          "C:/green/emacs/libexec/emacs/28.2/x86_64-w64-mingw32/cmdproxy.exe"
          (list "-c" "\"C:/env/ripgrep/ripgrep-14.1.0-x86_64-pc-windows-msvc/rg.exe\" SomeTextInFiles"))

    This doesn't work, i.e. it displayed nothing in "newbuffer123" (also for rg.exe only and cmd.exe /c).

  3. The way to fix this problem is adding . at the end of command, i.e.

    (apply 'start-process "rg" "newbuffer123"
          "C:/green/emacs/libexec/emacs/28.2/x86_64-w64-mingw32/cmdproxy.exe"
          (list "-c" "\"C:/env/ripgrep/ripgrep-14.1.0-x86_64-pc-windows-msvc/rg.exe\" SomeTextInFiles ."))

    Then works, but why?

  4. Not all of the ripgrep commands can't display, -h can do for example:

    (apply 'start-process "rg" "newbuffer123"
          "C:/green/emacs/libexec/emacs/28.2/x86_64-w64-mingw32/cmdproxy.exe"
          (list  "-c" "\"C:/env/ripgrep/ripgrep-14.1.0-x86_64-pc-windows-msvc/rg.exe\" -h"))

    This can display help information in "newbuffer123"

I found this patch was added by @drvink from https://github.com/dajva/rg.el/pull/10 but no explanation. Also, there are two related commits https://github.com/dajva/rg.el/commit/842452ccb9bba80582c13fb309bebdb399c1e890 and https://github.com/dajva/rg.el/commit/89343e9858787fa8d3651cd03ff7b0d03309dee8.

Nevertheless, the . solution works fine, until someone want to add rg-command-line-flags to rg.el.

For example, suppose I'd like to search only two specific directories under the current directory (multiple directories search):

(defun test-rg ()
  (interactive)
  (let ((rg-command-line-flags '("\"./folder1\" \"./folder2\"")))
    (call-interactively 'rg)))

In the current rg.el implementation, these two directories will be combined with the current directory (i.e. .), which causes these two flags meaningless, i.e. it still searches the entire current directory.

Of course, this problem can be workaround via deleting (list ".") in the code above, but that breaks the code.

So anyone know why we have to add . on Windows (and Mac)? Is this related to Emacs or ripgrep?

Thanks.

chansey97 commented 2 months ago

I think I know what happened here:

When the command-line arguments did not explicitly indicate the search path (e.g. . or ./), ripgrep would use a heuristic to guess users' intention, i.e. whether searching in the current directory or in stdin via a pipe, see hiargs.rs#L1104 and lib.rs#L170. Unfortunately, on Windows (might be also on Mac), ripgrep guesses "users want to search in stdin via a pipe", so Emacs process hangs.

A simple experiment to make the above process code work:

(let ((p (apply 'start-process "rg" "newbuffer123"
                "C:/env/ripgrep/ripgrep-14.1.0-x86_64-pc-windows-msvc/rg.exe"
                (list "SomeTextInFiles"))))
  (process-send-string p "1. SomeTextInFiles1\nxxxxxx\n2. SomeTextInFiles2\nyyyyy\n3. SomeTextInFiles3\n")
  (process-send-eof p))

This code work, Emacs can display the result.

1. SomeTextInFiles1
2. SomeTextInFiles2
3. SomeTextInFiles3

Process rg<1> finished

However as you see that, ripgrep searched "SomeTextInFiles" in the string content, i.e. "1. SomeTextInFiles1\nxxxxxx\n2. SomeTextInFiles2\nyyyyy\n3. SomeTextInFiles3\n" instead of directory.


Some suggestions:

  1. Make the command-line consistent on Windows, Linux and Mac OS, i.e. explicitly provide the search path instead of leaving ripgrep to guess. Remove (member system-type '(darwin windows-nt)) condition.
  2. The search path (or "multiple directories search") should be implemented as a separate feature instead of hardcoded as . or added through rg-command-line-flags.
drvink commented 2 months ago

Yes, @chansey97's description is what my fix was for.