NeoVintageous / NeoVintageous

Vim for Sublime Text.
https://neovintageous.github.io
GNU General Public License v3.0
682 stars 43 forks source link

Run a cli command on every mode change #932

Open eugenesvk opened 1 year ago

eugenesvk commented 1 year ago

I'd like to add a typo-free And convenient way to exit Insert mode. One such way is to bind hold i to , but Sublime/NV can't handle taps vs hold keys. Other key remapping apps can, but then they don't know what mode NV is currently in, so they can't remap i only in Insert mode But NV could send those apps a cli signal on every mode switch (would differ depending on the source/target mode)

So would it be possible to add some kind of optional hook that would execute a cli command on every mode switch? Then I could se this command to, eg, send to Karabiner Elements on a Mac a command to set isNVⓘ whenever NV enters Insert mode, and then within Karabiner Elements I'd set up i on hold to exit, but otherwise continue to type i

gerardroche commented 1 year ago

Do you mean how plugins like vim-xkbswitch invoke a program on entering and exiting insert mode?

I don't understand what you mean by "taps vs hold keys"? Is this an ST limitation or NeoVintageous?

Other key remapping apps can, but then they don't know what mode NV is currently in, so they can't remap i only in Insert mode.

I don't understand. Could you explain a bit more?

Could you also post the keymaps file you're currently using so I can maybe better understand how to solve i18n issues?

P.S Take a look at these plugins. I think you should be able to roughly prototype something by hooking into the base Sublime event system like the way these do.

They both do some very similar, but notice that the Line Numbers plugin also checks against the "command_mode".

https://github.com/gerardroche/NeoVintageousHighlightLine https://github.com/gerardroche/NeoVintageousLineNumbers

I am planning on pull those checks into the core plugin and expose them to plugins so that plugins don't have to write those internal checks. Also, the internals might change without notice.

Or maybe even provide full fledged event classes that plugins can hook into. Those plugins are sort of beta test for to try things like that.

eugenesvk commented 1 year ago

Do you mean how plugins like vim-xkbswitch invoke a program on entering and exiting insert mode?

Sound exactly like that

I don't understand what you mean by "taps vs hold keys"?

tap: press i, release i WITHIN 0.1 seconds hold: press i, release i AFTER 0.1 seconds

(0.1s is just an example, you can set your own delays in a keyboard remapper)

Is this an ST limitation or NeoVintageous?

ST's which NV inherits

Other key remapping apps can, but then they don't know what mode NV is currently in, so they can't remap i only in Insert mode.

I don't understand. Could you explain a bit more?

I can bind hold i to send in Karabiner (a key remapping app), and I can even limit that remapping to only work in Sublime Text.

But let's say in Normal mode i moves cursor up, so now you can't hold i as it will send instead BUT if Karabiner knew that NV is in normal mode, it could just NOT remap anything, and only remap when NV is Insert mode Karabiner can receive input via a CLI command, but something needs to send that input, hence this feature request

Could you also post the keymaps file you're currently using so I can maybe better understand how to solve i18n issues?

Do you mean this autogenerated file from https://github.com/NeoVintageous/NeoVintageous/pull/869?

P.S Take a look at these plugins. I think you should be able to roughly prototype something by hooking into the base Sublime event system like the way these do.

They both subscribe to every single text command, which seems like a waste, but that gave me an idea to subscribe to settings changes via sublime_settings.clear_on_change('command_mode'), but then this subscribes to every single config change, which fires on every cursor move

Is there some command within NV that would uniquely identify insert mode enter/exit? class ViEnterInserMode(ViOperatorDef): seems to be the one to monitor for entering, but there is nothing for exiting? Only other modes overwriting mode name Anyway, overriding this internally to try to run some cli command seems more sensible than tracking a config change on every single cursor movement

I am planning on pull those checks into the core plugin and expose them to plugins so that plugins don't have to write those internal checks. Also, the internals might change without notice.

Or maybe even provide full fledged event classes that plugins can hook into. Those plugins are sort of beta test for to try things like that.

that would be nice! This would allow monitoring a simple boolean isInsertMode?

gerardroche commented 1 year ago

Yes that's the keymap file I was looking for. Do you have a mapping that you used to generate it?

Do you have a recommendation for a Karabiner app on Linux?

Hooking into the text commands on every key would be better than hooking into the settings.

It's not ideal, but I'd like to see a proof-of-concept/prototype implementation using that method. It can be substituted with something better later.

It's certainly possible to have events OnEnterInsert, OnExitInsert, OnEnterNormal, etc. It's just a case of how to implement it.

I had a wip ages ago when I was trying to get xkbswitch working. I couldn't get xkbswitch to work properly on Linux/Gnome so I gave up.

I think you need a blocking event.

A quickfix implementation would be to allow you to specify a commands to run when entering insert mode or exiting. Something like:

"neovintageous.events": {
    "InsertEnter": "my_custom_sublie_command",
    "InsertLeave": "my_custom_sublie_command",
    // ...
}

Does NeoVintageous need take a response and do something with it or would you just handle Karabiner and let nv continue? For instance, if you can you hook into the events with an st command, would that solve it?

A full fledged nv event

I'm thinking something like the way ST does events. You declare you event class, define the event methods you want, and register with nv. Then nv will just invoke those event methods.

Keymaps

I remember you mentioned having to override the users keymaps.

I don't think you need to override keymaps. For example, I'm pretty sure you can put the keymaps in a seperate package. As long as it loads after nv. For instance, you could put it in

Packages/NeoVintageousI18nEugenesvk/Default.sublime-keymap

I'm pretty sure that would override nv's keymaps.

This would then still allow you to override them again in user keymaps.

eugenesvk commented 1 year ago

Yes that's the keymap file I was looking for. Do you have a mapping that you used to generate it?

The fork https://github.com/eugenesvk/NeoVintageous links to an example config that has the mapping used to generate that as well as has the code to map a few keymaps (including colemak, dvorak etc), which would solve your other issues without having to have separate plugins for every keymap, and is also more flexible since a user can copy&paste&adjust any keymap to whatever they have

https://github.com/eugenesvk/NeoVintageous/blob/24c98e23da20c8b3d089eb64b69b5d365d74e52b/nv/layout_convert.py#L132-L153

Do you have a recommendation for a Karabiner app on Linux?

Unfortuantely not

Hooking into the text commands on every key would be better than hooking into the settings.

I've gone by calling a function inside the plugin and just getting/executing the full command from user config, seems like a more straightforward way that those limited ST's APIs

It's not ideal, but I'd like to see a proof-of-concept/prototype implementation using that method. It can be substituted with something better later.

sure, maybe the broader goal is better achieved this way

I had a wip ages ago when I was trying to get xkbswitch working. I couldn't get xkbswitch to work properly on Linux/Gnome so I gave up.

:(

Does NeoVintageous need take a response and do something with it or would you just handle Karabiner and let nv continue?

No response, you just pass a variable/value via cli, and that's it (well, just checking that the user passed command exists and printing errors)

For instance, if you can you hook into the events with an st command, would that solve it?

Sorry, don't understand how that would work, would the command be autoexecuted on ST's launch/new view/etc?

Keymaps

I don't think you need to override keymaps. For example, I'm pretty sure you can put the keymaps in a seperate package.

I think that should also work since User packages are always loaded last, I just thought that since this is a User generated file it should be inside the User folder, it's conceptually cleaner, but less convenient

gerardroche commented 1 year ago

Sorry, don't understand how that would work, would the command be autoexecuted on ST's launch/new view/etc?

It would fire the command on on entering and exiting the different modes. The command would then handle the cli call.

It sounds like you're invoking the cli directly inside nv. Using events you would handle the cli in the subscriber, but handling the cli directly would work. That's what I was doing when I tried to get xkbswitch working.

Let me know how it works.

eugenesvk commented 1 year ago

Let me know how it works

Works wonderfullly! Finally at least one app does mode switching properly!