Steps to reproduce:
:nnoremap <M-a> :echo "foo"<CR>
Pressing ALT-a does not invoke the <M-a> mapping.
Thanks for the issue, @justinmk ! Really appreciate you trying the build out.
I just tested this scenario on OSX and Windows:
<a-a>. The <m-a> mapping seems to pick this up anyway, so I see 'foo' output here.氓. So I have to change the binding to :nnoremap 氓 :echo "foo"<CR> to get it to work.Which platform are you on? And which keyboard layout did you test with? I'll see if I can reproduce it too.
Sometimes there is some flakiness with the Alt key in different keyboard layouts, because of how we try and differentiate the AltGr cases (like #696 ). It's possible we're hitting a case related to that.
I'm on macos. Getting around the default macos handling requires some fiddling, but I would expect electron to have a built-in mechanism to handle it as a modifier.
Hmm, I tried with binary nvim on OSX, and I see the same behavior - I need to use :nnoremap 氓 :echo "foo"<CR> in terminal nvim for this binding to work correctly. So it makes sense for Oni to behave the same way here, IMO - but I could be missing something. Is the <m-a> binding expected to work in terminal nvim for this case?
Getting around the default macos handling requires some fiddling, but I would expect electron to have a built-in mechanism to handle it as a modifier.
Yes, I assumed so too! Unfortunately, it's not great for some of this input scenarios. An example is pressing <A-S-a> - we get this character: 脜 However, it comes to us as an event like:
{ key: '脜', shiftKey: true, altKey: true }
So if we naively convert this to input nvim expects, we'd send: <A-S- 脜> - which isn't correct.
We end up using Atom's keyboard-layout module to ask how the character gets generated, in order to figure out which keys to 'ignore' when sending to Neovim. In the above case, we'd figure out that the 脜 key is produced by alt+shift+a... so we should ignore the alt+shift when sending to Neovim. Definitely more complicated than it _should_ be.... but luckily that module is available to help us out here.
Hmm, I tried with binary nvim on OSX, and I see the same behavior
Terminal.app and iTerm2 have an option to "send option as ESC", and the standard advice is to enable this option. Otherwise yes, you get the default OS-wide behavior that you are seeing.
Low-level applications like kitty must implement their own mechanisms to work around this macOS behavior. But electron/Chromium should have already dealt with this.
Terminal.app and iTerm2 have an option to "send option as ESC", and the standard advice is to enable this option. Otherwise yes, you get the default OS-wide behavior that you are seeing.
Interesting - didn't know that. Thanks!
Low-level applications like kitty must implement their own mechanisms to work around this macOS behavior. But electron/Chromium should have already dealt with this.
We do get enough information where we can decide _either_ to send to Neovim as 脜 or <a-s-a> - the problem is deciding which one to use.
If we just went back and started 'unwrapping' to across all our input (converting the resolved character to the corresponding key chord), this would cause issues for the AltGr cases: if I press 'alt+8' on my german keyboard layout - I'd expect that to be sent to neovim as { instead of <a-8>. It's not clear to me how we'd differentiate between this case - pressing <a-8> -> { and pressing <a-a> -> 氓 } - how do we decide which strategy to use, reliably, across different keyboard layouts?
FYI, I am planning on adding an API to add custom 'resolution' of characters - just a function that takes a keyboard event -> resolved neovim input string. We already have a chain of resolvers, defined here:
https://github.com/onivim/oni/blob/9ba6f55b6ee5664e9b7cea8651e2e2368fca3309/browser/src/Input/Keyboard/Resolvers.ts#L11 , just not exposed on our API surface area yet: oni-api. This would allow users / plugins to provide custom resolution logic for KeyboardEvent -> string for nvim. Even allowing something like a hardcoded mapping for a keyboard layout, if need be..
this would cause issues for the AltGr cases: if I press 'alt+8' on my german keyboard layout
What does Windows (or Linux/GNOME--both of which use ALT as a "menu accelerator") do in that case? What does Atom do? Sublime, VS Code? Don't ALT keys work there, for navigating menus?
Perhaps those problematic cases can be special-cased. But generally, nnoremap <M-...> should work out of the box. It's the common case.
What does Windows (or Linux/GNOME--both of which use ALT as a "menu accelerator") do in that case? What does Atom do? Sublime, VS Code? Don't ALT keys work there, for navigating menus?
They don't have the same issue - they actually have an easier problem, because they fully manage the input. For the 氓 case, they can check if they have any bindings associated with alt+a, and if so, they use that - otherwise, they send the 氓 to the editor. They sidestep the problem because they can look at their input manager / bindings and ask - 'is there a binding for alt+a'? 'is there a binding for 氓'? If so, just pick up and execute that binding - otherwise, send 氓 to the editor. Pretty simple and concise logic.
The additional complexity we have is we need to figure out how to send it to Neovim - do we send as <a-a> or 氓? <a-8> or {? We don't have a good way to know right now, because we don't have a good way to ask those same questions synchronously.
A potential option would be to use nvim_get_keymap or similiar, and check if there is a mapping that matches either <a-a>/<m-a> or 氓 to figure out what to send. This would give us the ability to ask the questions as above and follow the same logic - just means there is extra complexity on the client to manage and synchronize that state (for example, I'm not sure how we deterministically would know to update it if the user maps a new key). But if we have that state, we could query and check - is there a binding for <m-a>? If so, we send <m-a>, otherwise, we'd send 氓. This seems like reasonable behavior for the AltGr case too - if someone maps to <a-8>, we'd respect that.
Another option that would need an API extension would be for us to send _both_ candidates and let Neovim decide what to use. This simplifies our layer a bit because we don't have to manage & synchronize the keymap state.
We can also handle this in our input binding layer (we don't today, but it would be straightforward to add).
There is a separate issue with the ALT key with menus - which is that electron is aggressive in picking up the ALT key, regardless of it is part of a chord - you can see #1250 for how that impacts Oni.
For the 氓 case, they can check if they have any bindings associated with alt+a, and if so, they use that - otherwise, they send the 氓 to the editor
If Sublime or whatever ships with an alt-a binding and the user wants 氓, the user will get the editor default, not 氓.
But really, this doesn't need to be complicated. If <M-...> is supported, users that want it to input 氓 (the uncommon case) can fix it:
:nnoremap <M-a> 氓
Not to mention, platform-specific input is out of place in Nvim, which has digraph support.
But really, this doesn't need to be complicated. If
Are you suggesting we just always send the 'unpacked' version to nvim_input - like <m-a> instead of 氓, and <m-8> instead of {?
This doesn't seem like an acceptable solution. It makes Oni behave, in insert mode, different than every other editor experience I tried on OSX - Atom, VSCode, and Notes, since <m-a> sent via nvim_input will produce a instead of 氓, whereas those other editors will show 氓. Would also break our AltGr cases, like #644 . Let me know if I am misunderstanding the suggestion, though.
Otherwise - we're back at the core problem - deciding when we should send <m-a> vs 氓 to nvim_input.
Yes. I guess I'm biased because I use vim across platforms and don't want platform-specific quirks in my config.
Another option that would need an API extension would be for us to send both candidates and let Neovim decide what to use
This could probably be supported with a new keycode form, something like:
nvim_input('<? 氓 a-8 >')
Yes. I guess I'm biased because I use vim across platforms and don't want platform-specific quirks in my config.
Agree 100% 馃憤Having to create a platform-specific config is a terrible experience.
This could probably be supported with a new keycode form, something like:
nvim_input('<? 氓 a-8 >')
This would be excellent. It would mean minimal overhead for Oni - we could just send you both candidates and Neovim would do the right thing for us. I believe this would be applicable for the other browser clients hosting Neovim as well (would be interesting to see if @Chillee has run into this w/ VSCodeNeovim)
Per our discussion on Gitter - seems like we can implement this resolution via a custom VimL/Lua function, which would be simpler than updating the nvim_input API. If it turns out this is a requirement for other external UIs too, we can look at generalizing it/factoring it out.
@bryphe do you mean the external UI will call a VimL/lua function instead of the nvim_input? Then note that the function call will not be executed immediately in many contexts where nvim is waiting for user input, which can lead to unexpected behavior (such as user input being reordered).
@bryphe do you mean the external UI will call a VimL/lua function instead of the nvim_input?
Right, that's what I was thinking. Otherwise, we'd need the logic either on the nvim side (potentially with the alternate keycode form), or on the Oni client side (requiring synchronizing of the keyamps).
Then note that the function call will not be executed immediately in many contexts where nvim is waiting for user input, which can lead to unexpected behavior (such as user input being reordered).
Ah, good catch... I forgot about this. This would be problematic.
That may not be a big problem. Check nvim_get_mode().blocking. If it's blocking, it doesn't really matter what you send because mappings usually don't apply during Press-Enter prompt. If it's not blocking, it's ok to proceed as described above.
Any movement on this issue? I just tried out Oni and am very impressed, but none of my meta bindings work 馃槥
@bronzehedwick - unfortunately nothing new here, would 鉂わ笍 help if anyone is up for investigating it.
Okay gotcha. I have never coded anything like an editor before, but I'd like to contribute to the project. I think I'll try one of the good first issues first and get more comfortable before trying this.
Okay gotcha. I have never coded anything like an editor before, but I'd like to contribute to the project
Awesome, we can definitely use help! 馃挴
I think I'll try one of the good first issues first and get more comfortable before trying this.
Sounds good. Let me know if you have any questions!
Soooo miss the meta key. if something like set macmeta command on macvim can work, that will be great.
I don't know what VimR does under the hood, but it gives the option "Use Left Option as Meta" and "Use Right Option as Meta". If someone were to look into that, it could probably be migrated to Electron.
here is how NyaoVim handles the meta key on OSX
https://github.com/rhysd/neovim-component/commit/5b356d88669e8267cb27d128cd33f062ec5d8e0f