macvim-dev / macvim

Vim - the text editor - for macOS
https://macvim.org
Vim License
7.51k stars 683 forks source link

Feature Request: detect and reuse MacVim instance to open file by mvim:// url #1402

Open UncleBill opened 1 year ago

UncleBill commented 1 year ago

Greeting!

I configure mvim:// in React Developer Tools to open file in MacVim from the browser extension.

mvim://open?url=file://{path}&line={line}
image

It works good, but there's a small issue. The issue is that MacVim doesn't reuse the instance that I opened if the target file hasn't been opened. For example, I launch MacVim from /path/to/my-project, and I open files /path/to/my-project/{a,b,c}.js from React Developer Tools. They have different results:

file is editing or has been opened result
a.js editing 😃 get opened in the right instance
b.js has been opened 😃 ditto
c.js neither 💔 get opened in a new instance

I hope the c.js can be opened like a.js and b.js.

I have a workaround in favor of Raycast Script Command deeplinks. My script launch MacVim with specified servername, the launched instance will be reuse if I execute the script again. Here it is (I have multiple ones generated by another script):

#!/bin/bash

# Required parameters:
# @raycast.schemaVersion 1
# @raycast.title Vim Launch
# @raycast.mode silent
# Optional parameters:
# @raycast.icon ✅
# @raycast.packageName vim-launch
# @raycast.argument1 { "type": "text", "placeholder": "file path", "optional": true }
# @raycast.argument2 { "type": "text", "placeholder": "line number", "optional": true }

# Documentation:
# @raycast.description Open vim startify session

export PATH=/Applications/MacVim.app/Contents/bin:$PATH

open_file()
{
    if [[ -n $1 ]]; then
      mvim --servername THE_SERVER_NAME --remote-send "<c-w>:tabedit $1<CR>"
    fi
    if [[ -n $2 ]]; then
      mvim --servername THE_SERVER_NAME --remote-send "$2G"
    fi
}

SERVERS=`mvim --serverlist | grep -i THE_SERVER_NAME | awk '{print tolower($0)}'`
for server in $SERVERS; do
  if [[ $server == "THE_SERVER_NAME" ]];
  then
    osascript >/dev/null <<END
      tell application "System Events" to tell process "MacVim"
        set frontmost to true
        windows where title ends with "THE_SERVER_NAME"
        if result is not {} then perform action "AXRaise" of item 1 of result
      end tell
END
    open_file $1 $2
    exit 0
  fi
done

LANG=en_US.UTF-8 mvim --servername THE_SERVER_NAME +SLoad\ THE_SERVER_NAME >/dev/null 2>&1
# wait for server registration
sleep 1
open_file $1 $2

With this script, I replace mvim:// url with Raycast's deeplink:

raycast://script-commands/vim-launch?arguments={path}&arguments={line}

It's fixed! However it would be better to have native support in MacVim.

I would suggestion to add feature to detect the instance I want to open file with (like if the opening file path is in the working directory of an instance, the closest one), or add another parameter to specified the instance.

Thanks!

eirnym commented 1 year ago

Thank you for sharing

What do you mean with "MacVim doesn't reuse old instance"?

My the only guess "MacVim opens a new window", is it correct? If my guess is correct, please, look into preferences, "open from applications" and report if it's working correctly.

UncleBill commented 1 year ago

My the only guess "MacVim opens a new window", is it correct

Yes. That's correct.

look into preferences, "open from applications" and report if it's working correctly.

Thanks for this suggestion. I set it to "in the current window". But it might be wrong if I have multiple MacVim windows opened.

eirnym commented 1 year ago

I personally prefer, that opens a new window instead of a tab or a buffer.

ychin commented 1 year ago

I set it to "in the current window". But it might be wrong if I have multiple MacVim windows opened.

Right. How would you expect the mvim:// protocol to be able to determine which window then? By servername? I could see extending the protocol handler to take in a "servername" argument (it currently only takes "line" and "column" URL arguments).

UncleBill commented 1 year ago

@ychin Thanks for you reply.

How would you expect the mvim:// protocol to be able to determine which window

My idea is to compare the working directories of each windows and find the closest one. For example, having three windows: WIN1 (CWD is /path/to/project1), WIN2 (CWD is /path/to/project2), and WIN3 (CWD is /path/to/project2/subproject/) then

open url result
mvim://open?url=file:///path/to/project1/file WIN1
mvim://open?url=file:///path/to/project2/file WIN2
mvim://open?url=file:///path/to/project1/subproject/file WIN3

By servername? I could see extending the protocol handler to take in a "servername" argument (it currently only takes "line" and "column" URL arguments).

Looks reasonable and it's explicit. Hope to see this feature implemented, and comparing working directories could be optional.

ychin commented 1 year ago

My idea is to compare the working directories of each windows and find the closest one. For example, having three windows: WIN1 (CWD is /path/to/project1), WIN2 (CWD is /path/to/project2), and WIN3 (CWD is /path/to/project2/subproject/) then

I think this could get complicated really quickly and will be very specific to an individual's workflow. First, Vim has three levels of "current directory": global (:cd), tab-level (:tcd), and local (:lcd). I think a lot of the times the user may not remember which one is which. Worse is that as you switch to different windows/tabs, the "current directory" will be different as well if the user is using tab-level or local current directories.

Also, sometimes Vim users can be using CWD /a/b/c/foo but editing /bar/some/file.txt. I think there could be a lot of counter-intuitive behaviors for relying on things like that.

By servername? I could see extending the protocol handler to take in a "servername" argument (it currently only takes "line" and "column" URL arguments).

Looks reasonable and it's explicit. Hope to see this feature implemented, and comparing working directories could be optional.

I'm more inclined to include this option as it's explicit and allows you to structure your workflow as needed.

UncleBill commented 1 year ago

I'm more inclined to include this option as it's explicit and allows you to structure your workflow as needed.

OK. That will be fine. Thanks. ❤️