[RFC] allow external uis to render the popupmenu #4432

Merged
merged 4 commits into from Aug 29, 2016

Projects

None yet
@bfredl
Member
bfredl commented Mar 9, 2016 edited

This enables the internal drawing of the completion popupmenu to be switched off and the data instead sent to an external gui for it to display as it likes.

Not that I care that much about the pum specifically, but it is a good example of an ui element whose implementation is reasonally well isolated from the rest of screen.c and thus serves as a good prototype for externalizing ui elements in general.

Some open questions:

  • It would seem unreasonable to define a member of ui_t for every ui event that would arise from an externalizied ui element. For the moment I just added (*event)(name, args) for a generic event that external gui:s care about but not the tui, but it seems like a hack over the present model. (Ref disscussion in #4322 about the distinction of ui/non-ui events).
  • Similar question could be raised about ui requests like remote_ui_try_resize. Why don't we have api/remote_ui.c and just autogenerate the msgpack validation as for all other api requests? (done in #4817 )
  • If multiple uis (including the tui) are connected they might differ in which ui elements they implement themselves or should be drawn on the grid. The "proper" solution would be to have multiple "layers" of the grid that ui:s could show or not show but that looks too complicated at this point (it should probably wait until progress is made on the smart ui protocol). A reasonable heuristic for this case could just be: the ui that sends the keypress opening the pum determines the display mode. solution: only use external popupmenu if all connected clients support it.

I made stupid test for the python-gui, it doesn't even draw anything but it echoes the events to stdout so one could see that they are correct.

The exposed ui events are:

popupmenu_show(items, selected, row, col)
popupmenu_select(selected)
popupmenu_hide()

items will be a list of tuples [text, kind, extra, info]. selected will either be a 0-based index or -1 if no element is selected.
To activate this mode, instead of using ui_attach(row, cols, true) use nvim_ui_attach(rows, cols, {'rgb': true, 'popupmenu_external': true}).
Alternatively nvim_ui_set_option('popupmenu_external', 'true') can be set after the ui already is attached.

@marvim marvim added the WIP label Mar 9, 2016
@tarruda
Member
tarruda commented Mar 9, 2016

It would seem unreasonable to define a member of ui_t for every ui event that would arise from an externalizied ui element. For the moment I just added (*event)(name, args) for a generic event that external gui:s care about but not the tui, but it seems like a hack over the present model. (Ref disscussion in #4322 about the distinction of ui/non-ui events).

👍 I plan to get rid of the UI structure, soon even the builtin TUI will be notified via msgpack-rpc.

Similar question could be raised about ui requests like remote_ui_try_resize. Why don't we have api/remote_ui.c and just autogenerate the msgpack validation as for all other api requests?

👍

If multiple uis (including the tui) are connected they might differ in which ui elements they implement themselves or should be drawn on the grid. The "proper" solution would be to have multiple "layers" of the grid that ui:s could show or not show but that looks too complicated at this point (it should probably wait until progress is made on the smart ui protocol). A reasonable heuristic for this case could just be: the ui that sends the keypress opening the pum determines the display mode.

I haven't thought much about how to handle "smart widgets" like a popup menu or the command line, but I imagine there's no need to have layers in the core grid structure, we just need to keep track of what is being displayed and(if applicable) where, leaving other details for the UI to define. For example, here's how I imagine the popup menu to be handled at protocol level:

// first notify UIs that they should display a popup menu at position (x,y) with the list of visible items:
[2, 'ui_display_popup_menu', {position: [x, y], visible_items: [...]}]
// each time the user presses tab, something like this is sent
[2, 'ui_popup_menu_item_changed', {selected_index: x}]
// when it needs to scroll:
[2, 'ui_popup_menu_scroll', {new_visible_items: [...], selected_index: x}]
// when the user selects a completion:
[2, 'ui_hide_popup_menu']

Note that there's no need to keep track of the widget dimensions, so it is possible for UIs to implement the widget with a different font size for example. The UI is also free to allow the user to customize such widgets(see nyaovim), this is possible because the widget is "detached" from the monospace font grid.

@bfredl
Member
bfredl commented Mar 9, 2016

Why msgpack (for tui) and not just Object ? Surely copying a Object tree is simpler and cheaper that first serializing and then deserializing msgpack ? (of course unless you plan to externalize tui to a separate process...)

With "layer" just meant the actual drawing that the core still needs to do when the tui (or an external ui not aware of a particular widget) is active, that we need to toggle on/off. But I don't see why the protocol should keep track of and send "visible" items. That would be more work (look how simple the present implementation is) and would just limit what an external ui is able to do. There is no need to restrict ui:s based on how the existing implementation presents stuff.

@wsdjeg
wsdjeg commented Mar 10, 2016

will you implement this?
#396

@tarruda
Member
tarruda commented Mar 10, 2016

of course unless you plan to externalize tui to a separate process...)\

That's the idea, to remove the builtin UI infrastructure and only maintain a system for external UIs(Though the TUI is still going to be distributed with nvim)

@bfredl
Member
bfredl commented Mar 10, 2016

@wsdjeg It will certainly move in that direction but that is a discussion thread with many ideas. Do you have any specific suggestion in mind?

For instance for more fancy widgets in the TUI (regarding @cHoco:s designs), an alternative could be to let a lua callback be called every time the the pum needs to be drawn (including redraws) and let it draw on the screen using the low-level screen_putchar etc functions (to be clear: a plugin will only be allowed to draw directly on the screen buffers in this kind of callback functions)

@wsdjeg
wsdjeg commented Mar 10, 2016

I would like to have a hotkey to open the info of current item in the popupmenu,the info can be opened below the popupmenu or on the right of the menu.I think it is a feature just like proview windows,but it is better.

@vhakulinen

Is this going to happen or what?

@bfredl
Member
bfredl commented Apr 13, 2016

@tarruda are you working on the TUI refactor soon, our should we move ahead on this before it? I think the most important refactor for this is to refactor the requests in msgpack_rpc/remote_ui.c to proper API functions in api/ui.c; we can live with ui_event in the meanwhile. Ping also @timeyyy who IIRC expressed interest on working on this.

@tarruda
Member
tarruda commented Apr 13, 2016

@tarruda are you working on the TUI refactor soon, our should we move ahead on this before it?

This doesn't clash with what I'm doing, so feel free to move ahead. It will be good to validate/improve the concept.

I noticed that we don't currently have many screen tests for the current popup menu implementation(I only found a few in test/functional/viml/completion_spec.lua), so it would be a good idea to add more coverage to ensure this maintains backwards compatibility.

@bfredl
Member
bfredl commented Apr 13, 2016

True, there has been some bugs regarding popupmenu + keys/events in the past. Sounds like a good start.

screen tests for the current popup menu in test/functional/viml/completion_spec.lua

I added those :)

@bfredl
Member
bfredl commented Apr 13, 2016

Looks we can get a long way to that by adding a screen:expect after every existing plain expect/getline in completion_spec.lua ...

@tarruda
Member
tarruda commented Apr 13, 2016

Looks we can get a long way to that by adding a screen:expect after every existing plain expect/getline in completion_spec.lua ...

👍

Using screen:expect is the way to go when testing user-visible features, as it has a good chance to represent what the user sees.

Now that the new version of the lua client(w libmpack as backend) is merged, I will work on the native nvim client, which I'm going to live in the main repository. Keeping in the main repo will improve maintainability as it will share the ugrid.c module with the core, and even the lua client will build on top of the native client. Screen:expect and native UIs will obtain its state from ugrid.c, making screen:expect even closer to what UIs will display.

@timeyyy timeyyy commented on an outdated diff Jun 6, 2016
src/nvim/popupmnu.c
} else {
ADD(args, INTEGER_OBJ(selected));
- ui_event("pum_select", args);
+ ui_event("popupmeny_select_item", args);
@timeyyy
timeyyy commented Jun 6, 2016

I got a nice little prototype going.

Might need some more tests.. haven't been able to reproduce generally but i experience a bug in a particular file where tabbing through the externalized pum (just printing), generates a call to popupmenu_show when it shouldn’t, The pum diverges from what neovim displays in this case.

Should we be generating events for colouring e.g Background/Foreground/Highlight?
In this case the colouring is quite simple but something like the status line might require a more generalized heuristic.

for the function names I think popupmenu_x is ok no need for popupmenu_x_item

@bfredl
Member
bfredl commented Jun 7, 2016

Yes it is [WIP] because of incomplete tests. Also ui_popupmenu_select_item is not tested at all (if it doesn't work it can be relegated to a later PR as it is not essential, just seems nice for an ui to allow the user to control the menu with mouse for instance)

a call to popupmenu_show when it shouldn’t

Is this a transient, i.e. immediately followed by another show or hide, or is the final visual state different ? Any specifics that triggers it like a certain complete source?

Should we be generating events for coloring e.g Background/Foreground/Highlight?

Not sure, the ui could potentially do more fanciful coloring than the buildin, like different colors for different item kinds. For now let's say the ui could read the Pmenu etc values if it likes, or use its own coloring. (I would imagine a gtk/qt ui could just use the native menu widget with system colors).

for the function names I think popupmenu_x is ok no need for popupmenu_x_item

Sounds good, I will update the names.

@bfredl
Member
bfredl commented Jun 8, 2016 edited

Updated (still not done), new names are

request:
ui_set_popupmenu_external(true/false)

events:
popupmenu_show(items, selected)
popupmenu_select(selected)
popupmenu_hide()

I removed ui_popupmenu_select_item because the implementation is entirely independent; let's add it in a followup PR.

@timeyyy
timeyyy commented Jun 8, 2016 edited

popupmenu_select SEEMS to be working.

Is this a transient, i.e. immediately followed by another show or hide, or is the final visual state different ? Any specifics that triggers it like a certain complete source?

A single call to popupmenu_show occurs, the visual state is then different from what vim is showing. (As far as i understand popupmenu_show should replace all existing items in the pum with the new items?, this is what i have implemented)
The behaviour is repeatable on the same file and same keyword. It seems to happen more readily if there are >5 items

For now let's say the ui could read the Pmenu etc values if it likes,

If the colours used by vim for the pum can be accessed i think that is enough. Could you give an example :h Pmenu was a bit vauge.

@equalsraf
Contributor

Having a look at this we seem to be doing two things at once in this PR

  1. Allow the UI to render the popupmenu using a custom widget
  2. Provide an API for the UI to manipulate the popupmenu (popupmenu_select)

Whats bothering me is the need for the UI to "register" (ui_set_popupmenu_external) to enable this feature, because one UI could register and mess up the user experience for a second UI that is attached (or attaches later) where the popupmenu would then be invisible (at least thats my impression, pum_wants_external is global, not per UI).

But it seems to me that point 1. should be possible without the need for ui_set_popupmenu_external but I'm not sure about 2. yet. If anything because vim/vim had a very similar design for the gui APIs.

As is, when the external popupmenu is disabled Neovim sends the usual redraw events to paint the popup. When the external popupmenu is enabled Neovim skips sending the regular redraw events and instead sends this menu contents.

I wonder if we can't use the new events to tell the UI that I'm about to draw the menu but if you want instead you can draw it yourself and here is the data (something like this).

The downside of doing it like this is the extra data sent in events i.e. the pum always goes out. Another way to go about it would be to make pum_wants_external a per UI setting.

@timeyyy
timeyyy commented Jun 8, 2016 edited

Another way to go about it would be to make pum_wants_external a per UI setting.

I like this. Use the normal draw method as a default, and each gui requests what it wants to handle.

@bfredl
Member
bfredl commented Jun 8, 2016

I wonder if we can't use the new events to tell the UI that I'm about to draw the menu

I suppose that is roughly what I meant with "multiple layers of the grid that ui:s could show or not show" I looked briefly into it when starting this, if it could be as simple as hinting "now I'm drawing this/that, don't draw if you don't like that" but it isn't because of the buffering into ScreenLines, so this would need quite some refactor.

at least thats my impression, pum_wants_external is global, not per UI

It happens to be global in the present internal implementation, but it is already per UI in the protocol (which is why the UI needs to "register"), so to forward enable doing something better. As I said, a simple possible heuristic is: the ui that sends the keypress opening the pum determines the display mode.

Provide an API for the UI to manipulate the popupmenu (popupmenu_select)

I removed this for now as it is implementationwise completely separate and just as well could be a separate PR (and the changed logic in edit.c is much more complex than popupmenu.c and thus much more testing is needed)

@equalsraf
Contributor

draw if you don't like that" but it isn't because of the buffering into ScreenLines, so this would need quite some refactor.

I see, then my assumption is flawed to begin with. The TUI would probably need to store the pum in order for this to work like that, rather than drawing into the screenlines. Thinking about it a bit further this makes sense, the UI/TUI have the exact same API and work based on the same state (at the core) so any side effects of one apply to the other.

(which is why the UI needs to "register")

Is it preferable to have a separate function for this, or just make it part of ui_attach()? Looking forward it seems the UI would have to call one such function for every externalized feature.

Making it part of attachment also has another advantage, it allows us to disable/enable the external pum based on which UIs are attached, i.e. the external pum is enabled if all attached UIs support it. Does that make more sense?

Sure it can break user experience a bit in cases when multiple UIs are attached. but it also avoids issues when we sequentially attach and detach different UIs (or even the TUI).

As I said, a simple possible heuristic is: the ui that sends the keypress opening the pum determines the display mode.

Not sure if this would help. If the pum can be triggered by a script what would happen? I'd rather leave it as it is then.

I removed this for now as it is implementationwise completely separate and just as well could be a separate PR (and the changed logic in edit.c is much more complex than popupmenu.c and thus much more testing is needed)

👍 I get the feeling one would need to deal with input on the GUI while the pum is active, which brings out other types of issues that go far beyond Neovim.

@bfredl
Member
bfredl commented Jun 9, 2016 edited

Not sure if this would help. If the pum can be triggered by a script what would happen? I'd rather leave it as it is then.

I meant to do this in practice by just keep track of whatever ui sent the last vim_input to handle all the sorts of indirections that are possible in completion triggering. But "the external pum is enabled if all attached UIs support it." as you said is probably good enough. I reckon the vast majority of nvim uses will have exactly one ui attached, at least one at a time, so prioritizing this use case while offering reasonable fallback for multi-ui should be good enough.

I get the feeling one would need to deal with input on the GUI while the pum is active, which brings out other types of issues that go far beyond Neovim.

Just curious, how does this go "far beyond Neovim"? For me this is a question of enumerating all the possible states that nvim can be in during insert/completion/popup-menu mode and testing we do something reasonable in all of them.

or just make it part of ui_attach()?

This sounds like a good design, but we need to be aware that the features could have parameters to set. For the popupmenu we might want to allow the ui to tell nvim the number of visible items, to make PgUp/PgDown scrolling more natural. This could easily change during runtime because of a screen resolution or font change. Still one could imagine a single ui_set_option or something instead of one function per feature.

@equalsraf
Contributor

I reckon the vast majority of nvim uses will have exactly one ui attached, at least one at a time, so prioritizing this use case while offering reasonable fallback for multi-ui should be good enough.

True, I was also concerned with consecutive attach/detach of different UIs. Because if one UI attaches and enables the external pum and then detaches, the next UI would them have to explicitly disable the external pum. Since it would need to be explicit anyway, that is why I suggested making it part of attach.

This sounds like a good design, but we need to be aware that the features could have parameters to set.

I do agree I would not like to have 100 parameters in ui_attach, so maybe an dictionary would be preferable. Not sure here.

Just curious, how does this go "far beyond Neovim"?

I meant from the point of view of the UI usability.

When the popup menu is show, and assuming the UI intends to control the movement on the popup and them call Neovim to select the entry, this means the UI would now control input keys instead of just passing it to vim_input. Which keys cause you to leave the popup or move up/down would them be controlled by the UI, with no respect for Neovim key mappings, etc.

This is not Neovim's fault, if the UI tries to be "too" smart about input, some usability expectations might be broken.

@bfredl
Member
bfredl commented Jun 9, 2016

Since it would need to be explicit anyway, that is why I suggested making it part of attach.

But this concern has nothing to with the API, i e whether the information is part of ui_attach or a separate method, but is a limitation of the WIP implementation. We could recalculate pum_wants_external also on attach/detach without changing the API at all. ui_set_popupmenu_external already requires the ui to be attached for this reason, but the implementation was left simple because it's better to have the discussion before implementing more logic in a WIP PR.

But if we have the explicit goal to minimize the number of methods, I would imagine the best would be to have ui_attach taking a dict of options + ui_set_option to allow them to be changed later.

this means the UI would now control input keys instead of just passing it to vim_input.

No, the keyboard should always be handled by nvim (the ui should instead tell nvim in advance much much a PgDown is, for instance), the purpose is rather for the mouse, if the ui draws a native menu widget with a scrollbar the user soon or later will try to scroll and select an item using the mouse.

@equalsraf
Contributor

But this concern has nothing to with the API, i e whether the information is part of ui_attach or a separate method, but is a limitation of the WIP implementation. ...

True I just felt it would be clearer like that.

@bfredl
Member
bfredl commented Jun 16, 2016

Prototyped the "ui options" concept. It follows the same "worst case" reduction as for clients with different screen sizes, so it is consistent with that, which is nice. For instance in the python-gui branch it is now bridge.attach(80, 24, rgb=True, popupmenu_external=True) .

@justinmk
Member
justinmk commented Jun 17, 2016 edited

#4842 may benefit from the work here, though it may also be helped by UIEnter event. (Perhaps a generic ClientConnected event would eliminate the need for UIEnter.)

@timeyyy
timeyyy commented Jun 30, 2016 edited

By providing the flexibility of externalizing only certain ui elements are we wasting our time?

I am reminded of the blog post by tarruda, the plan was when the smart_ui_protocol would be used, then the old protocol would be disabled (for that client i guess?).

I think this simplifies things for us a lot, either a client is using the smart protocol (externalizing elements) or he is not.

In the case that we decide to keep the old protocol and selectively externalize elements a lot more work is required. It would be nice to have of course, but i feel we would be better off prioritizing doing the new protocol.

For embedders it is better to just go with the protocol designed for gui's, and ditch the old protocol based on the terminal screen.

@bfredl
Member
bfredl commented Jun 30, 2016 edited

By providing the flexibility of externalizing only certain ui elements are we wasting our time?

I don't believe it is feasible to have one big PR which completely transforms how everything is drawn/communicated with external ui at once. The end goal might be a single global switch, but if a little bit of extra logic allows small improvements to reach end users soon, instead of waiting for everything to arrive in maybe a year or two from now, I won't call it a waste.

but i feel we would be better off prioritizing doing the new protocol.

The goal of this PR is precisely to find out how how the "new protocol" will represent the popupmenu. I don't see how the PR being usable right now could be a determent to that goal.

@timeyyy
timeyyy commented Jun 30, 2016

I will go ahead and test the new implementation.

Could you maybe tidy up this thread and just leave a summary of the current implementation? It's a bit hard to follow.

@bfredl
Member
bfredl commented Jun 30, 2016 edited

The events are:

popupmenu_show(items, selected)
popupmenu_select(selected)
popupmenu_hide()

items will be a list of tuples [text, kind, extra, info]. selected will either be a 0-based index or -1 if no element is selected.
To activate this mode, instead of using ui_attach(row, cols, true) use nvim_ui_attach(rows, cols, {'rgb': true, 'popupmenu_external': true}).

I can't find external ui in the docs, but this should be added as a section to msgpack_rpc.txt.

@romgrk
Contributor
romgrk commented Jun 30, 2016

Shouldn't the position of the popup upon popupmenu_show be provided by the server? Computing it on the UI side might result in a wrong alignement. (Unless like, calling the omnifunc through the neovim API; hacky)

@timeyyy
timeyyy commented Jun 30, 2016

The starting point of the pum would be nice to have i agree, one less thing for implementers to worry about

@fmoralesc
Contributor

Shouldn't the position of the popup upon popupmenu_show be provided by the server?

As long as the client is allowed to override it -- it will be necessary when the clients escape the grid model (one can hope!) ;)

@romgrk
Contributor
romgrk commented Jul 1, 2016

Yeah. Meanwhile this is cool. Here's a quick prototype in HTML/CSS. Thanks @bfredl.

screenshot from 2016-07-01 02-39-53

(Though there here a few issues with the implementation. Should I make more specific reports? Is this going to be merged?)

@bfredl
Member
bfredl commented Jul 1, 2016

I added the anchor position (the first char in the completed word) to popupmenu_show(). The ui is of course free to to ignore it : )

Should I make more specific reports?

Please do.

@equalsraf equalsraf added a commit to equalsraf/neovim-qt that referenced this pull request Jul 1, 2016
@equalsraf equalsraf FIXME Update bindings
These were updated against neovim/neovim#4432, but the API might not
be final, recall `make bindings` if needed and before merging into
master.
b15b4f3
@equalsraf
Contributor

:D looking good, testing here https://github.com/equalsraf/neovim-qt/tree/tb-pum

neovimqt

I still have to work on placement though.

The only issue I've noticed is that pressing Down in the TUI cycles the options. But in the GUI it moves the cursor (i.e. closes the popup). But maybe its an input bug in neovim-qt (screengrab here)

@bfredl
Member
bfredl commented Jul 1, 2016

pum_visible() was not always correct, please try latest commit.

@equalsraf
Contributor

@bfredl thanks, looks fixed here

@equalsraf equalsraf added a commit to equalsraf/neovim-qt that referenced this pull request Jul 1, 2016
@equalsraf equalsraf FIXME Update bindings
These were updated against neovim/neovim#4432, but the API might not
be final, recall `make bindings` if needed and before merging into
master.
082ddc3
@equalsraf
Contributor

To activate this mode, instead of using ui_attach(row, cols, true) use ui_attach_options(rows, cols, {'rgb': true, 'popupmenu_external': true}). (though we could actually call this ui_attach and be backwards compatible by checking if options is a bool instead of a dict).

I was wondering how to handle this too. AFAIK there is no version info in the api metadata so when I merge this with neovim-qt I'll be depending on a later version of Neovim, this is fine since neovim-qt determines compatibility based on the metadata api info. But what will be the 3rd argument reported in the api metadata for ui_attach? [Dictionary, options] or [Boolean, enable_rgb]?

If its a Dictionary we would be breaking compatibility, if it remains as Boolean then the GUI would have no way to know the new API is also available.

@equalsraf equalsraf referenced this pull request in equalsraf/neovim-qt Jul 1, 2016
Open

Support for GUI popup menu #150

@equalsraf equalsraf added a commit to equalsraf/neovim-qt that referenced this pull request Jul 3, 2016
@equalsraf equalsraf FIXME Update bindings
These were updated against neovim/neovim#4432, but the API might not
be final, recall `make bindings` if needed and before merging into
master.
57e4033
@romgrk
Contributor
romgrk commented Jul 4, 2016

If its a Dictionary we would be breaking compatibility, if it remains as Boolean then the GUI would have no way to know the new API is also available.

Does the API follow semver? Is it 1.0? Are there people out there using the API and whitout following closely development?

@bfredl
Member
bfredl commented Jul 4, 2016

Does the API follow semver? Is it 1.0?

The API is 0.x, but we try to avoid breaking changes if we can, at least have deprecations before removing/breaking stuff.

If its a Dictionary we would be breaking compatibility, if it remains as Boolean then the GUI would have no way to know the new API is also available.

If we don't do anything special the api type would be "Object". It should not break any dynamically typed client code nor would I expect it to break c++ code but in general for a statically typed client a type widening could be a breaking change...

@bfredl
Member
bfredl commented Jul 15, 2016

From gitter I was reminded that ui_attach is not in the metadata for latest released version 0.1.4. So we could just include the "new" signature in the metadata (even under the different name nvim_ui_attach if we merge #4934 first), while still accepting messages under the "old" format (generated by clients, static or dynamic, without any usage of the metadata).

@bfredl bfredl changed the title from [WIP] externalize ui elements like the popup menu? to [RFC] allow external uis to render the popupmenu Jul 17, 2016
@bfredl
Member
bfredl commented Jul 17, 2016

Still some TODOs left (and documentation...), but this should be feature-wise ready now so marking RFC.
The first post was updated with new method names.

@marvim marvim added RFC and removed WIP labels Jul 17, 2016
@equalsraf equalsraf added a commit to equalsraf/neovim-qt that referenced this pull request Jul 18, 2016
@equalsraf equalsraf FIXME Update bindings
These were updated against neovim/neovim#4432, but the API might not
be final, recall `make bindings` if needed and before merging into
master.
f647743
@bfredl
Member
bfredl commented Aug 15, 2016

I began work on documenting the ui update events, mostly from looking at the tui and python-gui implementation. Note it assumes #4934. Probably some incorrect statements lurking as I never implemented a gui myself... (and inconsistent grammar: do the updates say what did happen in nvim, or what the client should display?)

@romgrk
Contributor
romgrk commented Aug 19, 2016

If you want feedback drop a comment. I implemented this below as a React component on top of NyaoVim.

From an UI implementor POV, I would rather know what happens in nvim, not what I should display (let me choose what I display).

popup

(Actually the whole screen is a React component; spans and divs all the way, no canvas)

@timeyyy timeyyy and 1 other commented on an outdated diff Aug 19, 2016
runtime/doc/msgpack_rpc.txt
+
+Nvim will then send msgpack-rpc notifications, with the event name "redraw"
+and a single argument, which is an array of screen updates, described below,
+that should be processed in order. Preferably, the user should only be able to
+see the screen state after all updates are processed, not any intermediate
+state after processing only a part of the array.
+
+Screen updates are arrays, where the first element a string decribing the kind
+of update:
+
+["resize", width, height]
+ The internal screen was resized to `width` and `height` cells.
+
+["clear"]
+ Clear the screen. The screen should be filled with the default
+ background color.
@timeyyy
timeyyy Aug 19, 2016 edited

Clear the screen. That is, bring the screen back to the default state.

@bfredl
bfredl Aug 20, 2016 Member

Does this really need to be elaborated? The next sentence says already what should happen.

@fwalch fwalch referenced this pull request in neovim/neovim.github.io Aug 19, 2016
Merged

Newssssssssss #136

@bfredl
Member
bfredl commented Aug 20, 2016

From an UI implementor POV, I would rather know what happens in nvim, not what I should display (let me choose what I display).

Yeah, as the plan is to make the ui model in the future less rigid, this convention makes more sense.

My plan was to merge this after #4934, but as that one is blocked for longer than I expected (I thought 0.1.5 was going to be released soon...), let's merge this one first. We can live with ui_ methods being changed to nvim_ prefix first (just need nvim_ui_detach alias for ui_detach).

@timeyyy timeyyy and 2 others commented on an outdated diff Aug 20, 2016
runtime/doc/msgpack_rpc.txt
+
+Nvim will then send msgpack-rpc notifications, with the event name "redraw"
+and a single argument, which is an array of screen updates, described below,
+that should be processed in order. Preferably, the user should only be able to
+see the screen state after all updates are processed, not any intermediate
+state after processing only a part of the array.
+
+Screen updates are arrays, where the first element a string decribing the kind
+of update:
+
+["resize", width, height]
+ The internal screen is resized to `width` and `height` cells.
+
+["clear"]
+ Clear the screen. The screen is filled with the default
+ background color.
@timeyyy
timeyyy Aug 20, 2016

my issue with this statements is that it implies that this functions is setting the background colour.

Clear the screen. is probably self explanatory enough.

@bfredl
bfredl Aug 20, 2016 Member

we could fix that by putting this one after update_bg

@timeyyy
timeyyy Aug 20, 2016 edited

it would help, but that last sentence is more confusing then helpful i think.

@romgrk
romgrk Aug 20, 2016 Contributor

Agreeing with @timeyyy. I spent some time trying to interpret the meaning of this event. (Eg should I clear ALL information of the screen or just update the bg?). There is also the fact that the events are mostly written with the TUI interface in mind, but that's another problem.

@bfredl
bfredl Aug 21, 2016 Member

Just setting the background color wouldn't fill the screen, no? But you're right "Clear the screen" is enough here.

There is also the fact that the events are mostly written with the TUI interface in mind, but that's another problem.

This is because is the vim/nvim internal model pretty much is a terminal grid currently (with a few additions as I mentioned)

@timeyyy timeyyy and 1 other commented on an outdated diff Aug 20, 2016
runtime/doc/msgpack_rpc.txt
@@ -252,4 +253,169 @@ RPC functions are available in Vimscript:
a nvim server. |v:servername|
==============================================================================
+7. Remote UIs *rpc-remote-ui*
+
+Nvim allows Graphical user interfaces to be implemented by separate processes
+communicating with Nvim over the RPC api. Currently the ui model conists of a
+terminal-like grid with one single, monospace font size, with a few elements
+that could be drawn separately from the grid (for the momemnt only the popup
+menu)
+
+After connecting to a nvim instance (typically a spawned, embedded instance)
+use the |nvim_ui_attach|(width, height, options) api method to tell nvim that your
+program wants to draw the nvim screen on a grid with "width" times
+"height" cells. "options" should be a dictionary with the following (all
+optional) keys:
+ `rgb`: recieve rgb color values with 8-bit per channels
@timeyyy
timeyyy Aug 20, 2016 edited

after reading this i'm still not sure what it's meant to do, also the indenting

@bfredl
bfredl Aug 20, 2016 edited Member

it is the two different color representations [neo]vim supports. Most ui clients will want to have rgb colors ("true color"), but say, a terminal client to a nvim headless server would want to get terminal color codes from nvim if that's what the terminal supports.
You mean the actual indention in the file and not just github's broken diff indention?

@timeyyy
timeyyy Aug 20, 2016 edited

something like this then maybe.

rgb: control the color pallet

Set to false to use 8 bit color palette
Set to true to use 24 bit color palette

it could be github

@timeyyy timeyyy commented on an outdated diff Aug 20, 2016
runtime/doc/msgpack_rpc.txt
+"height" cells. "options" should be a dictionary with the following (all
+optional) keys:
+ `rgb`: recieve rgb color values with 8-bit per channels
+ if true, terminal color palette numbers if
+ false. Defaults to true.
+ `popupmenu_external`: Instead of drawing the completion popupmenu on
+ the grid, Nvim will send higher-level events to
+ the ui and let it draw the popupmenu.
+ Defaults to false.
+
+Nvim will then send msgpack-rpc notifications, with the event name "redraw"
+and a single argument, which is an array of screen updates, described below,
+that should be processed in order. Preferably, the user should only be able to
+see the screen state after all updates are processed, not any intermediate
+state after processing only a part of the array.
+
@timeyyy
timeyyy Aug 20, 2016 edited

Nvim will then send msgpack-rpc notifications containing a "redraw" event
and a single argument, an array of screen updates (described below).
These updates should be processed in order. Preferably the user should only be able to
see the screen state after all updates are processed (not intermediate
states after processing only a part of the array).

@timeyyy timeyyy commented on an outdated diff Aug 20, 2016
runtime/doc/msgpack_rpc.txt
+optional) keys:
+ `rgb`: recieve rgb color values with 8-bit per channels
+ if true, terminal color palette numbers if
+ false. Defaults to true.
+ `popupmenu_external`: Instead of drawing the completion popupmenu on
+ the grid, Nvim will send higher-level events to
+ the ui and let it draw the popupmenu.
+ Defaults to false.
+
+Nvim will then send msgpack-rpc notifications, with the event name "redraw"
+and a single argument, which is an array of screen updates, described below,
+that should be processed in order. Preferably, the user should only be able to
+see the screen state after all updates are processed, not any intermediate
+state after processing only a part of the array.
+
+Screen updates are arrays, where the first element a string decribing the kind
@timeyyy
timeyyy Aug 20, 2016

Screen updates are arrays. The first element is a string decribing the kind
of update.

@justinmk justinmk and 1 other commented on an outdated diff Aug 20, 2016
src/nvim/popupmnu.c
+ ADD(item, STRING_OBJ(cstr_to_string((char *)array[i].pum_info)));
+ ADD(arr, ARRAY_OBJ(item));
+ }
+ ADD(args, ARRAY_OBJ(arr));
+ ADD(args, INTEGER_OBJ(selected));
+ ADD(args, INTEGER_OBJ(row));
+ ADD(args, INTEGER_OBJ(col));
+ ui_event("popupmenu_show", args);
+ } else {
+ ADD(args, INTEGER_OBJ(selected));
+ ui_event("popupmenu_select", args);
+ }
+ pum_is_visible = true;
+ return;
+ }
+
def_width = PUM_DEF_WIDTH;
max_width = 0;
kind_width = 0;
extra_width = 0;
// Pretend the pum is already there to avoid that must_redraw is set when
// 'cuc' is on.
@justinmk
justinmk Aug 20, 2016 Member

this pattern is used a couple times, maybe wrap it in a function.

@bfredl
bfredl Aug 20, 2016 Member

Actually I think we could stop saying that we're pretending and just let pum_is_visible be true from here on.

@justinmk justinmk commented on an outdated diff Aug 20, 2016
test/functional/ui/screen.lua
end
-- print(self:_current_screen())
end
end
+function Screen:on_event(callback)
@justinmk
justinmk Aug 20, 2016 Member

set_on_event_handler ?

@justinmk
Member
justinmk commented Aug 20, 2016 edited

LGTM. Though I agree with @timeyyy about tweaking the doc, it doesn't need to block this, we can always improve docs later.

Lots of good discussion above about the obvious question, "how to handle multiple UIs". Did we consider this (future) approach:

  • Maintain internally two different screen grids.
    • One "TUI screen" for TUI-like UIs which has the legacy "inlined" widgets (such as popupmenu)
    • One "minimal screen", which does not "inline" externalized widgets, and expects non-TUI-like UIs to handle the externalized widgets.

Though maintaining 2 screens has a performance cost, it would only happen if multiple UIs with dissimilar capabilities were connected.

@bfredl
Member
bfredl commented Aug 20, 2016

Almost, my thought before was that that widgets would be separate grid layer (which then could be stored smaller than full-screen), possibly merged at the neovim side or even just layer-switch events a simple gui will ignore.

Though maintaining 2 screens has a performance cost, it would only happen if multiple UIs with dissimilar capabilities were connected.

I wonder how often that will be, and how high expectations users would have on that. For instance a future smart-ui mode where windows are separate grids will only work with clients that allow that, I don't see how we can support a full-screen grid and multi-window at the same time (especially as once a buffer will be on its own grid with no splits, it will be really tempting to start break away from the rigid monofont grid), nor that someone really would expect that.

@bfredl
Member
bfredl commented Aug 20, 2016

A TODO left for a potential leak/memory issue, and I will go through the existing suggestions, but otherwise it should be more or less ready.

@justinmk
Member

I don't see how we can support a full-screen grid and multi-window at the same time

Right, scrap the idea of 2 internal screens. Better to just force the built-in TUI (which may someday be externalized) to overlay the widgets like any other smart UI.

The tradeoff would be that it forces all UIs to be more sophisticated: the more we externalize widgets, the harder it is to implement a UI prototype--that is, if we stop offering the "dumb layout". We could ameliorate that by providing a built-in function that synthesizes all widgets into a "dumb layout".

@timeyyy
timeyyy commented Aug 20, 2016 edited

When everything gets externalized i would see it being much easier to implement than the current implementation.

I am interested in having a neovim editor embed. I would also like to connect random widgets, search bar etc, entry fields. Mainly for the convinence of using vim movements but also for utilizing plugins.

We should estimate how much work it would take to allow multiple screens to be attached. I don't think it's so urgent, (nice to have), but neovim starts quick and the footprint is fairly low so even having two or more instances of neovim open is not so bad i.m.o

@justinmk
Member
justinmk commented Aug 20, 2016 edited

The multiple UI concept isn't driven by performance; if that were the only use-case I would say it should be discarded totally. I've always been in favor of "peer-to-peer" nvims communicating without a central server.

Though I must admit I don't actually know a strong reason for connecting multiple UIs. Peer communication and sharing of structures like buffers/registers/cursor position/etc solves the use-case that most people have.

Why do we care about multiple UIs connecting to a single server? It gives us many difficult problems to solve.

Shared sessions could be achieved (with greater flexibility) by sharing events over RPC.

@timeyyy
timeyyy commented Aug 20, 2016 edited

The multiple UI concept isn't driven by performance

Ah true i kind of contradicted myself there.

I also have 0 use cases.

@bfredl
Member
bfredl commented Aug 20, 2016 edited

Why do we care about multiple UIs connecting to a single server? It gives us many difficult problems to solve.

There seems to be two separate issues here. What I'm saying we don't need to actively support well is "hetreogenous" sharing, different clients with very different ideas how nvim should be presented. (It is okay in this case to give them the lowest common denominator, refuse to work at all, and such) It is a separate issue whether we should allow two clients that are similar (has the same capabilities) i.e. by being instances of the same codebase. For collaborative editing for instance I wouldn't a priori exclude the idea of two different frontends communicating with a nvim server, which maybe might show the same or different layouts, but at least work on the same level of representation.

@romgrk
Contributor
romgrk commented Aug 20, 2016

The tradeoff would be that it forces all UIs to be more sophisticated: the more we externalize widgets, the harder it is to implement a UI prototype--that is, if we stop offering the "dumb layout". We could ameliorate that by providing a built-in function that synthesizes all widgets into a "dumb layout".
-- justinmk

Currently, a UI prototype is fairly easy to set up. On the contrary, it's even frustrating to be limited to the capabilities of neovim. For example, if I wanted to render the line number gutter in the UI, or display additional inline widgets in the gutter, there is no way to do so because the UI only gets the vim-rendered full-lines (line-number + line-content). It would be way easier to have the information about the interface rather than the nvim representation of it.

For collaborative editing for instance I wouldn't a priori exclude the idea of two different frontends communicating with a nvim server, which maybe might show the same or different layouts, but at least work on the same level of representation.
-- bfredl

I think maybe what should be shared in that case is the representation of the buffer, and that said representation might be better kept somewhere else than neovim. (Eg to allow multiple people with different editors to work together)

@bfredl
Member
bfredl commented Aug 21, 2016

On the contrary, it's even frustrating to be limited to the capabilities of neovim. For example, if I wanted to render the line number gutter in the UI, or display additional inline widgets in the gutter, there is no way to do so because the UI only gets the vim-rendered full-lines (line-number + line-content). It would be way easier to have the information about the interface rather than the nvim representation of it.

Agree. What this pr aims to do is set up a pattern that can be reused for other elements. Next thing I would investigate myself is externalizing the pager/cmdline display the same way, as it is currently what temporarily can break the window layout and thus it would be a prerequisite for client-side window layout. Other low-hanging fruit might be signs icons and per-window scrollbars like gvim allows, though here we might not need an option, just send the information to the ui and let it use it if it wants to.

I think maybe what should be shared in that case is the representation of the buffer, and that said representation might be better kept somewhere else than neovim. (Eg to allow multiple people with different editors to work together)

Though that wouldn't be "better" or "worse" but a different solution with very different trade-offs. A multi-editor solution would allow the most number of people to collaborate, while a nvim-specific "real-time shada"/rpc solution will allow sharing with nvim-semantics of registers/marks/persistent variables and so forth, while two frontends to the same instance will allow sharing of everything at the expense of only allowing one input mode/focus, which might be what you want anyway for some styles of pair-programming.

@oni-link oni-link commented on an outdated diff Aug 21, 2016
src/nvim/api/ui.c
@@ -88,21 +91,46 @@ void ui_attach(uint64_t channel_id, Integer width, Integer height,
ui->suspend = remote_ui_suspend;
ui->set_title = remote_ui_set_title;
ui->set_icon = remote_ui_set_icon;
+ ui->event = remote_ui_event;
+
+ for (size_t i = 0; i < options.size; i++) {
+ ui_set_option(ui, options.items[i].key, options.items[i].value, err);
+ if (err->set) {
+ xfree(ui);
+ xfree(data);
@oni-link
oni-link Aug 21, 2016 Contributor

The allocation of data could be delayed after setting the options.

@oni-link oni-link commented on an outdated diff Aug 21, 2016
src/nvim/api/ui.c
}
-void ui_detach(uint64_t channel_id, Error *err)
+/// @deprecated
+void ui_attach(uint64_t channel_id, Integer width, Integer height,
+ Boolean enable_rgb, Error *err)
+{
+ Dictionary opts = ARRAY_DICT_INIT;
+ PUT(opts, "rgb", BOOLEAN_OBJ(enable_rgb));
+ nvim_ui_attach(channel_id, width, height, opts, err);
+ api_free_dictionary(opts);
+}
+
+void nvim_ui_detach(uint64_t channel_id, Error *err)
{
if (!pmap_has(uint64_t)(connected_uis, channel_id)) {
api_set_error(err, Exception, _("UI is not attached for channel"));
}
@oni-link
oni-link Aug 21, 2016 Contributor

We could return; here.

@oni-link oni-link commented on the diff Aug 21, 2016
src/nvim/api/ui.c
{
if (!pmap_has(uint64_t)(connected_uis, channel_id)) {
api_set_error(err, Exception, _("UI is not attached for channel"));
}
remote_ui_disconnect(channel_id);
}
-Object ui_try_resize(uint64_t channel_id, Integer width,
- Integer height, Error *err)
+/// @deprecated
+void ui_detach(uint64_t channel_id, Error *err)
+{
+ nvim_ui_detach(channel_id, err);
+}
+
+void nvim_ui_try_resize(uint64_t channel_id, Integer width,
+ Integer height, Error *err)
{
if (!pmap_has(uint64_t)(connected_uis, channel_id)) {
api_set_error(err, Exception, _("UI is not attached for channel"));
@oni-link
oni-link Aug 21, 2016 Contributor

Here we should return;.

@oni-link oni-link commented on the diff Aug 21, 2016
src/nvim/api/ui.c
}
UI *ui = pmap_get(uint64_t)(connected_uis, channel_id);
ui->width = (int)width;
ui->height = (int)height;
ui_refresh();
- return NIL;
+}
+
+/// @deprecated
+void ui_try_resize(uint64_t channel_id, Integer width,
@oni-link
oni-link Aug 21, 2016 Contributor

Is it okay to change the return type?

@bfredl
bfredl Aug 21, 2016 Member

it should be, the wire format doesn't change, and this method didn't have any static return type in latest released version 0.1.4 as #4817 was done later

@oni-link oni-link commented on an outdated diff Aug 21, 2016
src/nvim/api/ui.c
+ api_set_error(error, Exception, _("UI is not attached for channel"));
+ return;
+ }
+ UI *ui = pmap_get(uint64_t)(connected_uis, channel_id);
+
+ ui_set_option(ui, name, value, error);
+ if (!error->set) {
+ ui_refresh();
+ }
+}
+
+static void ui_set_option(UI *ui, String name, Object value, Error *error) {
+ if (strcmp(name.data, "rgb") == 0) {
+ if (value.type != kObjectTypeBoolean) {
+ api_set_error(error, Validation, _("rgb must be a Boolean"));
+ }
@oni-link
oni-link Aug 21, 2016 Contributor

Here we could use return;.

@oni-link oni-link commented on an outdated diff Aug 21, 2016
src/nvim/api/ui.c
+ ui_set_option(ui, name, value, error);
+ if (!error->set) {
+ ui_refresh();
+ }
+}
+
+static void ui_set_option(UI *ui, String name, Object value, Error *error) {
+ if (strcmp(name.data, "rgb") == 0) {
+ if (value.type != kObjectTypeBoolean) {
+ api_set_error(error, Validation, _("rgb must be a Boolean"));
+ }
+ ui->rgb = value.data.boolean;
+ } else if (strcmp(name.data, "popupmenu_external") == 0) {
+ if (value.type != kObjectTypeBoolean) {
+ api_set_error(error, Validation, _("popupmenu_external must be a Boolean"));
+ }
@oni-link
oni-link Aug 21, 2016 Contributor

Here we could use return;.

@oni-link oni-link commented on an outdated diff Aug 21, 2016
src/nvim/popupmnu.c
validate_cursor_col();
- pum_array = NULL;
-
- row = curwin->w_wrow + curwin->w_winrow;
+ pum_is_visible = false;
@oni-link
oni-link Aug 21, 2016 Contributor

Why do we need this again? validate_cursor_col() was already used further up.

@oni-link oni-link commented on the diff Aug 21, 2016
src/nvim/popupmnu.c
@@ -53,7 +58,7 @@ static int pum_do_redraw = FALSE; // do redraw anyway
/// @param array
/// @param size
/// @param selected index of initially selected item, none if out of range
@oni-link
oni-link Aug 21, 2016 Contributor

Missing entry for @param array_changed.

@oni-link oni-link commented on an outdated diff Aug 21, 2016
src/nvim/popupmnu.c
@@ -36,8 +38,11 @@ static int pum_scrollbar; // TRUE when scrollbar present
static int pum_row; // top row of pum
static int pum_col; // left column of pum
-static int pum_do_redraw = FALSE; // do redraw anyway
+static bool pum_is_visible = false;
+static bool pum_do_redraw = false; // do redraw anyway
@oni-link
oni-link Aug 21, 2016 Contributor

pum_do_redraw is only set before calls to update_screen() in pum_set_selected(), so that the pum is not drawn when updating the screen. Can't we just set pum_is_visible = false before calling update_screen() in pum_set_selected() and remove the variable pum_do_redraw completly?

@oni-link oni-link commented on the diff Aug 21, 2016
src/nvim/ui.c
for (size_t i = 0; i < ui_count; i++) {
UI *ui = uis[i];
width = ui->width < width ? ui->width : width;
height = ui->height < height ? ui->height : height;
+ pum_external &= ui->pum_external;
@oni-link
oni-link Aug 21, 2016 Contributor

Is bitwise & operator what should be used here?

@bfredl
bfredl Aug 21, 2016 Member

well &&= doesn't exist, and as bool is semantically 1-bit it works correctly. But if the style guide or otherwise forbids it I will change it.

@bfredl
Member
bfredl commented Aug 21, 2016

Thanks you all for all comments, updated.

@oni-link oni-link commented on an outdated diff Aug 22, 2016
runtime/doc/msgpack_rpc.txt
@@ -238,4 +239,170 @@ the type codes, because a client may be built against one Nvim version but
connect to another with different type codes.
==============================================================================
+6. Remote UIs *rpc-remote-ui*
+
+Nvim allows Graphical user interfaces to be implemented by separate processes
+communicating with Nvim over the RPC api. Currently the ui model conists of a
@oni-link
oni-link Aug 22, 2016 Contributor

api -> API

@oni-link oni-link commented on an outdated diff Aug 22, 2016
runtime/doc/msgpack_rpc.txt
@@ -238,4 +239,170 @@ the type codes, because a client may be built against one Nvim version but
connect to another with different type codes.
==============================================================================
+6. Remote UIs *rpc-remote-ui*
+
+Nvim allows Graphical user interfaces to be implemented by separate processes
+communicating with Nvim over the RPC api. Currently the ui model conists of a
+terminal-like grid with one single, monospace font size, with a few elements
+that could be drawn separately from the grid (for the momemnt only the popup
+menu)
+
+After connecting to a nvim instance (typically a spawned, embedded instance)
+use the |nvim_ui_attach|(width, height, options) api method to tell nvim that your
@oni-link
oni-link Aug 22, 2016 Contributor

api -> API

@oni-link oni-link commented on an outdated diff Aug 22, 2016
runtime/doc/msgpack_rpc.txt
+Nvim allows Graphical user interfaces to be implemented by separate processes
+communicating with Nvim over the RPC api. Currently the ui model conists of a
+terminal-like grid with one single, monospace font size, with a few elements
+that could be drawn separately from the grid (for the momemnt only the popup
+menu)
+
+After connecting to a nvim instance (typically a spawned, embedded instance)
+use the |nvim_ui_attach|(width, height, options) api method to tell nvim that your
+program wants to draw the nvim screen on a grid with "width" times
+"height" cells. "options" should be a dictionary with the following (all
+optional) keys:
+ `rgb`: Controls what color format to use.
+ Set to true (default) to use 24-bit rgb
+ colors.
+ Set to false to use terminal color codes (at
+ most 255 different colors).
@oni-link
oni-link Aug 22, 2016 Contributor

Is it 255 or 256?

@oni-link oni-link commented on an outdated diff Aug 22, 2016
runtime/doc/msgpack_rpc.txt
+ Set to true (default) to use 24-bit rgb
+ colors.
+ Set to false to use terminal color codes (at
+ most 255 different colors).
+ `popupmenu_external`: Instead of drawing the completion popupmenu on
+ the grid, Nvim will send higher-level events to
+ the ui and let it draw the popupmenu.
+ Defaults to false.
+
+Nvim will then send msgpack-rpc notifications, with the method name "redraw"
+and a single argument, an array of screen updates (described below).
+These should be processed in order. Preferably the user should only be able to
+see the screen state after all updates are processed (not any intermediate
+state after processing only a part of the array).
+
+Screen updates are arrays. The first element a string decribing the kind
@oni-link
oni-link Aug 22, 2016 Contributor

... is a string ...
decribing -> describing

@oni-link oni-link commented on an outdated diff Aug 22, 2016
runtime/doc/msgpack_rpc.txt
+ `popupmenu_external`: Instead of drawing the completion popupmenu on
+ the grid, Nvim will send higher-level events to
+ the ui and let it draw the popupmenu.
+ Defaults to false.
+
+Nvim will then send msgpack-rpc notifications, with the method name "redraw"
+and a single argument, an array of screen updates (described below).
+These should be processed in order. Preferably the user should only be able to
+see the screen state after all updates are processed (not any intermediate
+state after processing only a part of the array).
+
+Screen updates are arrays. The first element a string decribing the kind
+of update.
+
+["resize", width, height]
+ The internal screen is resized to `width` and `height` cells.
@oni-link
oni-link Aug 22, 2016 Contributor

Is internal screen the grid?

@oni-link oni-link commented on an outdated diff Aug 22, 2016
runtime/doc/msgpack_rpc.txt
+ Clear the screen.
+
+["eol_clear"]
+ Clear from the cursor position to the end of the current line.
+
+["cursor_goto", row, col]
+ Move the cursor to position (row, col). Currently, the same cursor is
+ used to define the position for text insertion and the visible cursor.
+ However, only the last cursor position, after processing the entire
+ array in the "redraw" event, is intended to be a visible cursor
+ position.
+
+["update_fg", color]
+["update_bg", color]
+["update_sp", color]
+ set the default foreground, background and special colors
@oni-link
oni-link Aug 22, 2016 Contributor

set -> Set

@oni-link oni-link commented on an outdated diff Aug 22, 2016
runtime/doc/msgpack_rpc.txt
+["update_fg", color]
+["update_bg", color]
+["update_sp", color]
+ set the default foreground, background and special colors
+ respectively.
+
+["highlight_set", attrs]
+ Set the attributes that the next text put on the screen will have.
+ `attrs` is a dict with the keys below. Any absent key is reset
+ to its default value. Color defaults are set by the `update_fg` etc
+ updates. All boolean keys default to false.
+
+ `foreground`: foreground color.
+ `background`: backround color.
+ `special`: color to use for underline and undercurl, when present.
+ `reverse`: reverse video. foreground and background colors are
@oni-link
oni-link Aug 22, 2016 Contributor

foreground -> Foreground

@oni-link oni-link commented on an outdated diff Aug 22, 2016
runtime/doc/msgpack_rpc.txt
+ `underline`: underlined text. The line has `special` color.
+ `undercurl`: undercurled text. The curl has `special` color.
+
+["put", text]
+ The (utf-8 encoded) string `text` is put at the cursor position
+ (and the cursor is advanced), with the highlights as set by the
+ last `highlight_set` update.
+
+["set_scroll_region", top, bot, left, right]
+ Define the scroll region used by `scroll` below.
+
+["scroll", count]
+ Scroll the text in the scroll region. The diagrams below illustrate
+ what will happen, depending on the scroll direction. "=" is used to
+ represent the SR(scroll region) boundaries and "-" the moved rectangles.
+ note that dst and src share a common region.
@oni-link
oni-link Aug 22, 2016 Contributor

note -> Note

@oni-link oni-link commented on an outdated diff Aug 22, 2016
runtime/doc/msgpack_rpc.txt
+
+["put", text]
+ The (utf-8 encoded) string `text` is put at the cursor position
+ (and the cursor is advanced), with the highlights as set by the
+ last `highlight_set` update.
+
+["set_scroll_region", top, bot, left, right]
+ Define the scroll region used by `scroll` below.
+
+["scroll", count]
+ Scroll the text in the scroll region. The diagrams below illustrate
+ what will happen, depending on the scroll direction. "=" is used to
+ represent the SR(scroll region) boundaries and "-" the moved rectangles.
+ note that dst and src share a common region.
+
+ if count is bigger than 0, move an rectangle in the SR up, this can
@oni-link
oni-link Aug 22, 2016 Contributor

if -> If

@oni-link
oni-link Aug 22, 2016 Contributor

an -> a

@oni-link oni-link commented on an outdated diff Aug 22, 2016
runtime/doc/msgpack_rpc.txt
+["put", text]
+ The (utf-8 encoded) string `text` is put at the cursor position
+ (and the cursor is advanced), with the highlights as set by the
+ last `highlight_set` update.
+
+["set_scroll_region", top, bot, left, right]
+ Define the scroll region used by `scroll` below.
+
+["scroll", count]
+ Scroll the text in the scroll region. The diagrams below illustrate
+ what will happen, depending on the scroll direction. "=" is used to
+ represent the SR(scroll region) boundaries and "-" the moved rectangles.
+ note that dst and src share a common region.
+
+ if count is bigger than 0, move an rectangle in the SR up, this can
+ happen while scrolling down
@oni-link
oni-link Aug 22, 2016 Contributor

... down.

@oni-link oni-link commented on an outdated diff Aug 22, 2016
runtime/doc/msgpack_rpc.txt
+ note that dst and src share a common region.
+
+ if count is bigger than 0, move an rectangle in the SR up, this can
+ happen while scrolling down
+>
+ +-------------------------+
+ | (clipped above SR) | ^
+ |=========================| dst_top |
+ | dst (still in SR) | |
+ +-------------------------+ src_top |
+ | src (moved up) and dst | |
+ |-------------------------| dst_bot |
+ | src (cleared) | |
+ +=========================+ src_bot
+<
+ if count is less than zero, move a rectangle in the SR down, this can
@oni-link
oni-link Aug 22, 2016 Contributor

if -> If

@oni-link oni-link commented on an outdated diff Aug 22, 2016
runtime/doc/msgpack_rpc.txt
+
+ if count is bigger than 0, move an rectangle in the SR up, this can
+ happen while scrolling down
+>
+ +-------------------------+
+ | (clipped above SR) | ^
+ |=========================| dst_top |
+ | dst (still in SR) | |
+ +-------------------------+ src_top |
+ | src (moved up) and dst | |
+ |-------------------------| dst_bot |
+ | src (cleared) | |
+ +=========================+ src_bot
+<
+ if count is less than zero, move a rectangle in the SR down, this can
+ happen while scrolling up
@oni-link
oni-link Aug 22, 2016 Contributor

... up.

@oni-link oni-link commented on an outdated diff Aug 22, 2016
runtime/doc/msgpack_rpc.txt
+ if count is less than zero, move a rectangle in the SR down, this can
+ happen while scrolling up
+>
+ +=========================+ src_top
+ | src (cleared) | |
+ |------------------------ | dst_top |
+ | src (moved down) and dst| |
+ +-------------------------+ src_bot |
+ | dst (still in SR) | |
+ |=========================| dst_bot |
+ | (clipped below SR) | v
+ +-------------------------+
+<
+["set_title", title]
+["set_icon", icon]
+ set the window title, and icon (minimized) window title, respectively.
@oni-link
oni-link Aug 22, 2016 Contributor

set -> Set

@oni-link oni-link commented on an outdated diff Aug 22, 2016
runtime/doc/msgpack_rpc.txt
+["popupmenu_show", items, selected, row, col]
+ When `popupmenu_external` is set to true, nvim will not draw the
+ popupmenu on the grid, instead when the popupmenu is to be displayed
+ this update is sent. `items` is an array of the items to show, the
+ items are themselves arrays of the form [word, kind, menu, info]
+ as defined at |complete-items|, except that `word` is replaced by
+ `abbr` if present. `selected` is the initially selected item, either a
+ zero-based index into the array of items, or -1 if no item is
+ selected. `row` and `col` is the anchor position, where the first
+ character of the completed word will be.
+
+["popupmenu_select", selected]
+ An item in the currently displayed popupmenu is selected. `selected`
+ is either a zero-based index into the array of items from the last
+ `popupmenu_show` event, or -1 if no item
+ is selected.
@oni-link
oni-link Aug 22, 2016 Contributor

This line fits into the previous line.

@bfredl
Member
bfredl commented Aug 24, 2016

Thanks for the comments @oni-link. Updated.

The docs are certainly not complete yet, but I think we should merge this unless there are more comments on the code. Making readable and coherent docs for something like this will be simpler once RPC method docs are integrated in :help.

bfredl added some commits Mar 8, 2016
@bfredl bfredl api/ui: allow popupmenu to be drawn by external ui 999af47
@bfredl bfredl api/ui: add tests for popupmenu_external events
update screen.lua to use new style nvim_ui_attach
c41bacc
@bfredl bfredl api/ui: use ui options instead of one method per feature
Use new nvim_ui_ prefix to avoid breaking change.
e968d72
@bfredl bfredl api/ui: add documentation for remote ui redraw events
8d6e3f2
@bfredl bfredl merged commit 0b5a7e4 into neovim:master Aug 29, 2016

3 checks passed

continuous-integration/appveyor/pr AppVeyor build succeeded
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details
coverage/coveralls Coverage decreased (-0.06%) to 70.311%
Details
@jszakmeister jszakmeister removed the RFC label Aug 29, 2016
@justinmk
Member

Just a heads up for @rhysd @qvacua @rogual @carlosdcastillo who may be interested in this new API feature. See #4432 (comment) for a proof-of-concept.

@justinmk justinmk added a commit to justinmk/neovim that referenced this pull request Oct 27, 2016
@justinmk justinmk NVIM v0.1.6
FEATURES:
0b5a7e4 #4432 API: external UIs can render custom popupmenu
c6ac4f8 #4934 API: call any API method from vimscript
31df051 #4568 API: nvim_call_atomic(): multiple calls in a single request
b268ba3 #5424 API: nvim_win_get_number(), nvim_tabpage_get_number()
e7e2844 has("nvim-1.2.3") checks for a specific Nvim version
522b885 #5295, #5493 `:CheckHealth` checks tmux, terminfo, performance
719dae2 #5384 events: allow event processing in getchar()
f25797f #5386 API: metadata: Nvim version & API level
22dfe69 #5389 API: metadata: "since", "deprecated_since"
605e743 Added QuickFixLine highlight group

CHANGES:
4af6ec7 #5253 perf: Disable clipboard in do_cmdline()
6e9f329 #5299 perf: Skip foldUpdate() in insert-mode.
9d4fcec #5426 perf: Do not auto-update folds for some foldmethods.
eeec0ca #5419 tui: Default to normal-mode cursor shape.

FIXES:
e838452 #5436 tui: Fix "weird characters" / "bleeding termcodes"
10a54ad #5243 signal_init: Always unblock SIGCHLD.
bccb49b #5316 eval.c: Fix memory leak for detached pty job
626065d #5227 tchdir: New tab should inherit CWD.
cd321b7 #5292 getcwd(): Return empty string if CWD is invalid.
6127eae shada: Fix non-writeable ShaDa directory handling
ca65514 #2789 system(): Respect shellxescape, shellxquote
2daf54e #4874 Restore vim-like tab dragging
0c536b5 #5319 syntax.c: Support bg/fg special color-names.
3c53371 #4972 from justinmk/schedule-ui_refresh
68bcb32 #4789 tui.c: Do not wait for tui loop on teardown.
c8b6ec2 #5409 v:count broken in command-line window
6bc3bce #5461 fix emoji display
51937e1 #5470 fix :terminal with :argadd, :argu
79d77da #5481 external UIs: opening multiple files from command-line
657ba62 #5501 rplugin: resolve paths in manifest file
6a6f188 #5502 system('foo &', 'bar'): Show error, don't crash.
1ff162c #5515 os_nodetype: open fd with O_NONBLOCK
2a6c5bb #5450 modeline: Handle version number overflow.
0ade1bb #5225 CI tests now run against Windows!
962e876
@justinmk justinmk added a commit to justinmk/neovim that referenced this pull request Oct 28, 2016
@justinmk justinmk NVIM v0.1.6
FEATURES:
0b5a7e4 #4432 API: external UIs can render custom popupmenu
c6ac4f8 #4934 API: call any API method from vimscript
31df051 #4568 API: nvim_call_atomic(): multiple calls in a single request
b268ba3 #5424 API: nvim_win_get_number(), nvim_tabpage_get_number()
e7e2844 has("nvim-1.2.3") checks for a specific Nvim version
522b885 #5295, #5493 `:CheckHealth` checks tmux, terminfo, performance
719dae2 #5384 events: allow event processing in getchar()
f25797f #5386 API: metadata: Nvim version & API level
22dfe69 #5389 API: metadata: "since", "deprecated_since"
605e743 Added QuickFixLine highlight group

CHANGES:
4af6ec7 #5253 perf: Disable clipboard in do_cmdline()
6e9f329 #5299 perf: Skip foldUpdate() in insert-mode.
9d4fcec #5426 perf: Do not auto-update folds for some foldmethods.
eeec0ca #5419 tui: Default to normal-mode cursor shape.

FIXES:
e838452 #5436 tui: Fix "weird characters" / "bleeding termcodes"
10a54ad #5243 signal_init: Always unblock SIGCHLD.
bccb49b #5316 eval.c: Fix memory leak for detached pty job
626065d #5227 tchdir: New tab should inherit CWD.
cd321b7 #5292 getcwd(): Return empty string if CWD is invalid.
6127eae shada: Fix non-writeable ShaDa directory handling
ca65514 #2789 system(): Respect shellxescape, shellxquote
2daf54e #4874 Restore vim-like tab dragging
0c536b5 #5319 syntax.c: Support bg/fg special color-names.
3c53371 #4972 from justinmk/schedule-ui_refresh
68bcb32 #4789 tui.c: Do not wait for tui loop on teardown.
c8b6ec2 #5409 v:count broken in command-line window
6bc3bce #5461 fix emoji display
51937e1 #5470 fix :terminal with :argadd, :argu
79d77da #5481 external UIs: opening multiple files from command-line
657ba62 #5501 rplugin: resolve paths in manifest file
6a6f188 #5502 system('foo &', 'bar'): Show error, don't crash.
1ff162c #5515 os_nodetype: open fd with O_NONBLOCK
2a6c5bb #5450 modeline: Handle version number overflow.
0ade1bb #5225 CI tests now run against Windows!
cc1ec95
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment