mirror of
				https://github.com/neovim/neovim.git
				synced 2025-11-03 17:24:29 +00:00 
			
		
		
		
	UI/nvim_ui_attach(): add override option
				
					
				
			Before now, Nvim always degrades UI capabilities to the lowest-common
denominator. For example, if any connected UI has `ext_messages=false`
then `ext_messages=true` requested by any other connected UI is ignored.
Now `nvim_ui_attach()` supports `override=true`, which flips the
behavior: if any UI requests an `ext_*` UI capability then the
capability is enabled (and the legacy behavior is disabled).
Legacy UIs will be broken while a `override=true` UI is connected, but
it's useful for debugging: you can type into the TUI and observe the UI
events from another connected (UI) client. And the legacy UI will
"recover" after the `override=true` UI disconnects.
Example using pynvim:
    >>> n.ui_attach(2048, 2048, rgb=True, override=True, ext_multigrid=True, ext_messages=True, ext_popupmenu=True)
    >>> while True: n.next_message();
			
			
This commit is contained in:
		@@ -108,7 +108,7 @@ line numbers.  Double-click one of the lines and the Find Source dialog will
 | 
				
			|||||||
appear.  Navigate to the directory where the Vim source is (if you have it.)
 | 
					appear.  Navigate to the directory where the Vim source is (if you have it.)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
If you don't know how to debug this any further, follow the instructions
 | 
					If you don't know how to debug this any further, follow the instructions
 | 
				
			||||||
at ":help bug-reports".  Paste the call stack into the bug report.
 | 
					at ":help bug-report".  Paste the call stack into the bug report.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
If you have a non-free version of Visual Studio, you can save a minidump via
 | 
					If you have a non-free version of Visual Studio, you can save a minidump via
 | 
				
			||||||
the Debug menu and send it with the bug report.  A minidump is a small file
 | 
					the Debug menu and send it with the bug report.  A minidump is a small file
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -68,10 +68,8 @@ Options ~
 | 
				
			|||||||
*'viminfofile'*		Deprecated alias to 'shadafile' option.
 | 
					*'viminfofile'*		Deprecated alias to 'shadafile' option.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
UI extensions~
 | 
					UI extensions~
 | 
				
			||||||
*ui-wildmenu*		Use `ext_cmdline` and `ext_popupmenu` instead.
 | 
					*ui-wildmenu*		Use |ui-cmdline| with |ui-popupmenu| instead. Enabled
 | 
				
			||||||
			Enabled by `ext_wildmenu` |ui-options|.
 | 
								by `ext_wildmenu` |ui-options|. Emits these events:
 | 
				
			||||||
			If `ext_wildmenu` is set, these events are emitted for
 | 
					 | 
				
			||||||
			backwards-compatibility:
 | 
					 | 
				
			||||||
				["wildmenu_show", items]
 | 
									["wildmenu_show", items]
 | 
				
			||||||
				["wildmenu_select", selected]
 | 
									["wildmenu_select", selected]
 | 
				
			||||||
				["wildmenu_hide"]
 | 
									["wildmenu_hide"]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -58,7 +58,7 @@ For more information try one of these:
 | 
				
			|||||||
==============================================================================
 | 
					==============================================================================
 | 
				
			||||||
Nvim on the interwebs					*internet*
 | 
					Nvim on the interwebs					*internet*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			*www* *WWW*  *faq* *FAQ* *distribution* *download*
 | 
								*www* *faq* *distribution* *download*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Nvim home page:	  https://neovim.io/
 | 
						Nvim home page:	  https://neovim.io/
 | 
				
			||||||
	Nvim FAQ:	  https://github.com/neovim/neovim/wiki/FAQ
 | 
						Nvim FAQ:	  https://github.com/neovim/neovim/wiki/FAQ
 | 
				
			||||||
@@ -67,9 +67,10 @@ Nvim on the interwebs					*internet*
 | 
				
			|||||||
	Vim home page:	  https://www.vim.org/
 | 
						Vim home page:	  https://www.vim.org/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Bug reports:				*bugs* *bug-reports* *bugreport.vim*
 | 
								*bugs* *bug-report* *bugreport.vim* *feature-request* 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Report bugs on GitHub: https://github.com/neovim/neovim/issues
 | 
					Report bugs and request features here:
 | 
				
			||||||
 | 
					https://github.com/neovim/neovim/issues
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Be brief, yet complete.  Always give a reproducible example and try to find
 | 
					Be brief, yet complete.  Always give a reproducible example and try to find
 | 
				
			||||||
out which settings or other things trigger the bug.
 | 
					out which settings or other things trigger the bug.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,13 +25,20 @@ done by an embedder, see |ui-startup| below for details, but an UI can also
 | 
				
			|||||||
connect to a running nvim instance and invoke this method. `options` must be
 | 
					connect to a running nvim instance and invoke this method. `options` must be
 | 
				
			||||||
a dictionary with these (optional) keys:
 | 
					a dictionary with these (optional) keys:
 | 
				
			||||||
	`rgb`			Decides the color format. *ui-rgb*
 | 
						`rgb`			Decides the color format. *ui-rgb*
 | 
				
			||||||
				Set true (default) for 24-bit RGB colors.
 | 
									true:	(default) 24-bit RGB colors
 | 
				
			||||||
				Set false for terminal colors (max of 256).
 | 
									false:	Terminal colors (8-bit, max 256)
 | 
				
			||||||
 | 
						`override`		Decides how UI capabilities are resolved.
 | 
				
			||||||
 | 
									true:	Enable requested UI capabilities, even
 | 
				
			||||||
 | 
										if not supported by all connected UIs
 | 
				
			||||||
 | 
										(including |TUI|).
 | 
				
			||||||
 | 
									false:	(default) Disable UI capabilities not
 | 
				
			||||||
 | 
										supported by all connected UIs
 | 
				
			||||||
 | 
										(including TUI).
 | 
				
			||||||
							      *ui-ext-options*
 | 
												      *ui-ext-options*
 | 
				
			||||||
	`ext_popupmenu`		Externalize the popupmenu. |ui-popupmenu|
 | 
						`ext_popupmenu`		Externalize |popupmenu-completion| and
 | 
				
			||||||
 | 
									'wildmenu'. |ui-popupmenu|
 | 
				
			||||||
	`ext_tabline`		Externalize the tabline. |ui-tabline|
 | 
						`ext_tabline`		Externalize the tabline. |ui-tabline|
 | 
				
			||||||
	`ext_cmdline`		Externalize the cmdline. |ui-cmdline|
 | 
						`ext_cmdline`		Externalize the cmdline. |ui-cmdline|
 | 
				
			||||||
	`ext_wildmenu`		Externalize the wildmenu (deprecated). |ui-wildmenu|
 | 
					 | 
				
			||||||
	`ext_messages`		Externalize messages. |ui-messages|
 | 
						`ext_messages`		Externalize messages. |ui-messages|
 | 
				
			||||||
	`ext_linegrid`		Use new revision of the grid events. |ui-linegrid|
 | 
						`ext_linegrid`		Use new revision of the grid events. |ui-linegrid|
 | 
				
			||||||
	`ext_multigrid`		Use per-window grid based events. |ui-multigrid|
 | 
						`ext_multigrid`		Use per-window grid based events. |ui-multigrid|
 | 
				
			||||||
@@ -245,9 +252,9 @@ numerical highlight ids to the actual attributes.
 | 
				
			|||||||
	implementation, where using the terminal builtin ("ANSI") defaults
 | 
						implementation, where using the terminal builtin ("ANSI") defaults
 | 
				
			||||||
	are expected.
 | 
						are expected.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Note: unlike the corresponding events in the first revision, the
 | 
						Note: Unlike the corresponding |ui-grid-old| events, the screen is not
 | 
				
			||||||
	screen is not always cleared after sending this event. The GUI has to
 | 
						always cleared after sending this event. The UI must repaint the
 | 
				
			||||||
	repaint the screen with changed background color itself.
 | 
						screen with changed background color itself.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							*ui-event-hl_attr_define*
 | 
												*ui-event-hl_attr_define*
 | 
				
			||||||
["hl_attr_define", id, rgb_attr, cterm_attr, info]
 | 
					["hl_attr_define", id, rgb_attr, cterm_attr, info]
 | 
				
			||||||
@@ -554,6 +561,7 @@ See |nvim_input_mouse| for sending mouse events to Nvim.
 | 
				
			|||||||
Popupmenu Events						 *ui-popupmenu*
 | 
					Popupmenu Events						 *ui-popupmenu*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Only sent if `ext_popupmenu` option is set in |ui-options|.
 | 
					Only sent if `ext_popupmenu` option is set in |ui-options|.
 | 
				
			||||||
 | 
					Events for |popupmenu-completion| and command-line 'wildmenu'.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
["popupmenu_show", items, selected, row, col, grid]
 | 
					["popupmenu_show", items, selected, row, col, grid]
 | 
				
			||||||
	Show |popupmenu-completion|. `items` is an array of completion items
 | 
						Show |popupmenu-completion|. `items` is an array of completion items
 | 
				
			||||||
@@ -590,9 +598,7 @@ Only sent if `ext_tabline` option is set in |ui-options|
 | 
				
			|||||||
Cmdline Events							   *ui-cmdline*
 | 
					Cmdline Events							   *ui-cmdline*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Only sent if `ext_cmdline` option is set in |ui-options|. To handle
 | 
					Only sent if `ext_cmdline` option is set in |ui-options|. To handle
 | 
				
			||||||
command-line completion (wildmenu), use |ui-popupmenu| events activated by
 | 
					command-line 'wildmenu', enable |ui-popupmenu| and handle its events.
 | 
				
			||||||
|ext_popupmenu| option. (The `ext_wildmenu` option only exists for backwards
 | 
					 | 
				
			||||||
compatibility).
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
["cmdline_show", content, pos, firstc, prompt, indent, level]
 | 
					["cmdline_show", content, pos, firstc, prompt, indent, level]
 | 
				
			||||||
        content: List of [attrs, string]
 | 
					        content: List of [attrs, string]
 | 
				
			||||||
@@ -650,18 +656,18 @@ compatibility).
 | 
				
			|||||||
==============================================================================
 | 
					==============================================================================
 | 
				
			||||||
Message Events							   *ui-messages*
 | 
					Message Events							   *ui-messages*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Only sent if `ext_messages` option is set in |ui-options|. This option implies
 | 
					Only sent if `ext_messages` option is set in |ui-options|. This option
 | 
				
			||||||
`ext_linegrid` and `ext_cmdline` also being set. |ui-linegrid| and |ui-cmdline| events
 | 
					implicitly enables `ext_linegrid` and `ext_cmdline`. |ui-linegrid| and
 | 
				
			||||||
will thus also be sent.
 | 
					|ui-cmdline| events will thus also be sent.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This extension allows the UI to control the display of messages that otherwise
 | 
					This extension allows the UI to control the display of messages that otherwise
 | 
				
			||||||
would have been displayed in the message/cmdline area in the bottom of the
 | 
					would have been displayed in the message/cmdline area in the bottom of the
 | 
				
			||||||
screen.
 | 
					screen.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Activating this extension means that Nvim will allocate no screen space for
 | 
					Activating this extension means that Nvim will not allocate screen space for
 | 
				
			||||||
the cmdline or messages, and 'cmdheight' will be set to zero.  Attempting to
 | 
					the cmdline or messages, 'cmdheight' will be zero.  Attempting to change
 | 
				
			||||||
change 'cmdheight' will silently be ignored. |ui-cmdline| events will be used
 | 
					'cmdheight' will be silently ignored. |ui-cmdline| events represent the state
 | 
				
			||||||
to represent the state of the cmdline.
 | 
					of the cmdline.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
["msg_show", kind, content, replace_last]
 | 
					["msg_show", kind, content, replace_last]
 | 
				
			||||||
	Display a message to the user.
 | 
						Display a message to the user.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -110,6 +110,7 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height,
 | 
				
			|||||||
  ui->width = (int)width;
 | 
					  ui->width = (int)width;
 | 
				
			||||||
  ui->height = (int)height;
 | 
					  ui->height = (int)height;
 | 
				
			||||||
  ui->rgb = true;
 | 
					  ui->rgb = true;
 | 
				
			||||||
 | 
					  ui->override = false;
 | 
				
			||||||
  ui->grid_resize = remote_ui_grid_resize;
 | 
					  ui->grid_resize = remote_ui_grid_resize;
 | 
				
			||||||
  ui->grid_clear = remote_ui_grid_clear;
 | 
					  ui->grid_clear = remote_ui_grid_clear;
 | 
				
			||||||
  ui->grid_cursor_goto = remote_ui_grid_cursor_goto;
 | 
					  ui->grid_cursor_goto = remote_ui_grid_cursor_goto;
 | 
				
			||||||
@@ -236,6 +237,15 @@ void nvim_ui_set_option(uint64_t channel_id, String name,
 | 
				
			|||||||
static void ui_set_option(UI *ui, bool init, String name, Object value,
 | 
					static void ui_set_option(UI *ui, bool init, String name, Object value,
 | 
				
			||||||
                          Error *error)
 | 
					                          Error *error)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					  if (strequal(name.data, "override")) {
 | 
				
			||||||
 | 
					    if (value.type != kObjectTypeBoolean) {
 | 
				
			||||||
 | 
					      api_set_error(error, kErrorTypeValidation, "override must be a Boolean");
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    ui->override = value.data.boolean;
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (strequal(name.data, "rgb")) {
 | 
					  if (strequal(name.data, "rgb")) {
 | 
				
			||||||
    if (value.type != kObjectTypeBoolean) {
 | 
					    if (value.type != kObjectTypeBoolean) {
 | 
				
			||||||
      api_set_error(error, kErrorTypeValidation, "rgb must be a Boolean");
 | 
					      api_set_error(error, kErrorTypeValidation, "rgb must be a Boolean");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -141,6 +141,17 @@ bool ui_rgb_attached(void)
 | 
				
			|||||||
  return false;
 | 
					  return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Returns true if any UI requested `override=true`.
 | 
				
			||||||
 | 
					bool ui_override(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  for (size_t i = 1; i < ui_count; i++) {
 | 
				
			||||||
 | 
					    if (uis[i]->override) {
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool ui_active(void)
 | 
					bool ui_active(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  return ui_count > 1;
 | 
					  return ui_count > 1;
 | 
				
			||||||
@@ -173,12 +184,13 @@ void ui_refresh(void)
 | 
				
			|||||||
    ext_widgets[i] = true;
 | 
					    ext_widgets[i] = true;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool inclusive = ui_override();
 | 
				
			||||||
  for (size_t i = 0; i < ui_count; i++) {
 | 
					  for (size_t i = 0; i < ui_count; i++) {
 | 
				
			||||||
    UI *ui = uis[i];
 | 
					    UI *ui = uis[i];
 | 
				
			||||||
    width = MIN(ui->width, width);
 | 
					    width = MIN(ui->width, width);
 | 
				
			||||||
    height = MIN(ui->height, height);
 | 
					    height = MIN(ui->height, height);
 | 
				
			||||||
    for (UIExtension j = 0; (int)j < kUIExtCount; j++) {
 | 
					    for (UIExtension j = 0; (int)j < kUIExtCount; j++) {
 | 
				
			||||||
      ext_widgets[j] &= ui->ui_ext[j];
 | 
					      ext_widgets[j] &= (ui->ui_ext[j] || inclusive);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -431,6 +443,7 @@ Array ui_array(void)
 | 
				
			|||||||
    PUT(info, "width", INTEGER_OBJ(ui->width));
 | 
					    PUT(info, "width", INTEGER_OBJ(ui->width));
 | 
				
			||||||
    PUT(info, "height", INTEGER_OBJ(ui->height));
 | 
					    PUT(info, "height", INTEGER_OBJ(ui->height));
 | 
				
			||||||
    PUT(info, "rgb", BOOLEAN_OBJ(ui->rgb));
 | 
					    PUT(info, "rgb", BOOLEAN_OBJ(ui->rgb));
 | 
				
			||||||
 | 
					    PUT(info, "override", BOOLEAN_OBJ(ui->override));
 | 
				
			||||||
    for (UIExtension j = 0; j < kUIExtCount; j++) {
 | 
					    for (UIExtension j = 0; j < kUIExtCount; j++) {
 | 
				
			||||||
      if (ui_ext_names[j][0] != '_' || ui->ui_ext[j]) {
 | 
					      if (ui_ext_names[j][0] != '_' || ui->ui_ext[j]) {
 | 
				
			||||||
        PUT(info, ui_ext_names[j], BOOLEAN_OBJ(ui->ui_ext[j]));
 | 
					        PUT(info, ui_ext_names[j], BOOLEAN_OBJ(ui->ui_ext[j]));
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -48,9 +48,11 @@ typedef int LineFlags;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
struct ui_t {
 | 
					struct ui_t {
 | 
				
			||||||
  bool rgb;
 | 
					  bool rgb;
 | 
				
			||||||
 | 
					  bool override;  ///< Force highest-requested UI capabilities.
 | 
				
			||||||
  bool composed;
 | 
					  bool composed;
 | 
				
			||||||
  bool ui_ext[kUIExtCount];  ///< Externalized widgets
 | 
					  bool ui_ext[kUIExtCount];  ///< Externalized UI capabilities.
 | 
				
			||||||
  int width, height;
 | 
					  int width;
 | 
				
			||||||
 | 
					  int height;
 | 
				
			||||||
  void *data;
 | 
					  void *data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
 | 
					#ifdef INCLUDE_GENERATED_DECLARATIONS
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1284,7 +1284,7 @@ describe('API', function()
 | 
				
			|||||||
    end)
 | 
					    end)
 | 
				
			||||||
    it('returns attached UIs', function()
 | 
					    it('returns attached UIs', function()
 | 
				
			||||||
      local screen = Screen.new(20, 4)
 | 
					      local screen = Screen.new(20, 4)
 | 
				
			||||||
      screen:attach()
 | 
					      screen:attach({override=true})
 | 
				
			||||||
      local expected = {
 | 
					      local expected = {
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          chan = 1,
 | 
					          chan = 1,
 | 
				
			||||||
@@ -1299,6 +1299,7 @@ describe('API', function()
 | 
				
			|||||||
          ext_messages = false,
 | 
					          ext_messages = false,
 | 
				
			||||||
          height = 4,
 | 
					          height = 4,
 | 
				
			||||||
          rgb = true,
 | 
					          rgb = true,
 | 
				
			||||||
 | 
					          override = true,
 | 
				
			||||||
          width = 20,
 | 
					          width = 20,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@@ -1308,6 +1309,7 @@ describe('API', function()
 | 
				
			|||||||
      screen = Screen.new(44, 99)
 | 
					      screen = Screen.new(44, 99)
 | 
				
			||||||
      screen:attach({ rgb = false })
 | 
					      screen:attach({ rgb = false })
 | 
				
			||||||
      expected[1].rgb = false
 | 
					      expected[1].rgb = false
 | 
				
			||||||
 | 
					      expected[1].override = false
 | 
				
			||||||
      expected[1].width = 44
 | 
					      expected[1].width = 44
 | 
				
			||||||
      expected[1].height = 99
 | 
					      expected[1].height = 99
 | 
				
			||||||
      eq(expected, nvim("list_uis"))
 | 
					      eq(expected, nvim("list_uis"))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -255,14 +255,14 @@ describe('TUI', function()
 | 
				
			|||||||
    ]])
 | 
					    ]])
 | 
				
			||||||
  end)
 | 
					  end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  it('shows up in nvim_list_uis', function()
 | 
					  it('is included in nvim_list_uis()', function()
 | 
				
			||||||
    feed_data(':echo map(nvim_list_uis(), {k,v -> sort(items(filter(v, {k,v -> k[:3] !=# "ext_" })))})\013')
 | 
					    feed_data(':echo map(nvim_list_uis(), {k,v -> sort(items(filter(v, {k,v -> k[:3] !=# "ext_" })))})\013')
 | 
				
			||||||
    screen:expect([=[
 | 
					    screen:expect([=[
 | 
				
			||||||
                                                        |
 | 
					                                                        |
 | 
				
			||||||
      {4:~                                                 }|
 | 
					      {4:~                                                 }|
 | 
				
			||||||
      {5:                                                  }|
 | 
					      {5:                                                  }|
 | 
				
			||||||
      [[['height', 6], ['rgb', v:false], ['width', 50]]]|
 | 
					      [[['height', 6], ['override', v:false], ['rgb', v:|
 | 
				
			||||||
                                                        |
 | 
					      false], ['width', 50]]]                           |
 | 
				
			||||||
      {10:Press ENTER or type command to continue}{1: }          |
 | 
					      {10:Press ENTER or type command to continue}{1: }          |
 | 
				
			||||||
      {3:-- TERMINAL --}                                    |
 | 
					      {3:-- TERMINAL --}                                    |
 | 
				
			||||||
    ]=])
 | 
					    ]=])
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user