From b9ad12e6c2fa557e2c2c2f2f6c40fabc0cc89efd Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Thu, 9 May 2019 19:35:38 +0200 Subject: [PATCH] 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(); --- runtime/doc/debug.txt | 2 +- runtime/doc/deprecated.txt | 6 ++-- runtime/doc/intro.txt | 7 +++-- runtime/doc/ui.txt | 40 +++++++++++++++------------ src/nvim/api/ui.c | 10 +++++++ src/nvim/ui.c | 15 +++++++++- src/nvim/ui.h | 6 ++-- test/functional/api/vim_spec.lua | 4 ++- test/functional/terminal/tui_spec.lua | 6 ++-- 9 files changed, 64 insertions(+), 32 deletions(-) diff --git a/runtime/doc/debug.txt b/runtime/doc/debug.txt index 1019becf9c..fab12e36fa 100644 --- a/runtime/doc/debug.txt +++ b/runtime/doc/debug.txt @@ -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.) 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 the Debug menu and send it with the bug report. A minidump is a small file diff --git a/runtime/doc/deprecated.txt b/runtime/doc/deprecated.txt index 9272c0693e..e6b6a9df45 100644 --- a/runtime/doc/deprecated.txt +++ b/runtime/doc/deprecated.txt @@ -68,10 +68,8 @@ Options ~ *'viminfofile'* Deprecated alias to 'shadafile' option. UI extensions~ -*ui-wildmenu* Use `ext_cmdline` and `ext_popupmenu` instead. - Enabled by `ext_wildmenu` |ui-options|. - If `ext_wildmenu` is set, these events are emitted for - backwards-compatibility: +*ui-wildmenu* Use |ui-cmdline| with |ui-popupmenu| instead. Enabled + by `ext_wildmenu` |ui-options|. Emits these events: ["wildmenu_show", items] ["wildmenu_select", selected] ["wildmenu_hide"] diff --git a/runtime/doc/intro.txt b/runtime/doc/intro.txt index 1d2cca3073..1fb06e169c 100644 --- a/runtime/doc/intro.txt +++ b/runtime/doc/intro.txt @@ -58,7 +58,7 @@ For more information try one of these: ============================================================================== Nvim on the interwebs *internet* - *www* *WWW* *faq* *FAQ* *distribution* *download* + *www* *faq* *distribution* *download* Nvim home page: https://neovim.io/ 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/ -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 out which settings or other things trigger the bug. diff --git a/runtime/doc/ui.txt b/runtime/doc/ui.txt index 73eb2210f5..bfcd0369ad 100644 --- a/runtime/doc/ui.txt +++ b/runtime/doc/ui.txt @@ -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 a dictionary with these (optional) keys: `rgb` Decides the color format. *ui-rgb* - Set true (default) for 24-bit RGB colors. - Set false for terminal colors (max of 256). + true: (default) 24-bit RGB colors + 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* - `ext_popupmenu` Externalize the popupmenu. |ui-popupmenu| + `ext_popupmenu` Externalize |popupmenu-completion| and + 'wildmenu'. |ui-popupmenu| `ext_tabline` Externalize the tabline. |ui-tabline| `ext_cmdline` Externalize the cmdline. |ui-cmdline| - `ext_wildmenu` Externalize the wildmenu (deprecated). |ui-wildmenu| `ext_messages` Externalize messages. |ui-messages| `ext_linegrid` Use new revision of the grid events. |ui-linegrid| `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 are expected. - Note: unlike the corresponding events in the first revision, the - screen is not always cleared after sending this event. The GUI has to - repaint the screen with changed background color itself. + Note: Unlike the corresponding |ui-grid-old| events, the screen is not + always cleared after sending this event. The UI must repaint the + screen with changed background color itself. *ui-event-hl_attr_define* ["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* 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] 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* Only sent if `ext_cmdline` option is set in |ui-options|. To handle -command-line completion (wildmenu), use |ui-popupmenu| events activated by -|ext_popupmenu| option. (The `ext_wildmenu` option only exists for backwards -compatibility). +command-line 'wildmenu', enable |ui-popupmenu| and handle its events. ["cmdline_show", content, pos, firstc, prompt, indent, level] content: List of [attrs, string] @@ -650,18 +656,18 @@ compatibility). ============================================================================== Message Events *ui-messages* -Only sent if `ext_messages` option is set in |ui-options|. This option implies -`ext_linegrid` and `ext_cmdline` also being set. |ui-linegrid| and |ui-cmdline| events -will thus also be sent. +Only sent if `ext_messages` option is set in |ui-options|. This option +implicitly enables `ext_linegrid` and `ext_cmdline`. |ui-linegrid| and +|ui-cmdline| events will thus also be sent. 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 screen. -Activating this extension means that Nvim will allocate no screen space for -the cmdline or messages, and 'cmdheight' will be set to zero. Attempting to -change 'cmdheight' will silently be ignored. |ui-cmdline| events will be used -to represent the state of the cmdline. +Activating this extension means that Nvim will not allocate screen space for +the cmdline or messages, 'cmdheight' will be zero. Attempting to change +'cmdheight' will be silently ignored. |ui-cmdline| events represent the state +of the cmdline. ["msg_show", kind, content, replace_last] Display a message to the user. diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index fd94418d48..9f12ae6888 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -110,6 +110,7 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, ui->width = (int)width; ui->height = (int)height; ui->rgb = true; + ui->override = false; ui->grid_resize = remote_ui_grid_resize; ui->grid_clear = remote_ui_grid_clear; 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, 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 (value.type != kObjectTypeBoolean) { api_set_error(error, kErrorTypeValidation, "rgb must be a Boolean"); diff --git a/src/nvim/ui.c b/src/nvim/ui.c index 0dddfe5f59..7dbb8ec790 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -141,6 +141,17 @@ bool ui_rgb_attached(void) 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) { return ui_count > 1; @@ -173,12 +184,13 @@ void ui_refresh(void) ext_widgets[i] = true; } + bool inclusive = ui_override(); for (size_t i = 0; i < ui_count; i++) { UI *ui = uis[i]; width = MIN(ui->width, width); height = MIN(ui->height, height); 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, "height", INTEGER_OBJ(ui->height)); PUT(info, "rgb", BOOLEAN_OBJ(ui->rgb)); + PUT(info, "override", BOOLEAN_OBJ(ui->override)); for (UIExtension j = 0; j < kUIExtCount; j++) { if (ui_ext_names[j][0] != '_' || ui->ui_ext[j]) { PUT(info, ui_ext_names[j], BOOLEAN_OBJ(ui->ui_ext[j])); diff --git a/src/nvim/ui.h b/src/nvim/ui.h index 3f6b3babad..e1dd18a289 100644 --- a/src/nvim/ui.h +++ b/src/nvim/ui.h @@ -48,9 +48,11 @@ typedef int LineFlags; struct ui_t { bool rgb; + bool override; ///< Force highest-requested UI capabilities. bool composed; - bool ui_ext[kUIExtCount]; ///< Externalized widgets - int width, height; + bool ui_ext[kUIExtCount]; ///< Externalized UI capabilities. + int width; + int height; void *data; #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index c508ca37db..2178abab53 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -1284,7 +1284,7 @@ describe('API', function() end) it('returns attached UIs', function() local screen = Screen.new(20, 4) - screen:attach() + screen:attach({override=true}) local expected = { { chan = 1, @@ -1299,6 +1299,7 @@ describe('API', function() ext_messages = false, height = 4, rgb = true, + override = true, width = 20, } } @@ -1308,6 +1309,7 @@ describe('API', function() screen = Screen.new(44, 99) screen:attach({ rgb = false }) expected[1].rgb = false + expected[1].override = false expected[1].width = 44 expected[1].height = 99 eq(expected, nvim("list_uis")) diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 9d0eb5e40e..469d088c57 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -255,14 +255,14 @@ describe('TUI', function() ]]) 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') screen:expect([=[ | {4:~ }| {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: } | {3:-- TERMINAL --} | ]=])