Obsidian’s Vim features are quite powerful, and in some cases more capable than one could imagine. I can map both simple and complex key mappings and even record macros for some really useful stuff (e.g. “jump to next Markdown headline”).
However, all these things are non-persistent. AFAIK there’s no way to load my favorite mappings and macros from file on startup, and I need to redo them every time I launch Obsidian.
It would really be a useful if Obsidian could load a simple .vimrc-like file with supported commands, or if I could enter some default commands in the configuration to load on startup.
This is exactly what I was thinking. a .vimrc type of file would be ideal but perhaps complicated to integrate fully specially for things like plug-ins
but what you said on recording macros would be ideal and super helpful. I agree with you, hopefully this is something that’ll be possible in the future of obsidian!
I’m not expecting Obsidian to be an IDE or a fancy editor for text files – for that I have the real Vim So an actual .vimrc file with some support of Vim plugins is a little over the top IMHO.
But since the Vim mode exists and is already so useful, but limited due to nothing being permanent, my request is only to be able to load already-supported commands on startup. Modest, I hope
I spent some time playing around with the temporary Volcano plugin loader for Obsidian, and figured it’s actually very easy to make this Vimrc feature happen!
So no guarantees whatsoever, but the following seems to work (I called it vimrc.js under ~/volcano/plugins):
class VimrcLoader {
constructor() {
this.id = 'vimrc-loader';
this.name = 'Vimrc loader plugin';
this.description = 'Auto-loader for Obsidian Vim commands on startup.';
this.defaultOn = true; // Whether or not to enable the plugin on load
}
init(app, instance) {
this.app = app;
this.instance = instance;
this.enabled = false;
}
onEnable(app, instance) {
instance.registerEvent(app.workspace.on("file-open", this.onFileOpen, this));
this.enabled = true;
}
onDisable(app, instance) {
this.enabled = false;
}
async onFileOpen(file) {
var activeView = this.app.workspace.activeLeaf.view;
const FILE_NAME = ".obsidian.vimrc";
if (this.enabled && activeView && activeView.sourceMode) {
var cmEditor = activeView.sourceMode.cmEditor;
var vaultPath = this.app.vault.adapter.basePath;
var configPath = require('path').join(vaultPath, FILE_NAME);
this.readVimInit(configPath);
}
}
readVimInit(filePath) {
var fs = require("fs");
var cmEditor = this.app.workspace.activeLeaf.view.sourceMode.cmEditor;
fs.readFileSync(filePath).toString().split("\n").forEach(
function(line, index, arr) {
if (line.length > 0) {
CodeMirror.Vim.handleEx(cmEditor, line)
}
}
);
}
}
module.exports = () => new VimrcLoader()
Example .obsidian.vimrc file (in the vault root):
nmap H ^
nmap L $
nmap j gj
nmap k gk
nmap <F9> :nohl
Notes:
You’d need your Vim commands file to be named VAULT_ROOT/.obsidian.vimrc. I’d prefer this file to reside in the Obsidian config directory but I couldn’t find a portable way to get it from the app object.
The vimrc is loaded every time a file is loaded in Obsidian. It might be better to do it just once.
The vimrc parsing is extremely simplistic, every line is sent as-is to the CodeMirror Ex-command parser. So even standard Vim comments would generate an error.
Speaking about errors, they are not properly reported anywhere.
There are probably many other gotchas, I just hacked this together rather quickly to get it working and I don’t really know what I’m doing
The core functionality of CodeMirror’s Vim support is very far from allowing to implement complex plugins and plugin managers, but they have an extensive API for extending it. So writing a CodeMirror-Vim plugin manager is doable.
But I think that the main question is if it’s worth the hassle.
Obsidian will soon have a formal plugin manager, and assuming formal Obsidian plugins will have full access to the underlying CodeMirror object like Volcano plugins have, it will be trivial to add functionality to Obsidian’s Vim support using Obsidian plugins. I immediately think of something like obsidian-vim-surround to make a vim-surround clone
At least the way I see it, Obsidian is a notes editor – not a full-fledged text editor. We’ll always have the real Vim for that So many Vim plugins that revolve around code editing are probably an overkill here. IMHO we should think what notes-related functionality is truly helpful in Obsidian’s Vim support – e.g. for me it’s the ability to use basic motions like the ones in the sample vimrc that I wrote, plus some nice text-related shortcuts like “jump to next Markdown block”.
TBH one thing that is make or break for me with the vim mode in Obsidian is, if i cant have relative number lines (which i think is an issue with ace-editors, code mirror or electron, IDK its an issue somewhere cause RStudio has the same issue) then having the functionality of vim-easymotion would sell me on adding the vim plugin back in. that alone.
That’s a very useful plugin idea, may you can try the suggestion here and wrap it in a Volcano plugin if it works!
(BTW I think this discussion should continue in Relative line numbers)
got you. Thanks for the info! You are right, The real vim can always be used for code, in obsidian basic functionality for comfortable writing with vim is more than enough.
There are some great vim plug ins for writing, but you are right it’s better to wait for the API to implement these things.
For now I can’t say how happy I am with:
nmap j gj
nmap k gk
That remap is so essential, to the point where vim can be really annoying without it.
I didn’t yet try 0.9.7, but I did read through the alpha plugin API and I’ll definitely make a proper plugin in the next few days.
BTW did you repatch Obsidian with Volcano after the upgrade? One of the practical downsides of Volcano is that after each upgrade you need to run it so it will patch the new version.
awesome, looking forward to see it as a plug in, without your obsidian.vimrc vim mode is just not the same.
Yeah I run volcano again, but it didn’t seem to work, it might be some issue for my side, but I can see volcano slowly fading away now that the API has been released
I’ll keep track of your porject, thanks for your work!
A few additional nice-to-haves for Vim support. I’m looking at @esm90 (thanks so much for the plugin!) but I’m not sure if some of these issues are rooted in Obsidian or CodeMirror, or need their own plugins.
It would be nice if nmap <CR> o<Esc> could be added to the .obsidian.vimrc file. This allows you press enter to create a new blank line below the cursor but stay in normal mode. It seems that any attempt to map or remap <CR> is broken, but I don’t know if this a problem with Obsidian or CodeMirror. My current workaround is nmap J o<Esc> and nmap K O<Esc> but it’s not ideal.
I can’t seem to get search and replace macros to work. For example, if I want to clear all checkboxes on a note I have to type :s/\[x\]/[ ], and if I write this into a macro it doesn’t seem to “stick”–the macro executes, and then stops with a blank command line open. I haven’t tried to write this into the .obsidian.vimrc file yet since I can’t get it to work manually.
It would be nice if there was a way to keep the Vim console open for more than 3 seconds. For example, typing :reg to figure out whether that macro recorded.
It would be nice if the .obsidian.vimrc file actually behaved like one and allowed for comments and blank lines–but this does risk a deep rabbit hole of making it a full on parser.
Is there a way to get the vim register to interat with the system clipboard? Ctrl/Cmd + C is okay for now, but we all prefer yy and p
Let me know what you think, and if my amateur coding skills could be of any assistance.
These are interesting and I’ll answer based on what I know:
I don’t know to explain why it doesn’t work because at first glance it seems like CodeMirror should support it. <CR> is a default CodeMirror key mapping that should be possible to override. Very possibly a bug.
I struggled with a similar issue, it seems like CodeMirror macros can’t execute searches (they open a search box instead of searching what’s in the macro). Maybe we should open them a bug (or even better, try to fix it?)
That duration is hard-coded in CodeMirror, see duration: 5000 in showConfirm.
Comments and blank lines are very easy to add, I’ll do that if it’s a wanted feature.
I started looking into that one a few days ago and am thinking to add support for it by overriding the CodeMirror yank function (together with a set clipboard vimrc setting). I also started looking into another thing that I really want, which are marks that work across files. Hopefully I’ll get to these.