vi modes feature integration

Hi, I had several questions about the state of vi modes and contributing to its feature set.

I am on Xamarin Studio 4.2.5, and it seems like the 'e' motion to navigate to the end of the word is not implemented. However, I built MonoDevelop from github (showed version 5 at the time) and it seems like this feature made its way in. I assume it will make its way into XS in the next version bump. I assume there is a one-to-one correspondence between version numbers in XS and MD?

There are features still missing from the source build of MD, and I was wondering if it was also just a matter of time before they get integrated? For instance, there is an open pull request for repeated actions in vi mode. In that link, there's a second pull request referenced that has changes conforming to the coding style.

Finally, I'd like to propose and work on some additional features for vi modes. Would it be best to just start a pull request on MonoDevelop and discuss it there? For instance, CTRL+V would be used for visual block selection, and it'd be useful to add. But I guess it potentially conflicts with IDE bindings, so maybe there should be a way to specify which binding to use in the UI (a la Visual Studio + VSVim).

Thanks,

-Alex

Best Answer

Answers

  • mhutchmhutch USXamarin Team Xamurai
    1. Yes, there's a 1:1 version correspondence between MD and XS.

    2. I have to apologize for not having finished reviewing and merging that pull request, it's overwhelmingly complex and I haven't really had time to work on the vi modes lately :/

    3. Yes, pull requests would be the way to go, although in the case of the vi mode it might be a better idea to fork it into a separate addin so you won't be blocking on me reviewing it.

    4. Yes, there is a system for key binding schemes so you could automatically switch over to a scheme that doesn't conflict with the vi keys.

    5. One of the big issues with the vi modes is that I wrote it before learning vi so it has some architectural issues (basically, no sane encapulation of state) that make it very hard to maintain and to develop more complex features. In the source you can also find some old experimentation around a ground-up rewrite that didn't quite get off the group.

  • atsuiatsui USMember

    in the case of the vi mode it might be a better idea to fork it into a separate addin so you won't be blocking on me reviewing it.

    Thanks for the useful information. I'm just getting started working with MD so I have some homework to do with the addin architecture and reading over the vi modes source. Just so I'm clear about your suggestion, the way to start is to create an addin that will live in src/addins that mirrors the code in src/core/Mono.Texteditor/Mono.TextEditor.Vi and extend from there?

  • mhutchmhutch USXamarin Team Xamurai

    You could actually create it in a standalone repository and then publish it on addins.monodevelop.com. You may find my MonkeySpace 2013 talk on Extending Xamarin Studio with Addins useful. I'd also recommend checking out the Addin Maker addin from the Addin manager. And I'd be happy to answer any further questions, of course.

  • atsuiatsui USMember

    What would be a good way to get an addin to hook into the text editor? Currently, the button in Preferences -> Text Editor -> Behavior to enable vi modes will explicitly. Currently, the ExtensibleTextEditor will set up an IdeViMode to capture keystrokes or otherwise stick with a simple edit mode. Is there a way that an addin can get access to the text editor, or does this part of MD need to be modified?

  • mhutchmhutch USXamarin Team Xamurai

    From any MonoDevelop.Ide.Gui.Document you can get the SourceEditorView like this:

    document.GetContent<MonoDevelop.SourceEditor.SourceEditorView> ();

    From that you can get to the ExtensibleTextEditor and assign a new mode to it.

    Maybe the most appropriate place for this would be a TextEditorExtension, which is initialized for every source view.

  • atsuiatsui USMember

    I was able to get the ExtensibleTextEditor as you said, and I can manually change the mode from my addin. I think that's enough to get started hooking in my own custom vi mode -- awesome.

    So it looks like the way to go is to create a class that extends MonoDevelop.Ide.Gui.Content.TextEditorExtension and override the Initialize method to set up the new vi mode. How can I register my TextEditorExtension so that it is called for every source view? And I guess I should query a boolean setting to decide whether I want to do this -- can I throw this into the CommandHandler (I am basically building up from the DateInserter sample)?

    As an aside, I noticed that the template .addin.xml has changed somewhat in the recent AddinMaker since it was updated for version 5. The root Addin tag is gone, but it seems like everything works as usual if I put extensions under the ExtensionModel tag.

  • mhutchmhutch USXamarin Team Xamurai
    edited June 2014

    An instance of your TextEditorExtension will be created for each source editor, that's how it works.

    For enabling /disabling, I'd suggest you check the "UseViModes" property from the PropertyService. You can subscribe to events to be notified when it's changed. The source editor does this indirectly by updating its SourceEditorOptions and updating the modes when that changes.

    Yes, some of the addin metadata was moved to assembly attributes so it can use version constants defined in MonoDveelop core.

  • atsuiatsui USMember

    I wasn't sure if I needed to specify my TextEditorExtension in the addin xml manifest for it to be used. I had a test subclass write to console in the Initialize method, but I didn't see anything. Will MonoDevelop pick up any TextEditorExtension in my .dll automatically?

  • mhutchmhutch USXamarin Team Xamurai

    No, you need to register it in the manifest, see e.g. the T4 addin.

  • atsuiatsui USMember

    I've copied the set of classes implementing vi modes from the MD core into a separate addin, and I've registered the TextEditorExtension to work with the new vi modes code in the addin. Now I can go to work on updating the edit mode on this standalone addin.

    There's a few things that I had to disable, and I still don't know how to deal with. Basically, the core vi modes was making use of a few methods with internal (not public) visibility, which the addin code is not able to call. There's three things I've found:

    1. The caret blinking in the status area: In Mono.TextEditor.Vi/ViStatusArea.cs, there is access to TextEditor.TextViewMargin.CaretBlink for showing the caret in the bottom of the editor when entering an ex command.
    2. Save and quit: In IdeViMode.cs, the ExtensibleTextEditor.View is directly accessed to save or close the document but have internal access only.
    3. In Mono.TextEditor.Vi/ViBuilders.cs, there are calls to BeginAtomicUndo and EndAtomicUndo that I'm not sure what they do, but they only have internal access.

    What do you think should be done for these?

    Thanks for the help getting this set up. I put up the solution so far on github here.

  • mhutchmhutch USXamarin Team Xamurai
    1. Maybe we can make that public.
    2. The TextEditorExtension can pass its IdeViMode a reference to the Document, from which you can save, etc.
    3. I think the public version of that API is using (var undoGroup = TextEditor.OpenUndoGroup ()) ...
  • atsuiatsui USMember

    Is there a way to ensure that the vim addin text editor extension gets priority over the built-in vi modes? If I check+uncheck the vi modes in the behavior preferences, the built-in vi modes takes precedence because I guess it is the last one to set the mode.

  • mhutchmhutch USXamarin Team Xamurai

    Not really. But now you've published your addin, I have removing the built-in support on my todo list...

  • atsuiatsui USMember

    Do you know of a good reference addin that introduces UI to manage its own user settings? VimAddin has been updated a bunch at this point but is still piggybacking off of the checkbox in XS's global user preferences, so I would like to look into how a conventional way to set up the addin once the core vi modes has been phased out.

  • mhutchmhutch USXamarin Team Xamurai

    You need to register a panel into the global options dialog. Here's an example.

  • atsuiatsui USMember
    edited September 2014

    Okay, I am going to do this when I add a panel, but how can I add UI elements to the addin project? I've been using your AddinMaker addin up until now, but I can't figure out how to make it aware that I want to add GTK# elements. The NuGet addin project, for example, has a User Interface folder that you can add widgets and windows to like if you started a new GTK# project.

    By the way, I'm working on the addin with a development build of MonoDevelop (5.7 at this time) (this may be a bad idea), and the usual way I have been initializing the addin has stopped working. Maybe I'll try just using the release version (closer to 5.0.1), but I was just wondering if there's been any change in how the TextEditorExtension is set up? Maybe I should just stick to a stable release in general to avoid possible issues on the development version? Thanks.It's my fault. I have multiple copies of MonoDevelop and was using the wrong one...

  • mattwardmattward GBMember Xamurai

    @atsui - If you have the GTK# Visual Designer addin enabled you should be able to add a new Gtk file (i.e. widget, dialog, etc). The User Interface folder will then be displayed in Xamarin Studio.

  • atsuiatsui USMember

    Thanks for the tip, I'll take a look at the addin.

    Another thing that I've noticed is that keyboard shortcuts between the addin and the IDE changed precedence. For example, Ctrl+D or Ctrl+F used to page down in the text editor, but now Ctrl+F activates the IDE's find function, and Ctrl+D seems to trigger some multiple key input (repeated presses gives me "The key combination (Control+D, Control+D) is not a command" in the status area toward the top).

    I tried to use git bisect to hunt down where this behavior appears, and it looks like 7e65004df is the first bad commit, right after eeec9c523 where Ctrl+D and Ctrl+F still worked as I expected. Unfortunately, I don't understand how the diff between these can cause the change in behavior.

    At any rate, maybe it's just time for there to be a designated way for the user to pick alternate keybindings. While scrolling through commits, I did see some relevant bits introduced by mkrueger that seems to indicate there's a way to do this. For now, I guess I'll work on hooking an addin panel into global options.

    Thanks again,

    --Alex

  • v2d2v2d2 USMember

    what about using neo vim as a library wrapping it? I'm not sure sure if the libv stuff is ready there yet but that would be the most ideal solution :)

  • atsuiatsui USMember

    I think I stumbled across a post on the unity forum about using gvim as an external editor, and since then, I wondered if there was something that packages vim functionality for better IDE integration. I haven't heard of neovim but it sounds like that's what they're doing and it sounds cool. Are there any projects using it already?

    I will just continue to add stuff to the current VimAddin, though.

  • atsuiatsui USMember

    Well, I read a little bit more about neovim and just saw a video of neovim embedded in Atom and it looks pretty nice. I have to start thinking about how one might go about doing the embedding. Has anyone played with neovim?

  • atsuiatsui USMember

    Is there a proper way to programmatically feed keypress events to the EditMode of the TextEditor?

    Basically, I have created Commands that can be remapped to user-defined key bindings through user preferences. I would like to trigger some actions in the VimAddin keypress handler by programmatically sending the particular key combination.

    I tried to expose a public method that calls EditMode.HandleKeypress (Key key, UInt32 unicodeKey, ModifierType modifier) but am getting a NullReferenceException.

  • mhutchmhutch USXamarin Team Xamurai

    Probably the cleanest way to allow the EditMode to handle Commands would be to modify the SourceEditor so that it considers the EditMode part of the command chain. Then the EditMode could use command handler methods (via CommandHandlerAttribute) just like everything else.

    Alternatively you could use a TextEditorExtension which could implement the command handler methods and pass them on to the vi mode.

    That said converting keystrokes to MD command IDs then back to keystrokes then back to vi commands seems a little complicated... it maybe worth having your own command mapping system instead, especially since vi allows much more complicated mappings.

    Where is the null reference exception coming from?

  • atsuiatsui USMember

    Here's a stack trace I got going about the quick and dirty approach of exposing and calling HandleKeypress myself. It seems to indicate the null reference comes from the CheckVisualMode method.

  • mhutchmhutch USXamarin Team Xamurai

    Looks like the only thing that could be null in that case is Data, not sure how. Maybe you're getting an instance of the mode that's not bound to an editor?

  • atsuiatsui USMember

    I am getting the editor in the command handler the same way I do when I setup the edit mode. I assume that I get the VimAddin.IdeViMode that I set myself up in the first place, and it casts fine so I assume it is the same one, but I'm not sure why Data is coming out null.

  • mhutchmhutch USXamarin Team Xamurai

    Have you checked whether the textEditorData is null? Not sure why it would be... but it would probably be more consistent to get it directly from the source editor anyway instead of from the provider interface.

  • atsuiatsui USMember

    Yes, finally tracked down the problem caused by the internal State enum for ViMode not being initialized. I found Data to be non-null all the way into the HandleKeypress method, which actually ends up being set to null on the very first call to HandleKeypress because the EditMode is constructed with an CurState of State.Unknown...

    Well, that and I was sending a Control+F keystroke, which actually doesn't map to a caret motion (Control+D does, on the other hand).

    So now it's possible to setup custom key bindings, which I'll get started on this weekend. Thanks a bunch @mhutch .

  • mhutchmhutch USXamarin Team Xamurai

    Nice! I'm glad you're making good progress with this.

  • Ghopper21Ghopper21 USMember

    Hi @atsui - like you, I'm eager to see better vim support in Xamarin. Thanks for your work on the add-in. Seems like there is a long way to go with that (e.g. f doesn't work). You mentioned integrating neovim as another approach. Do you think that's a promising direction to get "real" vim into Xamarin, or is building up the add-in bit by bit the way to go?

  • atsuiatsui USMember

    Hi @Ghopper21, it feels like it would be more straightforward to hack on the current add-in if you have a particular itch you want to scratch and so you can move on and use the slight improvement, like f. I haven't seriously looked into the idea of integrating neovim so I can't offer any opinion, but just watching their google group and seeing reference UIs pop up for other languages is cool. I just knew I could only invest a couple of hours a week and I wouldn't be able to make it happen. I think either way you want to pursue, the community response seems really good if you have any questions.

Sign In or Register to comment.