mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	feat(server): allow embed with listen (#25709)
connection from any channel or stdio will unblock remote_ui_wait_for_attach. Wait on stdio only if only —embed specified, if both —embed and —listen then wait on any channel.
This commit is contained in:
		| @@ -390,6 +390,10 @@ argument. | |||||||
| <		Then startup will continue without waiting for `nvim_ui_attach`. | <		Then startup will continue without waiting for `nvim_ui_attach`. | ||||||
| 		This is equivalent to: > | 		This is equivalent to: > | ||||||
| 		    nvim --headless --cmd "call stdioopen({'rpc': v:true})" | 		    nvim --headless --cmd "call stdioopen({'rpc': v:true})" | ||||||
|  | < | ||||||
|  | 		Embedders that use the UI protocol on a socket connection must | ||||||
|  | 		pass |--listen| as well as |--embed|: > | ||||||
|  | 		    nvim --embed --listen addr | ||||||
|  |  | ||||||
| <		See also: |ui-startup| |channel-stdio| | <		See also: |ui-startup| |channel-stdio| | ||||||
|  |  | ||||||
|   | |||||||
| @@ -126,18 +126,24 @@ void remote_ui_disconnect(uint64_t channel_id) | |||||||
|   xfree(ui); |   xfree(ui); | ||||||
| } | } | ||||||
|  |  | ||||||
| /// Wait until ui has connected on stdio channel. | /// Wait until ui has connected on stdio channel if only_stdio | ||||||
| void remote_ui_wait_for_attach(void) | /// is true, otherwise any channel. | ||||||
|  | void remote_ui_wait_for_attach(bool only_stdio) | ||||||
| { | { | ||||||
|   Channel *channel = find_channel(CHAN_STDIO); |   if (only_stdio) { | ||||||
|   if (!channel) { |     Channel *channel = find_channel(CHAN_STDIO); | ||||||
|     // this function should only be called in --embed mode, stdio channel |     if (!channel) { | ||||||
|     // can be assumed. |       // this function should only be called in --embed mode, stdio channel | ||||||
|     abort(); |       // can be assumed. | ||||||
|   } |       abort(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|   LOOP_PROCESS_EVENTS_UNTIL(&main_loop, channel->events, -1, |     LOOP_PROCESS_EVENTS_UNTIL(&main_loop, channel->events, -1, | ||||||
|                             map_has(uint64_t, &connected_uis, CHAN_STDIO)); |                               map_has(uint64_t, &connected_uis, CHAN_STDIO)); | ||||||
|  |   } else { | ||||||
|  |     LOOP_PROCESS_EVENTS_UNTIL(&main_loop, main_loop.events, -1, | ||||||
|  |                               ui_active()); | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| /// Activates UI events on the channel. | /// Activates UI events on the channel. | ||||||
|   | |||||||
| @@ -392,9 +392,10 @@ int main(int argc, char **argv) | |||||||
|   // Wait for UIs to set up Nvim or show early messages |   // Wait for UIs to set up Nvim or show early messages | ||||||
|   // and prompts (--cmd, swapfile dialog, …). |   // and prompts (--cmd, swapfile dialog, …). | ||||||
|   bool use_remote_ui = (embedded_mode && !headless_mode); |   bool use_remote_ui = (embedded_mode && !headless_mode); | ||||||
|  |   bool listen_and_embed = params.listen_addr != NULL; | ||||||
|   if (use_remote_ui) { |   if (use_remote_ui) { | ||||||
|     TIME_MSG("waiting for UI"); |     TIME_MSG("waiting for UI"); | ||||||
|     remote_ui_wait_for_attach(); |     remote_ui_wait_for_attach(!listen_and_embed); | ||||||
|     TIME_MSG("done waiting for UI"); |     TIME_MSG("done waiting for UI"); | ||||||
|     firstwin->w_prev_height = firstwin->w_height;  // may have changed |     firstwin->w_prev_height = firstwin->w_height;  // may have changed | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -2,10 +2,13 @@ local uv = require'luv' | |||||||
|  |  | ||||||
| local helpers = require('test.functional.helpers')(after_each) | local helpers = require('test.functional.helpers')(after_each) | ||||||
| local Screen = require('test.functional.ui.screen') | local Screen = require('test.functional.ui.screen') | ||||||
|  | local thelpers = require('test.functional.terminal.helpers') | ||||||
|  |  | ||||||
| local feed = helpers.feed | local feed = helpers.feed | ||||||
| local eq = helpers.eq | local eq = helpers.eq | ||||||
| local clear = helpers.clear | local clear = helpers.clear | ||||||
|  | local ok = helpers.ok | ||||||
|  |  | ||||||
|  |  | ||||||
| local function test_embed(ext_linegrid) | local function test_embed(ext_linegrid) | ||||||
|   local screen |   local screen | ||||||
| @@ -133,3 +136,60 @@ describe('--embed UI', function() | |||||||
|     ]]} |     ]]} | ||||||
|   end) |   end) | ||||||
| end) | end) | ||||||
|  |  | ||||||
|  | describe('--embed --listen UI', function() | ||||||
|  |   it('waits for connection on listening address', function() | ||||||
|  |     helpers.skip(helpers.is_os('win')) | ||||||
|  |     clear() | ||||||
|  |     local child_server = assert(helpers.new_pipename()) | ||||||
|  |  | ||||||
|  |     local screen = thelpers.screen_setup(0, | ||||||
|  |       string.format( | ||||||
|  |         [=[["%s", "--embed", "--listen", "%s", "-u", "NONE", "-i", "NONE", "--cmd", "%s"]]=], | ||||||
|  |         helpers.nvim_prog, child_server, helpers.nvim_set)) | ||||||
|  |     screen:expect{grid=[[ | ||||||
|  |       {1: }                                                 | | ||||||
|  |                                                         | | ||||||
|  |                                                         | | ||||||
|  |                                                         | | ||||||
|  |                                                         | | ||||||
|  |                                                         | | ||||||
|  |       {3:-- TERMINAL --}                                    | | ||||||
|  |     ]]} | ||||||
|  |  | ||||||
|  |     local child_session = helpers.connect(child_server) | ||||||
|  |  | ||||||
|  |     local info_ok, apiinfo = child_session:request('nvim_get_api_info') | ||||||
|  |     assert(info_ok) | ||||||
|  |     assert(#apiinfo == 2) | ||||||
|  |  | ||||||
|  |     child_session:request('nvim_exec2', [[ | ||||||
|  |       let g:vim_entered=0 | ||||||
|  |       autocmd VimEnter * call execute("let g:vim_entered=1") | ||||||
|  |     ]], {}) | ||||||
|  |  | ||||||
|  |     -- g:vim_entered shouldn't be set to 1 until after attach | ||||||
|  |     local var_ok, var = child_session:request('nvim_get_var', 'vim_entered') | ||||||
|  |     assert(var_ok) | ||||||
|  |     ok(var == 0) | ||||||
|  |  | ||||||
|  |     local child_screen = Screen.new(40, 6) | ||||||
|  |     child_screen:attach(nil, child_session) | ||||||
|  |     child_screen:expect{grid=[[ | ||||||
|  |       ^                                        | | ||||||
|  |       {1:~                                       }| | ||||||
|  |       {1:~                                       }| | ||||||
|  |       {1:~                                       }| | ||||||
|  |       {1:~                                       }| | ||||||
|  |                                               | | ||||||
|  |     ]], attr_ids={ | ||||||
|  |       [1] = {foreground = Screen.colors.Blue, bold = true}; | ||||||
|  |     }} | ||||||
|  |  | ||||||
|  |     -- g:vim_entered should now be set to 1 | ||||||
|  |     var_ok, var = child_session:request('nvim_get_var', 'vim_entered') | ||||||
|  |     assert(var_ok) | ||||||
|  |     ok(var == 1) | ||||||
|  |  | ||||||
|  |   end) | ||||||
|  | end) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 George Harker
					George Harker