Support loading Vim commands from configuration (vimrc-style)

+1 This would be really helpful for those of us running a custom keyboard layout that makes the default vimkeys less ergonomic.

1 Like

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 :slight_smile:
8 Likes

You are a genius!! @esm90 Thank you so much for making this!

I was in desparate need for:

nmap j gj
nmap k gk

It worked perfectly for me. Specially since that’s what I really needed from an obsidian vimrc.


This is probably too much to ask, but out of curiosity is it possible to use something like:
junegunn/vim-plug: Minimalist Vim Plugin Manager

for managing vim plug ins?

Not really sure of the limitations of code mirror, but curious to know if it’s a possibility

Thanks again for the excellent work!


PS: I’d highly recommend posting this to the “Share and Showcase” Section. It would be a shame for this to not be found by those who need it!

2 Likes

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.

  1. 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 :slight_smile:
  2. 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 :wink: 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”.
2 Likes

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.

1 Like

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.

Thanks again @esm90

PS: @tallguyjenks vim-easymotion is a killer plug in, it would be amazing to have it in obsidian!

2 Likes

Your quick hack code just converted a guy from one “note taking OS” to Obsidian.

I also avoided Obsidian because the lack of gj and gk key bindings. thank you!

3 Likes

hey @esm90 I’m not sure if it’s just me or if your amazing .obisidian.vimrc stopped working on version 0.9.7

Would it be possible to move this from volcano to the new plugin API?

Thanks for your hard work!

1 Like

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.

3 Likes

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!

Done! I made a formal plugin that can already be installed manually and created a PR to list it in the community plugins.

6 Likes

Finally I can unmap <C-c> properly. Thank you so much.

3 Likes

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.

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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:

  1. 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.
  2. 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?)
  3. That duration is hard-coded in CodeMirror, see duration: 5000 in showConfirm.
  4. Comments and blank lines are very easy to add, I’ll do that if it’s a wanted feature.
  5. 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.
1 Like

I would appreciate point 4.
I already achieved point 5 with this script(https://github.com/ianhi/jupyterlab_vim-system-clipboard-support) in my own private plugin. Just as a tip.

1 Like

thanks @Vinadon for sharing your script, could you provide some instructions for setting it up for Obsidian if possible?
also, does it work for linux manjaro?

It is not my script, I found in in the internet, but because it is codemirror, you can use it in obsidian as well. I didnt make a public plugin, because I am not sure with the rights and so on with this script.
To use it you have to

  1. create you own plugin with this template
  2. put the yank.ts in your plugin folder
  3. register it with
this.registerEvent(this.app.on('codemirror', (cm: CodeMirror.Editor) => {
     CodeMirror.Vim.defineOperator("yank", yankGenerator(CodeMirror.Vim.getRegisterController(), true))
}));

somewhere in your main.ts

Honestly I dont know what the last argument stands for, I noticed no differene between true and false, but it works. EDIT: I found some info, but I guess true is the right choice.

It will throw some types error, because it cant find Vim and so on, but I guess it is just not well documentated.

To make it accessible for everybody, do you mind opening a PR to add this to the Vimrc plugin? I’d add a custom option (CodeMirror.Vim.defineOption) named clipboard to make it configurable similarly to Vim.
If you don’t get to it I’ll do it in the next few days.

1 Like

What do you mean exactly with?

I’d add a custom option (CodeMirror.Vim.defineOption) named clipboard to make it configurable similarly to Vim.

Do you want that it is configurable with the .vimrc file? What options and syntax do you have in mind?

In addition, should I ask the author of the originial script if is ok to use it?