22#include " renderer/renderer.h"
33
44struct Context {
5- int start_x, start_y;
6- GridSize start_grid_size;
75 bool start_maximized;
86 bool start_fullscreen;
97 bool disable_fullscreen;
@@ -46,19 +44,13 @@ void ToggleFullscreen(HWND hwnd, Context *context) {
4644void ProcessMPackMessage (Context *context, mpack_tree_t *tree) {
4745 MPackMessageResult result = MPackExtractMessageResult (tree);
4846
49- if (result.type == MPackMessageType::Response) {
47+ switch (result.type ) {
48+ case MPackMessageType::Response: {
5049 assert (result.response .msg_id <= context->nvim ->next_msg_id );
5150 switch (context->nvim ->msg_id_to_method [result.response .msg_id ]) {
52- case NvimRequest::vim_get_api_info: {
53- mpack_node_t top_level_map = mpack_node_array_at (result.params , 1 );
54- mpack_node_t version_map = mpack_node_map_value_at (top_level_map, 0 );
55- int64_t api_level = mpack_node_map_cstr (version_map, " api_level" ).data ->value .i ;
56- assert (api_level > 6 );
57- } break ;
5851 case NvimRequest::nvim_eval: {
5952 Vec<char > guifont_buffer;
6053 NvimParseConfig (context->nvim , result.params , &guifont_buffer);
61-
6254 if (!guifont_buffer.empty ()) {
6355 bool updated = RendererUpdateGuiFont (context->renderer , guifont_buffer.data (), strlen (guifont_buffer.data ()));
6456 if (!updated) {
@@ -72,45 +64,27 @@ void ProcessMPackMessage(Context *context, mpack_tree_t *tree) {
7264 free (command);
7365 }
7466 }
75-
76- if (context->start_grid_size .rows != 0 &&
77- context->start_grid_size .cols != 0 ) {
78- PixelSize start_size = RendererGridToPixelSize (context->renderer ,
79- context->start_grid_size .rows , context->start_grid_size .cols );
80- RECT client_rect;
81- GetClientRect (context->hwnd , &client_rect);
82- MoveWindow (context->hwnd , client_rect.left , client_rect.top ,
83- start_size.width , start_size.height , false );
84- }
85-
86- // Attach the renderer now that the window size is determined
87- RendererAttach (context->renderer );
88- auto [rows, cols] = RendererPixelsToGridSize (context->renderer ,
89- context->renderer ->pixel_size .width , context->renderer ->pixel_size .height );
90- NvimSendUIAttach (context->nvim , rows, cols);
91-
92- if (context->start_x != CW_USEDEFAULT ||
93- context->start_y != CW_USEDEFAULT ) {
94- SetWindowPos (context->hwnd , NULL ,
95- context->start_x , context->start_y ,
96- 0 , 0 ,
97- SWP_NOSIZE | SWP_NOREDRAW | SWP_NOACTIVATE |
98- SWP_NOOWNERZORDER | SWP_NOZORDER );
99- }
100- if (context->start_fullscreen ) {
101- ToggleFullscreen (context->hwnd , context);
102- }
103- } break ;
104- case NvimRequest::nvim_input:
105- case NvimRequest::nvim_input_mouse:
106- case NvimRequest::nvim_command: {
10767 } break ;
68+ case NvimRequest::vim_get_api_info:
69+ case NvimRequest::nvim_input:
70+ case NvimRequest::nvim_input_mouse:
71+ case NvimRequest::nvim_command: {
72+ } break ;
10873 }
109- }
110- else if (result. type == MPackMessageType::Notification) {
74+ } break ;
75+ case MPackMessageType::Notification: {
11176 if (MPackMatchString (result.notification .name , " redraw" )) {
11277 RendererRedraw (context->renderer , result.params , context->start_maximized );
11378 }
79+ } break ;
80+ case MPackMessageType::Request: {
81+ if (MPackMatchString (result.request .method , " vimenter" )) {
82+ // nvim has read user init file, we can now request info if we want
83+ // like additional startup settings or something else
84+ NvimSendResponse (context->nvim , result.request .msg_id );
85+ NvimQueryConfig (context->nvim );
86+ }
87+ } break ;
11488 }
11589}
11690
@@ -400,7 +374,7 @@ BOOL ShouldUseDarkMode()
400374 return false ;
401375}
402376
403- int WINAPI wWinMain (HINSTANCE instance, HINSTANCE prev_instance, PWSTR p_cmd_line, int n_cmd_show) {
377+ int WINAPI wWinMain (_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance, _In_ LPWSTR p_cmd_line, _In_ int n_cmd_show) {
404378 SetProcessDpiAwarenessContext (DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE );
405379
406380 int n_args;
@@ -410,16 +384,16 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance, PWSTR p_cmd_lin
410384 bool disable_ligatures = false ;
411385 bool disable_fullscreen = false ;
412386 float linespace_factor = 1 .0f ;
413- int64_t rows = 0 ;
414- int64_t cols = 0 ;
415- int64_t x = CW_USEDEFAULT ;
416- int64_t y = CW_USEDEFAULT ;
417-
418- constexpr int MAX_NVIM_CMD_LINE_SIZE = 32767 ;
419- wchar_t nvim_command_line[ MAX_NVIM_CMD_LINE_SIZE ] = {} ;
420- wcscpy_s (nvim_command_line, MAX_NVIM_CMD_LINE_SIZE , L" nvim --embed " ) ;
421- int cmd_line_size_left = MAX_NVIM_CMD_LINE_SIZE - wcslen ( L" nvim --embed " ) ;
422-
387+ int64_t start_rows = 0 ;
388+ int64_t start_cols = 0 ;
389+ int64_t start_pos_x = CW_USEDEFAULT ;
390+ int64_t start_pos_y = CW_USEDEFAULT ;
391+
392+ struct WArg {
393+ wchar_t *arg ;
394+ size_t len ;
395+ } ;
396+ Vec<WArg> nvim_args;
423397
424398 // Skip argv[0]
425399 for (int i = 1 ; i < n_args; ++i) {
@@ -437,13 +411,13 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance, PWSTR p_cmd_lin
437411 }
438412 else if (!wcsncmp (cmd_line_args[i], L" --geometry=" , wcslen (L" --geometry=" ))) {
439413 wchar_t *end_ptr;
440- cols = wcstol (&cmd_line_args[i][11 ], &end_ptr, 10 );
441- rows = wcstol (end_ptr + 1 , nullptr , 10 );
414+ start_cols = wcstol (&cmd_line_args[i][11 ], &end_ptr, 10 );
415+ start_rows = wcstol (end_ptr + 1 , nullptr , 10 );
442416 }
443417 else if (!wcsncmp (cmd_line_args[i], L" --position=" , wcslen (L" --position=" ))) {
444418 wchar_t *end_ptr;
445- x = wcstol (&cmd_line_args[i][11 ], &end_ptr, 10 );
446- y = wcstol (end_ptr + 1 , nullptr , 10 );
419+ start_pos_x = wcstol (&cmd_line_args[i][11 ], &end_ptr, 10 );
420+ start_pos_y = wcstol (end_ptr + 1 , nullptr , 10 );
447421 }
448422 else if (!wcsncmp (cmd_line_args[i], L" --linespace-factor=" , wcslen (L" --linespace-factor=" ))) {
449423 wchar_t *end_ptr;
@@ -454,15 +428,10 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance, PWSTR p_cmd_lin
454428 }
455429 // Otherwise assume the argument is a filename to open
456430 else {
457- size_t arg_size = wcslen (cmd_line_args[i]);
458- if (arg_size <= (cmd_line_size_left + 3 )) {
459- wcscat_s (nvim_command_line, cmd_line_size_left, L" \" " );
460- cmd_line_size_left -= 2 ;
461- wcscat_s (nvim_command_line, cmd_line_size_left, cmd_line_args[i]);
462- cmd_line_size_left -= arg_size;
463- wcscat_s (nvim_command_line, cmd_line_size_left, L" \" " );
464- cmd_line_size_left -= 1 ;
465- }
431+ nvim_args.push_back (WArg{
432+ .arg = cmd_line_args[i],
433+ .len = wcslen (cmd_line_args[i])
434+ });
466435 }
467436 }
468437
@@ -473,10 +442,10 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance, PWSTR p_cmd_lin
473442 .style = CS_HREDRAW | CS_VREDRAW ,
474443 .lpfnWndProc = WndProc,
475444 .hInstance = instance,
476- .hIcon = static_cast <HICON >(LoadImage (GetModuleHandle (NULL ), L" NVIM_ICON" , IMAGE_ICON , LR_DEFAULTSIZE , LR_DEFAULTSIZE , 0 )),
445+ .hIcon = static_cast <HICON >(LoadImage (GetModuleHandle (NULL ), L" NVIM_ICON" , IMAGE_ICON , LR_DEFAULTSIZE , LR_DEFAULTSIZE , 0 )),
477446 .hCursor = LoadCursor (NULL , IDC_ARROW ),
478447 .lpszClassName = window_class_name,
479- .hIconSm = static_cast <HICON >(LoadImage (GetModuleHandle (NULL ), L" NVIM_ICON" , IMAGE_ICON , LR_DEFAULTSIZE , LR_DEFAULTSIZE , 0 ))
448+ .hIconSm = static_cast <HICON >(LoadImage (GetModuleHandle (NULL ), L" NVIM_ICON" , IMAGE_ICON , LR_DEFAULTSIZE , LR_DEFAULTSIZE , 0 ))
480449 };
481450
482451 if (!RegisterClassEx (&window_class)) {
@@ -486,12 +455,6 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance, PWSTR p_cmd_lin
486455 Nvim nvim {};
487456 Renderer renderer {};
488457 Context context {
489- .start_x = static_cast <int >(x),
490- .start_y = static_cast <int >(y),
491- .start_grid_size {
492- .rows = static_cast <int >(rows),
493- .cols = static_cast <int >(cols)
494- },
495458 .start_maximized = start_maximized,
496459 .start_fullscreen = start_fullscreen,
497460 .disable_fullscreen = disable_fullscreen,
@@ -525,10 +488,47 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance, PWSTR p_cmd_lin
525488 BOOL should_use_dark_mode = ShouldUseDarkMode ();
526489 DwmSetWindowAttribute (hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE , &should_use_dark_mode, sizeof (BOOL ));
527490 RendererInitialize (&renderer, hwnd, disable_ligatures, linespace_factor, context.saved_dpi_scaling );
491+
492+ // Prepare nvim command line
493+ size_t nvim_command_len = wcslen (L" nvim --embed" );
494+ for (const auto & nvim_command_arg : nvim_args) {
495+ nvim_command_len += wcslen (L" \"\" " ) + nvim_command_arg.len ;
496+ }
497+ wchar_t *nvim_command_line = static_cast <wchar_t *>(malloc (sizeof (wchar_t ) * (nvim_command_len + 1 )));
498+ int cur_len = _snwprintf_s (nvim_command_line, nvim_command_len + 1 , nvim_command_len, L" nvim --embed" );
499+ for (const auto & [arg, len] : nvim_args) {
500+ cur_len += _snwprintf_s (nvim_command_line + cur_len, nvim_command_len + 1 - cur_len, nvim_command_len - cur_len,
501+ L" \" %s\" " , arg, static_cast <uint32_t >(len));
502+ }
503+
528504 NvimInitialize (&nvim, nvim_command_line, hwnd);
505+
529506 // Forceably update the window to prevent any frames where the window is blank. Windows API docs
530507 // specify that SetWindowPos should be called with these arguments after SetWindowLong is called.
531- SetWindowPos (hwnd, HWND_TOP , 0 , 0 , 0 , 0 , SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED );
508+ UINT window_flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED ;
509+ int window_w = 0 , window_h = 0 ;
510+
511+ if (start_rows != 0 && start_cols != 0 ) {
512+ PixelSize start_size = RendererGridToPixelSize (context.renderer ,
513+ start_rows, start_cols);
514+ window_w = start_size.width ;
515+ window_h = start_size.height ;
516+ window_flags = window_flags & ~SWP_NOSIZE ;
517+ }
518+ if (start_pos_x != CW_USEDEFAULT || start_pos_y != CW_USEDEFAULT ) {
519+ window_flags = window_flags & ~SWP_NOMOVE ;
520+ }
521+ SetWindowPos (hwnd, HWND_TOP , start_pos_x, start_pos_y, window_w, window_h, window_flags);
522+
523+ if (start_fullscreen) {
524+ ToggleFullscreen (context.hwnd , &context);
525+ }
526+
527+ // Attach the renderer now that the window size is determined
528+ RendererAttach (context.renderer );
529+ auto [rows, cols] = RendererPixelsToGridSize (context.renderer ,
530+ context.renderer ->pixel_size .width , context.renderer ->pixel_size .height );
531+ NvimSendUIAttach (context.nvim , rows, cols);
532532
533533 MSG msg;
534534 uint32_t previous_width = 0 , previous_height = 0 ;
@@ -551,6 +551,7 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance, PWSTR p_cmd_lin
551551 NvimShutdown (&nvim);
552552 UnregisterClass (window_class_name, instance);
553553 DestroyWindow (hwnd);
554+ free (nvim_command_line);
554555
555556 return nvim.exit_code ;
556557}
0 commit comments