-*builtin.txt* For Vim version 9.2. Last change: 2026 Jun 17
+*builtin.txt* For Vim version 9.2. Last change: 2026 Jun 24
VIM REFERENCE MANUAL by Bram Moolenaar
Return type: |Number|
-serverlist() *serverlist()*
+serverlist([{dict}]) *serverlist()*
Return a list of available server names, one per line.
When there are no servers or the information is not available
- an empty string is returned. See also |clientserver|.
+ an empty string is returned.
{only available when compiled with the |+clientserver| feature}
+
+ If {dict} is given, then it is a |Dictionary| supporting the
+ following options:
+ key type meaning ~
+ list |Boolean| Return a list of strings,
+ where each string is a server
+ name.
+
+ See also |clientserver|.
+
Example: >
:echo serverlist()
<
- Return type: |String|
+ Return type: |String| or list<string>
setbufline({buf}, {lnum}, {text}) *setbufline()*
- During |complete()|-triggered completion, CTRL-N and CTRL-P are now subject
to insert-mode mappings.
- It is possible to clear the alternate file register |quote#|.
+- |serverlist()| can return a list of all available server names.
*added-9.3*
}
else if (STRICMP(argv[i], "--serverlist") == 0)
{
+ list_T *list = NULL;
+ garray_T ga;
+
# ifdef MSWIN
if (clientserver_method == CLIENTSERVER_METHOD_MSWIN)
// Win32 always works?
- res = serverGetVimNames();
+ list = serverGetVimNames();
# endif
# ifdef FEAT_SOCKETSERVER
if (clientserver_method == CLIENTSERVER_METHOD_SOCKET)
-# ifdef MSWIN
- res = vim_strsave((char_u *)"");
-# else
- res = socketserver_list();
-# endif
+ list = socketserver_list();
# endif
# ifdef FEAT_X11
if (clientserver_method == CLIENTSERVER_METHOD_X11 &&
xterm_dpy != NULL)
- res = serverGetVimNames(xterm_dpy);
+ list = serverGetVimNames(xterm_dpy);
# endif
+
+ ga_init2(&ga, 1, 80);
+ if (list != NULL)
+ {
+ list_join(&ga, list, (char_u *)"\n", TRUE, FALSE, 0);
+ ga_append(&ga, NUL);
+ list_free(list);
+ }
+ res = ga.ga_data;
+
if (did_emsg)
mch_errmsg("\n");
}
void
f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
{
- char_u *r = NULL;
+ list_T *list = NULL;
+ bool use_list = false;
+
+ if (check_for_opt_dict_arg(argvars, 0) == FAIL)
+ return;
+
+ if (argvars[0].v_type != VAR_UNKNOWN)
+ {
+ dict_T *d = argvars[0].vval.v_dict;
+
+ use_list = dict_get_bool(d, "list", false);
+ }
# ifdef FEAT_CLIENTSERVER
# ifdef MSWIN
if (clientserver_method == CLIENTSERVER_METHOD_MSWIN)
- r = serverGetVimNames();
+ list = serverGetVimNames();
# endif
# ifdef FEAT_SOCKETSERVER
if (clientserver_method == CLIENTSERVER_METHOD_SOCKET)
-# ifdef MSWIN
- r = vim_strsave((char_u *)"");
-# else
- r = socketserver_list();
-# endif
+ list = socketserver_list();
# endif
# ifdef FEAT_X11
if (clientserver_method == CLIENTSERVER_METHOD_X11)
{
- make_connection();
- if (X_DISPLAY != NULL)
- r = serverGetVimNames(X_DISPLAY);
+ make_connection();
+ if (X_DISPLAY != NULL)
+ list = serverGetVimNames(X_DISPLAY);
}
# endif
# endif
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = r;
+ if (use_list && list != NULL)
+ {
+ list->lv_refcount++;
+ rettv->v_type = VAR_LIST;
+ rettv->vval.v_list = list;
+ }
+ else
+ {
+ garray_T ga;
+
+ ga_init2(&ga, 1, 80);
+
+ if (list != NULL)
+ {
+ list_join(&ga, list, (char_u *)"\n", TRUE, FALSE, 0);
+ ga_append(&ga, NUL);
+ list_free(list);
+ }
+
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = (char_u *)ga.ga_data;
+ }
}
#endif
ret_list_number, f_searchpos},
{"server2client", 2, 2, FEARG_1, arg2_string,
ret_number_bool, f_server2client},
- {"serverlist", 0, 0, 0, NULL,
- ret_string, f_serverlist},
+ {"serverlist", 0, 1, 0, arg1_dict_any,
+ ret_any, f_serverlist},
{"setbufline", 3, 3, FEARG_3, arg3_setbufline,
ret_number_bool, f_setbufline},
{"setbufvar", 3, 3, FEARG_3, arg3_buffer_string_any,
* Fetch a list of all the Vim instance names currently registered for the
* display.
*
- * Returns a newline separated list in allocated memory or NULL.
+ * Returns a list of strings or NULL on failure.
*/
- char_u *
+ list_T *
serverGetVimNames(Display *dpy)
{
char_u *regProp;
char_u *p;
long_u numItems;
int_u w;
- garray_T ga;
+ list_T *list;
if (registryProperty == None)
{
return NULL;
}
+ list = list_alloc();
+ if (list == NULL)
+ return NULL;
+
/*
* Read the registry property.
*/
/*
* Scan all of the names out of the property.
*/
- ga_init2(&ga, 1, 100);
for (p = regProp; (long_u)(p - regProp) < numItems; p++)
{
entry = p;
w = None;
sscanf((char *)entry, "%x", &w);
if (WindowValid(dpy, (Window)w))
- {
- ga_concat(&ga, p + 1);
- GA_CONCAT_LITERAL(&ga, "\n");
- }
+ list_append_string(list, p + 1, -1);
while (*p != 0)
p++;
}
}
if (regProp != empty_prop)
XFree(regProp);
- ga_append(&ga, NUL);
- return ga.ga_data;
+ return list;
}
/////////////////////////////////////////////////////////////
static BOOL CALLBACK
enumWindowsGetNames(HWND hwnd, LPARAM lparam)
{
- garray_T *ga = (garray_T *)lparam;
+ list_T *list = (list_T *)lparam;
char server[MAX_PATH];
// Get the title of the window
if (getVimServerName(hwnd, server, sizeof(server)) == 0)
return TRUE;
- // Add the name to the list
- ga_concat(ga, (char_u *)server);
- GA_CONCAT_LITERAL(ga, "\n");
+ list_append_string(list, (char_u *)server, -1);
return TRUE;
}
}
}
- char_u *
+ list_T *
serverGetVimNames(void)
{
- garray_T ga;
+ list_T *list = list_alloc();
- ga_init2(&ga, 1, 100);
+ if (list == NULL)
+ return NULL;
- enum_windows(enumWindowsGetNames, (LPARAM)(&ga));
- ga_append(&ga, NUL);
+ enum_windows(enumWindowsGetNames, (LPARAM)list);
- return ga.ga_data;
+ return list;
}
int
int serverRegisterName(Display *dpy, char_u *name);
void serverChangeRegisteredWindow(Display *dpy, Window newwin);
int serverSendToVim(Display *dpy, char_u *name, char_u *cmd, char_u **result, Window *server, Bool asExpr, int timeout, Bool localLoop, int silent);
-char_u *serverGetVimNames(Display *dpy);
+list_T *serverGetVimNames(Display *dpy);
Window serverStrToWin(char_u *str);
int serverSendReply(char_u *name, char_u *str);
int serverReadReply(Display *dpy, Window win, char_u **str, int localLoop, int timeout);
void win32_set_foreground(void);
void serverInitMessaging(void);
void serverSetName(char_u *name);
-char_u *serverGetVimNames(void);
+list_T *serverGetVimNames(void);
int serverSendReply(char_u *name, char_u *reply);
int serverSendToVim(char_u *name, char_u *cmd, char_u **result, void *ptarget, int asExpr, int timeout, int silent);
void serverForeground(char_u *name);
/* socketserver.c */
int socketserver_start(char_u *name, bool quiet);
void socketserver_stop(void);
-char_u *socketserver_list(void);
+list_T *socketserver_list(void);
int set_ref_in_socketserver_channel(int copyID);
void socketserver_parse_messages(void);
int socketserver_send(char_u *name, char_u *str, char_u **result, bool is_expr, int timeout, bool silent, channel_T **ch);
/*
* List available sockets that can be connected to, only in common directories
* that Vim knows about. Vim instances with custom socket paths will not be
- * detected. Returns a newline separated string on success and NULL on failure.
+ * detected. Returns a list of strings (with reference count not set) on success
+ * and NULL on failure.
*/
- char_u *
+ list_T *
socketserver_list(void)
{
+ list_T *list = list_alloc();
+
+ if (list == NULL)
+ return NULL;
+
# ifdef MSWIN
// Only support addresses on Windows
- return vim_strsave((char_u *)"");
+ return list;
# else
- garray_T str;
string_T buf;
string_T path;
DIR *dirp;
buf.length = 0;
path.length = 0;
- ga_init2(&str, 1, 100);
-
for (size_t i = 0 ; i < ARRAY_LENGTH(known_dirs); i++)
{
const char_u *dir = known_dirs[i];
buf.length = vim_snprintf_safelen((char *)buf.string, MAXPATHL,
"%s/%s", path.string, dp->d_name);
- ga_concat_len(&str, (char_u *)dp->d_name,
+ list_append_string(list, (char_u *)dp->d_name,
buf.length - (path.length + 1));
- ga_append(&str, '\n');
}
closedir(dirp);
vim_free(path.string);
vim_free(buf.string);
- ga_append(&str, NUL);
-
- return str.ga_data;
+ return list;
# endif
}
endtry
endfunc
+" Test if serverlist() can return a list of strings
+func Test_clientserver_serverlist_list()
+ CheckNotGui
+
+ let g:test_is_flaky = 1
+ let cmd = GetVimCommand()
+
+ if cmd == ''
+ throw 'GetVimCommand() failed'
+ endif
+
+ " Don't use channel:2000, because previous tests use that and it may take a
+ " while for the channel to fully close.
+ let actual = cmd .. ' --servername XVIMTEST'
+
+ let job = job_start(actual, {'stoponexit': 'kill', 'out_io': 'null'})
+
+ call WaitForAssert({-> assert_match('XVIMTEST', serverlist())})
+
+ call assert_equal('list<string>', typename(serverlist(#{list: v:true})))
+ call assert_true(serverlist(#{list: v:true})->index('XVIMTEST') != -1)
+
+ if has('win32') || has('gui_running')
+ call job_stop(job, 'kill')
+ else
+ call system(actual .. " --remote-expr 'execute(\"qa!\")'")
+ endif
+ try
+ call WaitForAssert({-> assert_equal("dead", job_status(job))})
+ finally
+ if job_status(job) != 'dead'
+ call assert_report('Server did not exit')
+ call job_stop(job, 'kill')
+ endif
+ endtry
+endfunc
+
" Uncomment this line to get a debugging log
" call ch_logfile('channellog', 'w')
v9.CheckSourceDefAndScriptFailure(['remote_startserver({})'], ['E1013: Argument 1: type mismatch, expected string but got dict<any>', 'E1174: String required for argument 1'])
enddef
+def Test_remote_serverlist()
+ CheckFeature clientserver
+
+ v9.CheckSourceDefAndScriptFailure(['serverlist("")'], ['E1013: Argument 1: type mismatch, expected dict<any> but got string', 'E1206: Dictionary required for argument 1'])
+ v9.CheckSourceScriptFailure(['vim9script', 'serverlist({list: ""})'], 'E1135: Using a String as a Bool: ""')
+ var l: any = serverlist()
+ assert_equal(v:t_string, type(l))
+ l = serverlist({'list': true})
+ assert_equal(v:t_list, type(l))
+enddef
+
def Test_remove_literal_list()
var l: list<number> = [1, 2, 3, 4]
assert_equal([1, 2], remove(l, 0, 1))
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 721,
/**/
720,
/**/