comparison src/main.c @ 19920:5e41b2e63c73 v8.2.0516

patch 8.2.0516: client-server code is spread out Commit: https://github.com/vim/vim/commit/f87a0400fd81862c33d6ad2291a56e178db7dddd Author: Bram Moolenaar <Bram@vim.org> Date: Sun Apr 5 20:21:03 2020 +0200 patch 8.2.0516: client-server code is spread out Problem: Client-server code is spread out. Solution: Move client-server code to a new file. (Yegappan Lakshmanan, closes #5885)
author Bram Moolenaar <Bram@vim.org>
date Sun, 05 Apr 2020 20:30:35 +0200
parents 031184ace7c5
children aadd1cae2ff5
comparison
equal deleted inserted replaced
19919:b4b102849236 19920:5e41b2e63c73
51 static void source_startup_scripts(mparm_T *parmp); 51 static void source_startup_scripts(mparm_T *parmp);
52 static void main_start_gui(void); 52 static void main_start_gui(void);
53 static void check_swap_exists_action(void); 53 static void check_swap_exists_action(void);
54 # ifdef FEAT_EVAL 54 # ifdef FEAT_EVAL
55 static void set_progpath(char_u *argv0); 55 static void set_progpath(char_u *argv0);
56 # endif
57 # if defined(FEAT_CLIENTSERVER) || defined(PROTO)
58 static void exec_on_server(mparm_T *parmp);
59 static void prepare_server(mparm_T *parmp);
60 static void cmdsrv_main(int *argc, char **argv, char_u *serverName_arg, char_u **serverStr);
61 static char_u *serverMakeName(char_u *arg, char *cmd);
62 # endif 56 # endif
63 #endif 57 #endif
64 58
65 59
66 /* 60 /*
3712 vim_free(path); 3706 vim_free(path);
3713 # endif 3707 # endif
3714 } 3708 }
3715 3709
3716 #endif // NO_VIM_MAIN 3710 #endif // NO_VIM_MAIN
3717
3718 #if (defined(FEAT_CLIENTSERVER) && !defined(NO_VIM_MAIN)) || defined(PROTO)
3719
3720 /*
3721 * Common code for the X command server and the Win32 command server.
3722 */
3723
3724 static char_u *build_drop_cmd(int filec, char **filev, int tabs, int sendReply);
3725
3726 /*
3727 * Do the client-server stuff, unless "--servername ''" was used.
3728 */
3729 static void
3730 exec_on_server(mparm_T *parmp)
3731 {
3732 if (parmp->serverName_arg == NULL || *parmp->serverName_arg != NUL)
3733 {
3734 # ifdef MSWIN
3735 // Initialise the client/server messaging infrastructure.
3736 serverInitMessaging();
3737 # endif
3738
3739 /*
3740 * When a command server argument was found, execute it. This may
3741 * exit Vim when it was successful. Otherwise it's executed further
3742 * on. Remember the encoding used here in "serverStrEnc".
3743 */
3744 if (parmp->serverArg)
3745 {
3746 cmdsrv_main(&parmp->argc, parmp->argv,
3747 parmp->serverName_arg, &parmp->serverStr);
3748 parmp->serverStrEnc = vim_strsave(p_enc);
3749 }
3750
3751 // If we're still running, get the name to register ourselves.
3752 // On Win32 can register right now, for X11 need to setup the
3753 // clipboard first, it's further down.
3754 parmp->servername = serverMakeName(parmp->serverName_arg,
3755 parmp->argv[0]);
3756 # ifdef MSWIN
3757 if (parmp->servername != NULL)
3758 {
3759 serverSetName(parmp->servername);
3760 vim_free(parmp->servername);
3761 }
3762 # endif
3763 }
3764 }
3765
3766 /*
3767 * Prepare for running as a Vim server.
3768 */
3769 static void
3770 prepare_server(mparm_T *parmp)
3771 {
3772 # if defined(FEAT_X11)
3773 /*
3774 * Register for remote command execution with :serversend and --remote
3775 * unless there was a -X or a --servername '' on the command line.
3776 * Only register nongui-vim's with an explicit --servername argument,
3777 * or when compiling with autoservername.
3778 * When running as root --servername is also required.
3779 */
3780 if (X_DISPLAY != NULL && parmp->servername != NULL && (
3781 # if defined(FEAT_AUTOSERVERNAME) || defined(FEAT_GUI)
3782 (
3783 # if defined(FEAT_AUTOSERVERNAME)
3784 1
3785 # else
3786 gui.in_use
3787 # endif
3788 # ifdef UNIX
3789 && getuid() != ROOT_UID
3790 # endif
3791 ) ||
3792 # endif
3793 parmp->serverName_arg != NULL))
3794 {
3795 (void)serverRegisterName(X_DISPLAY, parmp->servername);
3796 vim_free(parmp->servername);
3797 TIME_MSG("register server name");
3798 }
3799 else
3800 serverDelayedStartName = parmp->servername;
3801 # endif
3802
3803 /*
3804 * Execute command ourselves if we're here because the send failed (or
3805 * else we would have exited above).
3806 */
3807 if (parmp->serverStr != NULL)
3808 {
3809 char_u *p;
3810
3811 server_to_input_buf(serverConvert(parmp->serverStrEnc,
3812 parmp->serverStr, &p));
3813 vim_free(p);
3814 }
3815 }
3816
3817 static void
3818 cmdsrv_main(
3819 int *argc,
3820 char **argv,
3821 char_u *serverName_arg,
3822 char_u **serverStr)
3823 {
3824 char_u *res;
3825 int i;
3826 char_u *sname;
3827 int ret;
3828 int didone = FALSE;
3829 int exiterr = 0;
3830 char **newArgV = argv + 1;
3831 int newArgC = 1,
3832 Argc = *argc;
3833 int argtype;
3834 #define ARGTYPE_OTHER 0
3835 #define ARGTYPE_EDIT 1
3836 #define ARGTYPE_EDIT_WAIT 2
3837 #define ARGTYPE_SEND 3
3838 int silent = FALSE;
3839 int tabs = FALSE;
3840 # ifndef FEAT_X11
3841 HWND srv;
3842 # else
3843 Window srv;
3844
3845 setup_term_clip();
3846 # endif
3847
3848 sname = serverMakeName(serverName_arg, argv[0]);
3849 if (sname == NULL)
3850 return;
3851
3852 /*
3853 * Execute the command server related arguments and remove them
3854 * from the argc/argv array; We may have to return into main()
3855 */
3856 for (i = 1; i < Argc; i++)
3857 {
3858 res = NULL;
3859 if (STRCMP(argv[i], "--") == 0) // end of option arguments
3860 {
3861 for (; i < *argc; i++)
3862 {
3863 *newArgV++ = argv[i];
3864 newArgC++;
3865 }
3866 break;
3867 }
3868
3869 if (STRICMP(argv[i], "--remote-send") == 0)
3870 argtype = ARGTYPE_SEND;
3871 else if (STRNICMP(argv[i], "--remote", 8) == 0)
3872 {
3873 char *p = argv[i] + 8;
3874
3875 argtype = ARGTYPE_EDIT;
3876 while (*p != NUL)
3877 {
3878 if (STRNICMP(p, "-wait", 5) == 0)
3879 {
3880 argtype = ARGTYPE_EDIT_WAIT;
3881 p += 5;
3882 }
3883 else if (STRNICMP(p, "-silent", 7) == 0)
3884 {
3885 silent = TRUE;
3886 p += 7;
3887 }
3888 else if (STRNICMP(p, "-tab", 4) == 0)
3889 {
3890 tabs = TRUE;
3891 p += 4;
3892 }
3893 else
3894 {
3895 argtype = ARGTYPE_OTHER;
3896 break;
3897 }
3898 }
3899 }
3900 else
3901 argtype = ARGTYPE_OTHER;
3902
3903 if (argtype != ARGTYPE_OTHER)
3904 {
3905 if (i == *argc - 1)
3906 mainerr_arg_missing((char_u *)argv[i]);
3907 if (argtype == ARGTYPE_SEND)
3908 {
3909 *serverStr = (char_u *)argv[i + 1];
3910 i++;
3911 }
3912 else
3913 {
3914 *serverStr = build_drop_cmd(*argc - i - 1, argv + i + 1,
3915 tabs, argtype == ARGTYPE_EDIT_WAIT);
3916 if (*serverStr == NULL)
3917 {
3918 // Probably out of memory, exit.
3919 didone = TRUE;
3920 exiterr = 1;
3921 break;
3922 }
3923 Argc = i;
3924 }
3925 # ifdef FEAT_X11
3926 if (xterm_dpy == NULL)
3927 {
3928 mch_errmsg(_("No display"));
3929 ret = -1;
3930 }
3931 else
3932 ret = serverSendToVim(xterm_dpy, sname, *serverStr,
3933 NULL, &srv, 0, 0, 0, silent);
3934 # else
3935 // Win32 always works?
3936 ret = serverSendToVim(sname, *serverStr, NULL, &srv, 0, 0, silent);
3937 # endif
3938 if (ret < 0)
3939 {
3940 if (argtype == ARGTYPE_SEND)
3941 {
3942 // Failed to send, abort.
3943 mch_errmsg(_(": Send failed.\n"));
3944 didone = TRUE;
3945 exiterr = 1;
3946 }
3947 else if (!silent)
3948 // Let vim start normally.
3949 mch_errmsg(_(": Send failed. Trying to execute locally\n"));
3950 break;
3951 }
3952
3953 # ifdef FEAT_GUI_MSWIN
3954 // Guess that when the server name starts with "g" it's a GUI
3955 // server, which we can bring to the foreground here.
3956 // Foreground() in the server doesn't work very well.
3957 if (argtype != ARGTYPE_SEND && TOUPPER_ASC(*sname) == 'G')
3958 SetForegroundWindow(srv);
3959 # endif
3960
3961 /*
3962 * For --remote-wait: Wait until the server did edit each
3963 * file. Also detect that the server no longer runs.
3964 */
3965 if (ret >= 0 && argtype == ARGTYPE_EDIT_WAIT)
3966 {
3967 int numFiles = *argc - i - 1;
3968 int j;
3969 char_u *done = alloc(numFiles);
3970 char_u *p;
3971 # ifdef FEAT_GUI_MSWIN
3972 NOTIFYICONDATA ni;
3973 int count = 0;
3974 extern HWND message_window;
3975 # endif
3976
3977 if (numFiles > 0 && argv[i + 1][0] == '+')
3978 // Skip "+cmd" argument, don't wait for it to be edited.
3979 --numFiles;
3980
3981 # ifdef FEAT_GUI_MSWIN
3982 ni.cbSize = sizeof(ni);
3983 ni.hWnd = message_window;
3984 ni.uID = 0;
3985 ni.uFlags = NIF_ICON|NIF_TIP;
3986 ni.hIcon = LoadIcon((HINSTANCE)GetModuleHandle(0), "IDR_VIM");
3987 sprintf(ni.szTip, _("%d of %d edited"), count, numFiles);
3988 Shell_NotifyIcon(NIM_ADD, &ni);
3989 # endif
3990
3991 // Wait for all files to unload in remote
3992 vim_memset(done, 0, numFiles);
3993 while (memchr(done, 0, numFiles) != NULL)
3994 {
3995 # ifdef MSWIN
3996 p = serverGetReply(srv, NULL, TRUE, TRUE, 0);
3997 if (p == NULL)
3998 break;
3999 # else
4000 if (serverReadReply(xterm_dpy, srv, &p, TRUE, -1) < 0)
4001 break;
4002 # endif
4003 j = atoi((char *)p);
4004 if (j >= 0 && j < numFiles)
4005 {
4006 # ifdef FEAT_GUI_MSWIN
4007 ++count;
4008 sprintf(ni.szTip, _("%d of %d edited"),
4009 count, numFiles);
4010 Shell_NotifyIcon(NIM_MODIFY, &ni);
4011 # endif
4012 done[j] = 1;
4013 }
4014 }
4015 # ifdef FEAT_GUI_MSWIN
4016 Shell_NotifyIcon(NIM_DELETE, &ni);
4017 # endif
4018 }
4019 }
4020 else if (STRICMP(argv[i], "--remote-expr") == 0)
4021 {
4022 if (i == *argc - 1)
4023 mainerr_arg_missing((char_u *)argv[i]);
4024 # ifdef MSWIN
4025 // Win32 always works?
4026 if (serverSendToVim(sname, (char_u *)argv[i + 1],
4027 &res, NULL, 1, 0, FALSE) < 0)
4028 # else
4029 if (xterm_dpy == NULL)
4030 mch_errmsg(_("No display: Send expression failed.\n"));
4031 else if (serverSendToVim(xterm_dpy, sname, (char_u *)argv[i + 1],
4032 &res, NULL, 1, 0, 1, FALSE) < 0)
4033 # endif
4034 {
4035 if (res != NULL && *res != NUL)
4036 {
4037 // Output error from remote
4038 mch_errmsg((char *)res);
4039 VIM_CLEAR(res);
4040 }
4041 mch_errmsg(_(": Send expression failed.\n"));
4042 }
4043 }
4044 else if (STRICMP(argv[i], "--serverlist") == 0)
4045 {
4046 # ifdef MSWIN
4047 // Win32 always works?
4048 res = serverGetVimNames();
4049 # else
4050 if (xterm_dpy != NULL)
4051 res = serverGetVimNames(xterm_dpy);
4052 # endif
4053 if (did_emsg)
4054 mch_errmsg("\n");
4055 }
4056 else if (STRICMP(argv[i], "--servername") == 0)
4057 {
4058 // Already processed. Take it out of the command line
4059 i++;
4060 continue;
4061 }
4062 else
4063 {
4064 *newArgV++ = argv[i];
4065 newArgC++;
4066 continue;
4067 }
4068 didone = TRUE;
4069 if (res != NULL && *res != NUL)
4070 {
4071 mch_msg((char *)res);
4072 if (res[STRLEN(res) - 1] != '\n')
4073 mch_msg("\n");
4074 }
4075 vim_free(res);
4076 }
4077
4078 if (didone)
4079 {
4080 display_errors(); // display any collected messages
4081 exit(exiterr); // Mission accomplished - get out
4082 }
4083
4084 // Return back into main()
4085 *argc = newArgC;
4086 vim_free(sname);
4087 }
4088
4089 /*
4090 * Build a ":drop" command to send to a Vim server.
4091 */
4092 static char_u *
4093 build_drop_cmd(
4094 int filec,
4095 char **filev,
4096 int tabs, // Use ":tab drop" instead of ":drop".
4097 int sendReply)
4098 {
4099 garray_T ga;
4100 int i;
4101 char_u *inicmd = NULL;
4102 char_u *p;
4103 char_u *cdp;
4104 char_u *cwd;
4105
4106 if (filec > 0 && filev[0][0] == '+')
4107 {
4108 inicmd = (char_u *)filev[0] + 1;
4109 filev++;
4110 filec--;
4111 }
4112 // Check if we have at least one argument.
4113 if (filec <= 0)
4114 mainerr_arg_missing((char_u *)filev[-1]);
4115
4116 // Temporarily cd to the current directory to handle relative file names.
4117 cwd = alloc(MAXPATHL);
4118 if (cwd == NULL)
4119 return NULL;
4120 if (mch_dirname(cwd, MAXPATHL) != OK)
4121 {
4122 vim_free(cwd);
4123 return NULL;
4124 }
4125 cdp = vim_strsave_escaped_ext(cwd,
4126 #ifdef BACKSLASH_IN_FILENAME
4127 (char_u *)"", // rem_backslash() will tell what chars to escape
4128 #else
4129 PATH_ESC_CHARS,
4130 #endif
4131 '\\', TRUE);
4132 vim_free(cwd);
4133 if (cdp == NULL)
4134 return NULL;
4135 ga_init2(&ga, 1, 100);
4136 ga_concat(&ga, (char_u *)"<C-\\><C-N>:cd ");
4137 ga_concat(&ga, cdp);
4138
4139 // Call inputsave() so that a prompt for an encryption key works.
4140 ga_concat(&ga, (char_u *)"<CR>:if exists('*inputsave')|call inputsave()|endif|");
4141 if (tabs)
4142 ga_concat(&ga, (char_u *)"tab ");
4143 ga_concat(&ga, (char_u *)"drop");
4144 for (i = 0; i < filec; i++)
4145 {
4146 // On Unix the shell has already expanded the wildcards, don't want to
4147 // do it again in the Vim server. On MS-Windows only escape
4148 // non-wildcard characters.
4149 p = vim_strsave_escaped((char_u *)filev[i],
4150 #ifdef UNIX
4151 PATH_ESC_CHARS
4152 #else
4153 (char_u *)" \t%#"
4154 #endif
4155 );
4156 if (p == NULL)
4157 {
4158 vim_free(ga.ga_data);
4159 return NULL;
4160 }
4161 ga_concat(&ga, (char_u *)" ");
4162 ga_concat(&ga, p);
4163 vim_free(p);
4164 }
4165 ga_concat(&ga, (char_u *)"|if exists('*inputrestore')|call inputrestore()|endif<CR>");
4166
4167 // The :drop commands goes to Insert mode when 'insertmode' is set, use
4168 // CTRL-\ CTRL-N again.
4169 ga_concat(&ga, (char_u *)"<C-\\><C-N>");
4170
4171 // Switch back to the correct current directory (prior to temporary path
4172 // switch) unless 'autochdir' is set, in which case it will already be
4173 // correct after the :drop command. With line breaks and spaces:
4174 // if !exists('+acd') || !&acd
4175 // if haslocaldir()
4176 // cd -
4177 // lcd -
4178 // elseif getcwd() ==# 'current path'
4179 // cd -
4180 // endif
4181 // endif
4182 ga_concat(&ga, (char_u *)":if !exists('+acd')||!&acd|if haslocaldir()|");
4183 ga_concat(&ga, (char_u *)"cd -|lcd -|elseif getcwd() ==# '");
4184 ga_concat(&ga, cdp);
4185 ga_concat(&ga, (char_u *)"'|cd -|endif|endif<CR>");
4186 vim_free(cdp);
4187
4188 if (sendReply)
4189 ga_concat(&ga, (char_u *)":call SetupRemoteReplies()<CR>");
4190 ga_concat(&ga, (char_u *)":");
4191 if (inicmd != NULL)
4192 {
4193 // Can't use <CR> after "inicmd", because an "startinsert" would cause
4194 // the following commands to be inserted as text. Use a "|",
4195 // hopefully "inicmd" does allow this...
4196 ga_concat(&ga, inicmd);
4197 ga_concat(&ga, (char_u *)"|");
4198 }
4199 // Bring the window to the foreground, goto Insert mode when 'im' set and
4200 // clear command line.
4201 ga_concat(&ga, (char_u *)"cal foreground()|if &im|star|en|redr|f<CR>");
4202 ga_append(&ga, NUL);
4203 return ga.ga_data;
4204 }
4205
4206 /*
4207 * Make our basic server name: use the specified "arg" if given, otherwise use
4208 * the tail of the command "cmd" we were started with.
4209 * Return the name in allocated memory. This doesn't include a serial number.
4210 */
4211 static char_u *
4212 serverMakeName(char_u *arg, char *cmd)
4213 {
4214 char_u *p;
4215
4216 if (arg != NULL && *arg != NUL)
4217 p = vim_strsave_up(arg);
4218 else
4219 {
4220 p = vim_strsave_up(gettail((char_u *)cmd));
4221 // Remove .exe or .bat from the name.
4222 if (p != NULL && vim_strchr(p, '.') != NULL)
4223 *vim_strchr(p, '.') = NUL;
4224 }
4225 return p;
4226 }
4227 #endif // FEAT_CLIENTSERVER
4228
4229 #if defined(FEAT_CLIENTSERVER) || defined(PROTO)
4230 /*
4231 * Replace termcodes such as <CR> and insert as key presses if there is room.
4232 */
4233 void
4234 server_to_input_buf(char_u *str)
4235 {
4236 char_u *ptr = NULL;
4237 char_u *cpo_save = p_cpo;
4238
4239 // Set 'cpoptions' the way we want it.
4240 // B set - backslashes are *not* treated specially
4241 // k set - keycodes are *not* reverse-engineered
4242 // < unset - <Key> sequences *are* interpreted
4243 // The last but one parameter of replace_termcodes() is TRUE so that the
4244 // <lt> sequence is recognised - needed for a real backslash.
4245 p_cpo = (char_u *)"Bk";
4246 str = replace_termcodes((char_u *)str, &ptr, REPTERM_DO_LT, NULL);
4247 p_cpo = cpo_save;
4248
4249 if (*ptr != NUL) // trailing CTRL-V results in nothing
4250 {
4251 /*
4252 * Add the string to the input stream.
4253 * Can't use add_to_input_buf() here, we now have K_SPECIAL bytes.
4254 *
4255 * First clear typed characters from the typeahead buffer, there could
4256 * be half a mapping there. Then append to the existing string, so
4257 * that multiple commands from a client are concatenated.
4258 */
4259 if (typebuf.tb_maplen < typebuf.tb_len)
4260 del_typebuf(typebuf.tb_len - typebuf.tb_maplen, typebuf.tb_maplen);
4261 (void)ins_typebuf(str, REMAP_NONE, typebuf.tb_len, TRUE, FALSE);
4262
4263 // Let input_available() know we inserted text in the typeahead
4264 // buffer.
4265 typebuf_was_filled = TRUE;
4266 }
4267 vim_free((char_u *)ptr);
4268 }
4269
4270 /*
4271 * Evaluate an expression that the client sent to a string.
4272 */
4273 char_u *
4274 eval_client_expr_to_string(char_u *expr)
4275 {
4276 char_u *res;
4277 int save_dbl = debug_break_level;
4278 int save_ro = redir_off;
4279 funccal_entry_T funccal_entry;
4280 int did_save_funccal = FALSE;
4281
4282 // Evaluate the expression at the toplevel, don't use variables local to
4283 // the calling function. Except when in debug mode.
4284 if (!debug_mode)
4285 {
4286 save_funccal(&funccal_entry);
4287 did_save_funccal = TRUE;
4288 }
4289
4290 // Disable debugging, otherwise Vim hangs, waiting for "cont" to be
4291 // typed.
4292 debug_break_level = -1;
4293 redir_off = 0;
4294 // Do not display error message, otherwise Vim hangs, waiting for "cont"
4295 // to be typed. Do generate errors so that try/catch works.
4296 ++emsg_silent;
4297
4298 res = eval_to_string(expr, NULL, TRUE);
4299
4300 debug_break_level = save_dbl;
4301 redir_off = save_ro;
4302 --emsg_silent;
4303 if (emsg_silent < 0)
4304 emsg_silent = 0;
4305 if (did_save_funccal)
4306 restore_funccal();
4307
4308 // A client can tell us to redraw, but not to display the cursor, so do
4309 // that here.
4310 setcursor();
4311 out_flush_cursor(FALSE, FALSE);
4312
4313 return res;
4314 }
4315
4316 /*
4317 * Evaluate a command or expression sent to ourselves.
4318 */
4319 int
4320 sendToLocalVim(char_u *cmd, int asExpr, char_u **result)
4321 {
4322 if (asExpr)
4323 {
4324 char_u *ret;
4325
4326 ret = eval_client_expr_to_string(cmd);
4327 if (result != NULL)
4328 {
4329 if (ret == NULL)
4330 {
4331 char *err = _(e_invexprmsg);
4332 size_t len = STRLEN(cmd) + STRLEN(err) + 5;
4333 char_u *msg;
4334
4335 msg = alloc(len);
4336 if (msg != NULL)
4337 vim_snprintf((char *)msg, len, "%s: \"%s\"", err, cmd);
4338 *result = msg;
4339 }
4340 else
4341 *result = ret;
4342 }
4343 else
4344 vim_free(ret);
4345 return ret == NULL ? -1 : 0;
4346 }
4347 server_to_input_buf(cmd);
4348 return 0;
4349 }
4350
4351 /*
4352 * If conversion is needed, convert "data" from "client_enc" to 'encoding' and
4353 * return an allocated string. Otherwise return "data".
4354 * "*tofree" is set to the result when it needs to be freed later.
4355 */
4356 char_u *
4357 serverConvert(
4358 char_u *client_enc UNUSED,
4359 char_u *data,
4360 char_u **tofree)
4361 {
4362 char_u *res = data;
4363
4364 *tofree = NULL;
4365 if (client_enc != NULL && p_enc != NULL)
4366 {
4367 vimconv_T vimconv;
4368
4369 vimconv.vc_type = CONV_NONE;
4370 if (convert_setup(&vimconv, client_enc, p_enc) != FAIL
4371 && vimconv.vc_type != CONV_NONE)
4372 {
4373 res = string_convert(&vimconv, data, NULL);
4374 if (res == NULL)
4375 res = data;
4376 else
4377 *tofree = res;
4378 }
4379 convert_setup(&vimconv, NULL, NULL);
4380 }
4381 return res;
4382 }
4383 #endif