mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +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
	 Justin M. Keyes
					Justin M. Keyes