Sometimes it seems like nothing is ever easy. Follow along on my adventure in getting my $EDITOR to open markdown files.

Goal

When editing a markdown file in Obsidian sometimes I just want to open the file in a proper editor like Neovim.

Attempt 1 - Open in default app

Obsidian already has a command Open in default app. This seemed like the obvious first choice. Unfortunately to start with this just opens the file in Firefox.

What sets the program?

I suspected this was related to xdg-open. Since there are multiple ways this could work I figured a good first step would be to double check. I wanted to know what it was calling and there's (at least) two ways to do this:

BCC's execsnoop

The BPF Compiler Collection is a toolkit with a lot of useful tracing tools. The one I used was sudo execsnoop -u kenny. This can be run in any terminal and will log all programs started by any processes I own. This method is useful because it doesn't require any changes to how the program is executed. Additionally, it doesn't require the program to be restarted."

After starting execsnoop and running the Open in default app command in Obsidian I was given the following output:

xdg-mime         1176318 1176317   0 /nix/store/...-xdg-utils-1.2.1/bin/xdg-mime query filetype /home/kenny/obsidian/test.md
...
xdg-mime         1176337 1176298   0 /nix/store/...-xdg-utils-1.2.1/bin/xdg-mime query default text/markdown

strace

Unlike execsnoop the strace tool generally works best if you restart the program while wrapping it. It's not technically required, as you can attach to an existing process, but in the case of a program like Obsidian it likely already has subprocesses which complicates things.

To start Obsidian and log the commands executed I used:

strace -e execve -s 1024 -f -o /tmp/exec -- obsidian

The arguments here are:

  • -e execve - Only trace the execve syscalls (ie the ones that start processes)
  • -s 1024 - Increase the max string size to make sure commands are truncated
  • -f - Follow all child processes
  • -o /tmp/exec - Write the output to a file to review afterwards
  • -- - Ends the options for strace. Not required this time, but good practice

The output after running the command contains:

1190785 execve("/nix/store/...-xdg-utils-1.2.1/bin/xdg-mime", ["/nix/store/...-xdg-utils-1.2.1/bin/xdg-mime", "query", "filetype", "/home/kenny/obsidian/test.md"], 0xb6b7a20 /* 141 vars */ <unfinished ...>
...
1190803 execve("/nix/store/...-xdg-utils-1.2.1/bin/xdg-mime", ["/nix/store/...-xdg-utils-1.2.1/bin/xdg-mime", "query", "default", "text/markdown"], 0xb6bfda0 /* 141 vars */)

xdg-mime query

Looking at the above commands we can see that it calls xdg-mime query filetype test.md. By trying this on the command line I get back text/markdown. This is the value passed to the next query in attempting to look up the program that should be run. On my system there was no value.

To see where it's actually checking for these types I can run:

$ XDG_UTILS_DEBUG_LEVEL=2 xdg-mime query default text/markdown
Checking /home/kenny/.config/mimeapps.list
Checking /home/kenny/.local/share/applications/defaults.list and /home/kenny/.local/share/applications/mimeinfo.cache
Checking /var/lib/snapd/desktop/applications/defaults.list and /var/lib/snapd/desktop/applications/mimeinfo.cache
Checking /nix/store/...-desktops/share/applications/defaults.list and /nix/store/...-desktops/share/applications/mimeinfo.cache

There's a bunch more, but only the first one actually matters.

~/.config/mimeapps.list

Opening the mimeapps.list file I see some existing entries for Firefox in a [Default Applications] section:

[Default Applications]
x-scheme-handler/http=firefox.desktop
x-scheme-handler/https=firefox.desktop
x-scheme-handler/chrome=firefox.desktop
text/html=firefox.desktop

Seems easy enough, I added an entry for text/markdown=nvim.desktop. Now programs should use neovim to open markdown files. Testing with xdg-open test.md shows this to work

Obsidian Result

After making this change I tested it in Obsidian and... it didn't work. Using the above methods I could see that it was calling nvim test.md. This isn't right as the .desktop file contains:

Exec=nvim %F
Terminal=true

It should be run in a terminal. If I run the nvim desktop file from either the window manager or from a command line then I get a new terminal. I'm not sure if this is a bug in Obsidian or if I'm missing some other setting, but Obsidian is unfortunately closed-source (boo!), so at this point, I started looking for other options.

Attempt 2 - obsidian-open-with

Giving up on the expected solution I found the plugin obsidian-open-with. After installing it I opened the config and did an Add new application with the value:

  • Display Name: Vim
  • Path/Command: kitty
  • Arguments (optional): nvim

I clicked the little + to add it, then enabled Show in File-Menu. Now I can right-click on the file in the tree and I get the option to Open in Vim.

Conclusion

Ultimately, this solution works well, and as a bonus, I now have the correct entry in my mimeapps.list. Hopefully my steps will help someone in figuring out their own mimetype or tracing issues.