Skip to content

Commit c57f6b2

Browse files
authored
Merge neovim#8519 feat: name, test ids, sockets in stdpath(state)
2 parents 279bc71 + 1f2c2a3 commit c57f6b2

File tree

21 files changed

+372
-259
lines changed

21 files changed

+372
-259
lines changed

runtime/doc/builtin.txt

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6628,30 +6628,29 @@ serverlist() *serverlist()*
66286628
66296629
serverstart([{address}]) *serverstart()*
66306630
Opens a socket or named pipe at {address} and listens for
6631-
|RPC| messages. Clients can send |API| commands to the address
6632-
to control Nvim.
6633-
6634-
Returns the address string.
6635-
6636-
If {address} does not contain a colon ":" it is interpreted as
6637-
a named pipe or Unix domain socket path.
6638-
6639-
Example: >
6631+
|RPC| messages. Clients can send |API| commands to the
6632+
returned address to control Nvim.
6633+
6634+
Returns the address string (may differ from the requested
6635+
{address}).
6636+
6637+
- If {address} contains a colon ":" it is interpreted as
6638+
a TCP/IPv4/IPv6 address where the last ":" separates host
6639+
and port (empty or zero assigns a random port).
6640+
- Else it is interpreted as a named pipe or Unix domain socket
6641+
path. If there are no slashes it is treated as a name and
6642+
appended to a generated path.
6643+
- If {address} is empty it generates a path.
6644+
6645+
Example named pipe: >
66406646
if has('win32')
6641-
call serverstart('\\.\pipe\nvim-pipe-1234')
6647+
echo serverstart('\\.\pipe\nvim-pipe-1234')
66426648
else
6643-
call serverstart('nvim.sock')
6649+
echo serverstart('nvim.sock')
66446650
endif
66456651
<
6646-
If {address} contains a colon ":" it is interpreted as a TCP
6647-
address where the last ":" separates the host and port.
6648-
Assigns a random port if it is empty or 0. Supports IPv4/IPv6.
6649-
6650-
Example: >
6651-
:call serverstart('::1:12345')
6652-
<
6653-
If no address is given, it is equivalent to: >
6654-
:call serverstart(tempname())
6652+
Example TCP/IP address: >
6653+
echo serverstart('::1:12345')
66556654
66566655
serverstop({address}) *serverstop()*
66576656
Closes the pipe or socket at {address}.
@@ -7545,7 +7544,7 @@ stdpath({what}) *stdpath()* *E6100*
75457544
data_dirs List Other data directories.
75467545
log String Logs directory (for use by plugins too).
75477546
state String Session state directory: storage for file
7548-
drafts, undo history, shada, etc.
7547+
drafts, undo, shada, named pipes, ...
75497548

75507549
Example: >
75517550
:echo stdpath("config")

src/nvim/api/vim.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1790,8 +1790,9 @@ Dictionary nvim__stats(void)
17901790
{
17911791
Dictionary rv = ARRAY_DICT_INIT;
17921792
PUT(rv, "fsync", INTEGER_OBJ(g_stats.fsync));
1793-
PUT(rv, "redraw", INTEGER_OBJ(g_stats.redraw));
1793+
PUT(rv, "log_skip", INTEGER_OBJ(g_stats.log_skip));
17941794
PUT(rv, "lua_refcount", INTEGER_OBJ(nlua_get_global_ref_count()));
1795+
PUT(rv, "redraw", INTEGER_OBJ(g_stats.redraw));
17951796
return rv;
17961797
}
17971798

src/nvim/eval/funcs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8497,7 +8497,7 @@ static void f_serverstart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
84978497
address = xstrdup(tv_get_string(argvars));
84988498
}
84998499
} else {
8500-
address = server_address_new();
8500+
address = server_address_new(NULL);
85018501
}
85028502

85038503
int result = server_start(address);

src/nvim/event/process.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ int process_spawn(Process *proc, bool in, bool out, bool err)
120120
proc->internal_close_cb = decref;
121121
proc->refcount++;
122122
kl_push(WatcherPtr, proc->loop->children, proc);
123-
DLOG("new: pid=%d argv=[%s]", proc->pid, *proc->argv);
123+
DLOG("new: pid=%d argv=[%s]", proc->pid, proc->argv[0]);
124124
return 0;
125125
}
126126

src/nvim/log.c

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@
1616
#include <uv.h>
1717

1818
#include "auto/config.h"
19+
#include "nvim/eval.h"
1920
#include "nvim/log.h"
2021
#include "nvim/main.h"
2122
#include "nvim/message.h"
2223
#include "nvim/os/os.h"
2324
#include "nvim/os/time.h"
25+
#include "nvim/path.h"
2426
#include "nvim/types.h"
2527

26-
#define LOG_FILE_ENV "NVIM_LOG_FILE"
27-
2828
/// Cached location of the expanded log file path decided by log_path_init().
2929
static char log_file_path[MAXPATHL + 1] = { 0 };
3030

@@ -52,17 +52,16 @@ static bool log_try_create(char *fname)
5252
return true;
5353
}
5454

55-
/// Initializes path to log file. Sets $NVIM_LOG_FILE if empty.
55+
/// Initializes the log file path and sets $NVIM_LOG_FILE if empty.
5656
///
5757
/// Tries $NVIM_LOG_FILE, or falls back to $XDG_STATE_HOME/nvim/log. Failed
5858
/// initialization indicates either a bug in expand_env() or both $NVIM_LOG_FILE
5959
/// and $HOME environment variables are undefined.
6060
static void log_path_init(void)
6161
{
6262
size_t size = sizeof(log_file_path);
63-
expand_env((char_u *)"$" LOG_FILE_ENV, (char_u *)log_file_path,
64-
(int)size - 1);
65-
if (strequal("$" LOG_FILE_ENV, log_file_path)
63+
expand_env((char_u *)"$" ENV_LOGFILE, (char_u *)log_file_path, (int)size - 1);
64+
if (strequal("$" ENV_LOGFILE, log_file_path)
6665
|| log_file_path[0] == '\0'
6766
|| os_isdir((char_u *)log_file_path)
6867
|| !log_try_create(log_file_path)) {
@@ -87,7 +86,7 @@ static void log_path_init(void)
8786
log_file_path[0] = '\0';
8887
return;
8988
}
90-
os_setenv(LOG_FILE_ENV, log_file_path, true);
89+
os_setenv(ENV_LOGFILE, log_file_path, true);
9190
if (log_dir_failure) {
9291
WLOG("Failed to create directory %s for writing logs: %s",
9392
failed_dir, os_strerror(log_dir_failure));
@@ -209,7 +208,7 @@ FILE *open_log_file(void)
209208
// - Directory does not exist
210209
// - File is not writable
211210
do_log_to_file(stderr, LOGLVL_ERR, NULL, __func__, __LINE__, true,
212-
"failed to open $" LOG_FILE_ENV " (%s): %s",
211+
"failed to open $" ENV_LOGFILE " (%s): %s",
213212
strerror(errno), log_file_path);
214213
return stderr;
215214
}
@@ -277,6 +276,9 @@ static bool v_do_log_to_file(FILE *log_file, int log_level, const char *context,
277276
va_list args)
278277
FUNC_ATTR_PRINTF(7, 0)
279278
{
279+
// Name of the Nvim instance that produced the log.
280+
static char name[16] = { 0 };
281+
280282
static const char *log_levels[] = {
281283
[LOGLVL_DBG] = "DBG",
282284
[LOGLVL_INF] = "INF",
@@ -291,8 +293,7 @@ static bool v_do_log_to_file(FILE *log_file, int log_level, const char *context,
291293
return false;
292294
}
293295
char date_time[20];
294-
if (strftime(date_time, sizeof(date_time), "%Y-%m-%dT%H:%M:%S",
295-
&local_time) == 0) {
296+
if (strftime(date_time, sizeof(date_time), "%Y-%m-%dT%H:%M:%S", &local_time) == 0) {
296297
return false;
297298
}
298299

@@ -302,14 +303,30 @@ static bool v_do_log_to_file(FILE *log_file, int log_level, const char *context,
302303
millis = (int)curtime.tv_usec / 1000;
303304
}
304305

306+
// Get a name for this Nvim instance.
307+
// TODO(justinmk): expose this as v:name ?
308+
if (starting || name[0] == '\0') {
309+
// Parent servername.
310+
const char *parent = path_tail(os_getenv(ENV_NVIM));
311+
// Servername. Empty until starting=false.
312+
const char *serv = path_tail(get_vim_var_str(VV_SEND_SERVER));
313+
if (parent && parent[0] != NUL) {
314+
snprintf(name, sizeof(name), "%s/c", parent); // "/c" indicates child.
315+
} else if (serv && serv[0] != NUL) {
316+
snprintf(name, sizeof(name), "%s", serv ? serv : "");
317+
} else {
318+
int64_t pid = os_get_pid();
319+
snprintf(name, sizeof(name), "?.%-5" PRId64, pid);
320+
}
321+
}
322+
305323
// Print the log message.
306-
int64_t pid = os_get_pid();
307324
int rv = (line_num == -1 || func_name == NULL)
308-
? fprintf(log_file, "%s %s.%03d %-5" PRId64 " %s",
309-
log_levels[log_level], date_time, millis, pid,
325+
? fprintf(log_file, "%s %s.%03d %-10s %s",
326+
log_levels[log_level], date_time, millis, name,
310327
(context == NULL ? "?:" : context))
311-
: fprintf(log_file, "%s %s.%03d %-5" PRId64 " %s%s:%d: ",
312-
log_levels[log_level], date_time, millis, pid,
328+
: fprintf(log_file, "%s %s.%03d %-10s %s%s:%d: ",
329+
log_levels[log_level], date_time, millis, name,
313330
(context == NULL ? "" : context),
314331
func_name, line_num);
315332
if (rv < 0) {

src/nvim/msgpack_rpc/server.c

Lines changed: 39 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323

2424
#define MAX_CONNECTIONS 32
2525
#define ENV_LISTEN "NVIM_LISTEN_ADDRESS" // deprecated
26-
#define ENV_NVIM "NVIM"
2726

2827
static garray_T watchers = GA_EMPTY_INIT_VALUE;
2928

@@ -43,7 +42,7 @@ bool server_init(const char *listen_addr)
4342

4443
int rv = listen_addr ? server_start(listen_addr) : 1;
4544
if (0 != rv) {
46-
listen_addr = server_address_new();
45+
listen_addr = server_address_new(NULL);
4746
if (!listen_addr) {
4847
return false;
4948
}
@@ -56,6 +55,11 @@ bool server_init(const char *listen_addr)
5655
os_unsetenv(ENV_LISTEN);
5756
}
5857

58+
// TODO(justinmk): this is for logging_spec. Can remove this after nvim_log #7062 is merged.
59+
if (os_env_exists("__NVIM_TEST_LOG")) {
60+
ELOG("test log message");
61+
}
62+
5963
return rv == 0;
6064
}
6165

@@ -83,23 +87,26 @@ void server_teardown(void)
8387

8488
/// Generates unique address for local server.
8589
///
86-
/// In Windows this is a named pipe in the format
87-
/// \\.\pipe\nvim-<PID>-<COUNTER>.
88-
///
89-
/// For other systems it is a path returned by vim_tempname().
90-
///
91-
/// This function is NOT thread safe
92-
char *server_address_new(void)
90+
/// Named pipe format:
91+
/// - Windows: "\\.\pipe\<name>.<pid>.<counter>"
92+
/// - Other: "~/.local/state/nvim/<name>.<pid>.<counter>"
93+
char *server_address_new(const char *name)
9394
{
94-
#ifdef WIN32
9595
static uint32_t count = 0;
96-
char template[ADDRESS_MAX_SIZE];
97-
snprintf(template, ADDRESS_MAX_SIZE,
98-
"\\\\.\\pipe\\nvim-%" PRIu64 "-%" PRIu32, os_get_pid(), count++);
99-
return xstrdup(template);
96+
char fmt[ADDRESS_MAX_SIZE];
97+
#ifdef WIN32
98+
int r = snprintf(fmt, sizeof(fmt), "\\\\.\\pipe\\%s.%" PRIu64 ".%" PRIu32,
99+
name ? name : "nvim", os_get_pid(), count++);
100100
#else
101-
return (char *)vim_tempname();
101+
char *dir = get_xdg_home(kXDGStateHome);
102+
int r = snprintf(fmt, sizeof(fmt), "%s/%s.%" PRIu64 ".%" PRIu32,
103+
dir, name ? name : "nvim", os_get_pid(), count++);
104+
xfree(dir);
102105
#endif
106+
if ((size_t)r >= sizeof(fmt)) {
107+
ELOG("truncated server address");
108+
}
109+
return xstrdup(fmt);
103110
}
104111

105112
/// Check if this instance owns a pipe address.
@@ -114,35 +121,35 @@ bool server_owns_pipe_address(const char *path)
114121
return false;
115122
}
116123

117-
/// Starts listening for API calls.
124+
/// Starts listening for RPC calls.
118125
///
119-
/// The socket type is determined by parsing `endpoint`: If it's a valid IPv4
120-
/// or IPv6 address in 'ip:[port]' format, then it will be a TCP socket.
121-
/// Otherwise it will be a Unix socket or named pipe (Windows).
126+
/// Socket type is decided by the format of `addr`:
127+
/// - TCP socket if it looks like an IPv4/6 address ("ip:[port]").
128+
/// - If [port] is omitted, a random one is assigned.
129+
/// - Unix socket (or named pipe on Windows) otherwise.
130+
/// - If the name doesn't contain slashes it is appended to a generated path. #8519
122131
///
123-
/// If no port is given, a random one will be assigned.
124-
///
125-
/// @param endpoint Address of the server. Either a 'ip:[port]' string or an
126-
/// arbitrary identifier (trimmed to 256 bytes) for the Unix
127-
/// socket or named pipe.
128-
/// @returns 0: success, 1: validation error, 2: already listening,
129-
/// -errno: failed to bind or listen.
130-
int server_start(const char *endpoint)
132+
/// @param addr Server address: a "ip:[port]" string or arbitrary name or filepath (max 256 bytes)
133+
/// for the Unix socket or named pipe.
134+
/// @returns 0: success, 1: validation error, 2: already listening, -errno: failed to bind/listen.
135+
int server_start(const char *addr)
131136
{
132-
if (endpoint == NULL || endpoint[0] == '\0') {
133-
WLOG("Empty or NULL endpoint");
137+
if (addr == NULL || addr[0] == '\0') {
138+
WLOG("Empty or NULL address");
134139
return 1;
135140
}
136141

142+
bool isname = !strstr(addr, ":") && !strstr(addr, "/") && !strstr(addr, "\\");
143+
char *addr_gen = isname ? server_address_new(addr) : NULL;
137144
SocketWatcher *watcher = xmalloc(sizeof(SocketWatcher));
138-
139-
int result = socket_watcher_init(&main_loop, watcher, endpoint);
145+
int result = socket_watcher_init(&main_loop, watcher, isname ? addr_gen : addr);
146+
xfree(addr_gen);
140147
if (result < 0) {
141148
xfree(watcher);
142149
return result;
143150
}
144151

145-
// Check if a watcher for the endpoint already exists
152+
// Check if a watcher for the address already exists.
146153
for (int i = 0; i < watchers.ga_len; i++) {
147154
if (!strcmp(watcher->addr, ((SocketWatcher **)watchers.ga_data)[i]->addr)) {
148155
ELOG("Already listening on %s", watcher->addr);

src/nvim/os/os.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,7 @@
1616
# include "os/users.h.generated.h"
1717
#endif
1818

19+
#define ENV_LOGFILE "NVIM_LOG_FILE"
20+
#define ENV_NVIM "NVIM"
21+
1922
#endif // NVIM_OS_OS_H

src/nvim/os/pty_process_unix.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,10 +163,15 @@ static struct termios termios_default;
163163
/// @param tty_fd TTY file descriptor, or -1 if not in a terminal.
164164
void pty_process_save_termios(int tty_fd)
165165
{
166-
DLOG("tty_fd=%d", tty_fd);
167-
if (tty_fd == -1 || tcgetattr(tty_fd, &termios_default) != 0) {
166+
if (tty_fd == -1) {
168167
return;
169168
}
169+
int rv = tcgetattr(tty_fd, &termios_default);
170+
if (rv != 0) {
171+
ELOG("tcgetattr failed (tty_fd=%d): %s", tty_fd, strerror(errno));
172+
} else {
173+
DLOG("tty_fd=%d", tty_fd);
174+
}
170175
}
171176

172177
/// @returns zero on success, or negative error code

src/nvim/path.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,12 @@ FileComparison path_full_compare(char_u *const s1, char_u *const s2, const bool
8888
return kDifferentFiles;
8989
}
9090

91-
/// Gets the tail (i.e., the filename segment) of a path `fname`.
91+
/// Gets the tail (filename segment) of path `fname`.
92+
///
93+
/// Examples:
94+
/// - "dir/file.txt" => "file.txt"
95+
/// - "file.txt" => "file.txt"
96+
/// - "dir/" => ""
9297
///
9398
/// @return pointer just past the last path separator (empty string, if fname
9499
/// ends in a slash), or empty string if fname is NULL.

0 commit comments

Comments
 (0)