Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to specify custom mappings for vim mode? #2840

Closed
jondkinney opened this issue Oct 6, 2014 · 12 comments
Closed

How to specify custom mappings for vim mode? #2840

jondkinney opened this issue Oct 6, 2014 · 12 comments

Comments

@jondkinney
Copy link

I am confused about how to take advantage of "Key/command mapping with API (:map, :nmap, :vmap)" from http://codemirror.net/demo/vim.html

Is there an equivalent to a .vimrc where map, nmap, vmap, etc commands can go? I'm using Codio if that makes a difference. They have a way to specify keyboard shortcuts, but not specifically for 'vim' mode. Just when in insert mode.

@mightyguava
Copy link
Contributor

Vim mode supports custom key maps via the CodeMirror.Vim.map(lhs, rhs, context) function. Unfortunately, it doesn't look like Codio has hooks for you to do this. A potential workaround is to run Javascript on the page using a browser extension, as CodeMirror.Vim is in the global namespace.

We've discussed having a .vimrc a few times now and the conclusion has always been: CodeMirror is an editing component. Making it possible to load a .vimrc-like file would be an IDE feature that's out of scope here. Something like that would have to be implemented on Codio's side using the existing CodeMirror APIs.

@jondkinney
Copy link
Author

@mightyguava thanks so much for the info! I'll raise this with the Codio folks. In the mean time, could you elaborate a little bit on the workaround you specified? Probably pointing me to some docs would be enough. But if you have any examples of how to use a specific plugin to achieve this, that would be really great!

Thanks again.

@mightyguava
Copy link
Contributor

Sorry, took a look at Codio and I don't think the workaround will work. It looks like it's using dependency management and puts CodeMirror inside a function closure so it's not globally accessible. I was being naive and thought Codio would be similar to jsfiddle where to just load codemirror.js as is. i.e. you could just use something like this extension https://chrome.google.com/webstore/detail/custom-javascript-for-web/poakhlngfciodnhlhhgnaaelnpjljija?hl=en to run a piece of Javascript that calls CodeMirror.Vim.map for you.

@jondkinney
Copy link
Author

Well, that's a bummer. Thanks for looking into it though! Assuming that they provide a hook at some point, or I decide to roll my own cloud IDE (haha)... I've been looking around but I can't seem to figure out what a custom mapping would look like when implemented through that API. Do you have an example?

CodeMirror.Vim.map(lhs, rhs, context)

I don't know exactly what I'm able to pass to lhs and rhs and context.

Thanks!

@mightyguava
Copy link
Contributor

Ah, I should really get around to writing some documentation.

Suppose you want to map jk to Esc in insert mode, you would call CodeMirror.Vim.map('jk', '<Esc>', 'insert'). That's equivalent to :imap jk <Esc>. If you leave out 'insert', then it would be equivalent to :map jk <Esc>. The mapping applies to all CodeMirror instances on the page (in the same browser frame).

While in a CodeMirror instance, you could also type :imap jk <Esc> to achieve the same effect. But the change doesn't persist across refreshes.

@jondkinney
Copy link
Author

👍

@marijnh
Copy link
Member

marijnh commented Oct 7, 2014

You can always reach CodeMirror instances from the DOM, so if you want to get at the CodeMirror constructor in a website that has a visible editor, you could do this:

document.querySelector(".CodeMirror").CodeMirror.constructor

@jondkinney
Copy link
Author

@marijnh thanks for the response, and sorry if this is a silly question, but could you elaborate on if/how that'd work from a plugin running arbitrary JS in Safari or Chrome?

I understand what a constructor to a class is, but I'm unclear what I can pass into the constructor to re-define a keymap for all the instances of CodeMirror in the dom.

This is clearly wrong:

document.querySelector(".CodeMirror").CodeMirror.Vim.map('jj', 'Esc', 'insert')

Any tips? Thanks!

@mightyguava
Copy link
Contributor

document.querySelector('.CodeMirror').CodeMirror.constructor.Vim.map('jj', '<Esc>', 'insert')

FYI :imap support was only committed a few days ago, so it's not in Codio yet. nmap, vmap, and map should all work.

@mightyguava
Copy link
Contributor

I'm not very good at explaining how Javascript objects work, but simply put, you aren't passing anything into the constructor here. The constructor conveniently happens to be the object that contains all the API methods. So you call methods on .constructor instead of calling .constructor itself.

Maybe putting it in code might be clearer.

var CodeMirror = document.querySelector('.CodeMirror').CodeMirror.constructor;
CodeMirror.Vim.map(';', ':');

@jondkinney
Copy link
Author

Well, it took some fiddling, but I was able to get it working with the following

image

Which is this code:

$(document).ready(function() {
  setTimeout(function() {
    document.querySelector('.CodeMirror').CodeMirror.constructor.Vim.map('jj', 'kkkk');
  }, 2000)
});

Obviously typing 'kkkk' when you type 'jj' is utterly horrible :p but it proves it works. I'm also mixing jquery and regular js there, but I think $('.CodeMirror')[0].CodeMirror.constructor works as well.

I am, however, having a bit of an issue getting the same code to work in a similar plugin in Safari during auto-load. If I execute the script manually in Safari (through the same extension) it works fine... odd, but this doesn't work:

image

I get the error: TypeError: undefined is not an object (evaluating 'document.querySelector('.CodeMirror').CodeMirror.constructor') so the call to .CodeMirror immediately preceding the call to .constructor is returning undefined and then .constructor can't be called on that, of course. Odd, not sure if you have any insight on Safari plugins or not...

Thanks for the tips to getting this going in lieu of proper support from Codio!

@mightyguava
Copy link
Contributor

I have never dealt with scripting in Safari plugins before so I don't think I can be of much help. 2 things that come to mind are timing and sandboxing. Try increasing your timeout to like 10 seconds and if that doesn't work see if it's possible to fetch other elements on the page. If the second fails, I'd suggest asking on the plugin forums.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants