aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/os
diff options
context:
space:
mode:
authorJosh Rahm <rahm@google.com>2022-07-18 19:37:18 +0000
committerJosh Rahm <rahm@google.com>2022-07-18 19:37:18 +0000
commit308e1940dcd64aa6c344c403d4f9e0dda58d9c5c (patch)
tree35fe43e01755e0f312650667004487a44d6b7941 /src/nvim/os
parent96a00c7c588b2f38a2424aeeb4ea3581d370bf2d (diff)
parente8c94697bcbe23a5c7b07c292b90a6b70aadfa87 (diff)
downloadrneovim-308e1940dcd64aa6c344c403d4f9e0dda58d9c5c.tar.gz
rneovim-308e1940dcd64aa6c344c403d4f9e0dda58d9c5c.tar.bz2
rneovim-308e1940dcd64aa6c344c403d4f9e0dda58d9c5c.zip
Merge remote-tracking branch 'upstream/master' into rahm
Diffstat (limited to 'src/nvim/os')
-rw-r--r--src/nvim/os/env.c77
-rw-r--r--src/nvim/os/fs.c65
-rw-r--r--src/nvim/os/fs.h10
-rw-r--r--src/nvim/os/input.c67
-rw-r--r--src/nvim/os/lang.c60
-rw-r--r--src/nvim/os/os.h3
-rw-r--r--src/nvim/os/os_defs.h2
-rw-r--r--src/nvim/os/os_win_console.c1
-rw-r--r--src/nvim/os/pty_process_unix.c32
-rw-r--r--src/nvim/os/pty_process_win.c168
-rw-r--r--src/nvim/os/pty_process_win.h15
-rw-r--r--src/nvim/os/shell.c41
-rw-r--r--src/nvim/os/signal.c32
-rw-r--r--src/nvim/os/stdpaths.c44
-rw-r--r--src/nvim/os/stdpaths_defs.h1
-rw-r--r--src/nvim/os/time.c1
-rw-r--r--src/nvim/os/users.c35
-rw-r--r--src/nvim/os/win_defs.h2
18 files changed, 306 insertions, 350 deletions
diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c
index e9f44d2775..9c93057fe7 100644
--- a/src/nvim/os/env.c
+++ b/src/nvim/os/env.c
@@ -529,9 +529,9 @@ void free_homedir(void)
/// again soon.
/// @param src String containing environment variables to expand
/// @see {expand_env}
-char_u *expand_env_save(char_u *src)
+char *expand_env_save(char *src)
{
- return expand_env_save_opt(src, false);
+ return (char *)expand_env_save_opt((char_u *)src, false);
}
/// Similar to expand_env_save() but when "one" is `true` handle the string as
@@ -580,14 +580,14 @@ void expand_env_esc(char_u *restrict srcp, char_u *restrict dst, int dstlen, boo
int prefix_len = (prefix == NULL) ? 0 : (int)STRLEN(prefix);
- char_u *src = skipwhite(srcp);
+ char_u *src = (char_u *)skipwhite((char *)srcp);
dstlen--; // leave one char space for "\,"
while (*src && dstlen > 0) {
// Skip over `=expr`.
if (src[0] == '`' && src[1] == '=') {
var = src;
src += 2;
- (void)skip_expr(&src);
+ (void)skip_expr((char **)&src);
if (*src == '`') {
src++;
}
@@ -644,7 +644,7 @@ void expand_env_esc(char_u *restrict srcp, char_u *restrict dst, int dstlen, boo
#endif
} else if (src[1] == NUL // home directory
|| vim_ispathsep(src[1])
- || vim_strchr((char_u *)" ,\t\n", src[1]) != NULL) {
+ || vim_strchr(" ,\t\n", src[1]) != NULL) {
var = (char_u *)homedir;
tail = src + 1;
} else { // user directory
@@ -663,7 +663,7 @@ void expand_env_esc(char_u *restrict srcp, char_u *restrict dst, int dstlen, boo
// Get the user directory. If this fails the shell is used to expand
// ~user, which is slower and may fail on old versions of /bin/sh.
var = (*dst == NUL) ? NULL
- : (char_u *)os_get_user_directory((char *)dst + 1);
+ : (char_u *)os_get_userdir((char *)dst + 1);
mustfree = true;
if (var == NULL) {
expand_T xpc;
@@ -698,7 +698,7 @@ void expand_env_esc(char_u *restrict srcp, char_u *restrict dst, int dstlen, boo
// If "var" contains white space, escape it with a backslash.
// Required for ":e ~/tt" when $HOME includes a space.
- if (esc && var != NULL && vim_strpbrk(var, (char_u *)" \t") != NULL) {
+ if (esc && var != NULL && strpbrk((char *)var, " \t") != NULL) {
char_u *p = vim_strsave_escaped(var, (char_u *)" \t");
if (mustfree) {
@@ -715,12 +715,12 @@ void expand_env_esc(char_u *restrict srcp, char_u *restrict dst, int dstlen, boo
int c = (int)STRLEN(var);
// if var[] ends in a path separator and tail[] starts
// with it, skip a character
- if (*var != NUL && after_pathsep((char *)dst, (char *)dst + c)
+ if (after_pathsep((char *)dst, (char *)dst + c)
#if defined(BACKSLASH_IN_FILENAME)
&& dst[-1] != ':'
#endif
&& vim_ispathsep(*tail)) {
- ++tail;
+ tail++;
}
dst += c;
src = tail;
@@ -738,7 +738,7 @@ void expand_env_esc(char_u *restrict srcp, char_u *restrict dst, int dstlen, boo
at_start = false;
if (src[0] == '\\' && src[1] != NUL) {
*dst++ = *src++;
- --dstlen;
+ dstlen--;
} else if ((src[0] == ' ' || src[0] == ',') && !one) {
at_start = true;
}
@@ -805,7 +805,7 @@ static char *remove_tail(char *path, char *pend, char *dirname)
char *new_tail = pend - len - 1;
if (new_tail >= path
- && fnamencmp((char_u *)new_tail, (char_u *)dirname, len) == 0
+ && FNAMENCMP((char_u *)new_tail, (char_u *)dirname, len) == 0
&& (new_tail == path || after_pathsep(path, new_tail))) {
return new_tail;
}
@@ -878,17 +878,15 @@ const void *vim_env_iter_rev(const char delim, const char *const val, const void
}
}
-
/// @param[out] exe_name should be at least MAXPATHL in size
void vim_get_prefix_from_exepath(char *exe_name)
{
// TODO(bfredl): param could have been written as "char exe_name[MAXPATHL]"
// but c_grammar.lua does not recognize it (yet).
- xstrlcpy(exe_name, (char *)get_vim_var_str(VV_PROGPATH),
- MAXPATHL * sizeof(*exe_name));
- char *path_end = (char *)path_tail_with_sep((char_u *)exe_name);
+ xstrlcpy(exe_name, get_vim_var_str(VV_PROGPATH), MAXPATHL * sizeof(*exe_name));
+ char *path_end = path_tail_with_sep(exe_name);
*path_end = '\0'; // remove the trailing "nvim.exe"
- path_end = (char *)path_tail((char_u *)exe_name);
+ path_end = path_tail(exe_name);
*path_end = '\0'; // remove the trailing "bin/"
}
@@ -940,7 +938,7 @@ char *vim_getenv(const char *name)
// - the directory name from 'helpfile' (unless it contains '$')
// - the executable name from argv[0]
if (vim_path == NULL) {
- if (p_hf != NULL && vim_strchr(p_hf, '$') == NULL) {
+ if (p_hf != NULL && vim_strchr((char *)p_hf, '$') == NULL) {
vim_path = (char *)p_hf;
}
@@ -957,7 +955,7 @@ char *vim_getenv(const char *name)
if (vim_path != NULL) {
// remove the file name
- char *vim_path_end = (char *)path_tail((char_u *)vim_path);
+ char *vim_path_end = path_tail(vim_path);
// remove "doc/" from 'helpfile', if present
if (vim_path == (char *)p_hf) {
@@ -1035,7 +1033,7 @@ char *vim_getenv(const char *name)
/// a list of them.
///
/// @return length of the string put into dst, does not include NUL byte.
-size_t home_replace(const buf_T *const buf, const char_u *src, char_u *const dst, size_t dstlen,
+size_t home_replace(const buf_T *const buf, const char *src, char *const dst, size_t dstlen,
const bool one)
FUNC_ATTR_NONNULL_ARG(3)
{
@@ -1048,7 +1046,7 @@ size_t home_replace(const buf_T *const buf, const char_u *src, char_u *const dst
}
if (buf != NULL && buf->b_help) {
- const size_t dlen = STRLCPY(dst, path_tail(src), dstlen);
+ const size_t dlen = STRLCPY(dst, path_tail((char *)src), dstlen);
return MIN(dlen, dstlen - 1);
}
@@ -1072,8 +1070,8 @@ size_t home_replace(const buf_T *const buf, const char_u *src, char_u *const dst
size_t usedlen = 0;
size_t flen = strlen(homedir_env_mod);
char_u *fbuf = NULL;
- (void)modify_fname((char_u *)":p", false, &usedlen,
- (char_u **)&homedir_env_mod, &fbuf, &flen);
+ (void)modify_fname(":p", false, &usedlen,
+ &homedir_env_mod, (char **)&fbuf, &flen);
flen = strlen(homedir_env_mod);
assert(homedir_env_mod != homedir_env);
if (vim_ispathsep(homedir_env_mod[flen - 1])) {
@@ -1087,9 +1085,9 @@ size_t home_replace(const buf_T *const buf, const char_u *src, char_u *const dst
}
if (!one) {
- src = skipwhite(src);
+ src = skipwhite((char *)src);
}
- char *dst_p = (char *)dst;
+ char *dst_p = dst;
while (*src && dstlen > 0) {
// Here we are at the beginning of a file name.
// First, check to see if the beginning of the file name matches
@@ -1102,7 +1100,7 @@ size_t home_replace(const buf_T *const buf, const char_u *src, char_u *const dst
size_t len = dirlen;
for (;;) {
if (len
- && fnamencmp(src, (char_u *)p, len) == 0
+ && FNAMENCMP(src, (char_u *)p, len) == 0
&& (vim_ispathsep(src[len])
|| (!one && (src[len] == ',' || src[len] == ' '))
|| src[len] == NUL)) {
@@ -1111,10 +1109,9 @@ size_t home_replace(const buf_T *const buf, const char_u *src, char_u *const dst
*dst_p++ = '~';
}
- // If it's just the home directory, add "/".
- if (!vim_ispathsep(src[0]) && --dstlen > 0) {
- *dst_p++ = '/';
- }
+ // Do not add directory separator into dst, because dst is
+ // expected to just return the directory name without the
+ // directory separator '/'.
break;
}
if (p == homedir_env_mod) {
@@ -1126,11 +1123,11 @@ size_t home_replace(const buf_T *const buf, const char_u *src, char_u *const dst
// if (!one) skip to separator: space or comma.
while (*src && (one || (*src != ',' && *src != ' ')) && --dstlen > 0) {
- *dst_p++ = (char)(*src++);
+ *dst_p++ = *src++;
}
// Skip separator.
while ((*src == ' ' || *src == ',') && --dstlen > 0) {
- *dst_p++ = (char)(*src++);
+ *dst_p++ = *src++;
}
}
// If (dstlen == 0) out of space, what to do???
@@ -1140,26 +1137,26 @@ size_t home_replace(const buf_T *const buf, const char_u *src, char_u *const dst
if (must_free) {
xfree(homedir_env_mod);
}
- return (size_t)(dst_p - (char *)dst);
+ return (size_t)(dst_p - dst);
}
/// Like home_replace, store the replaced string in allocated memory.
/// @param buf When not NULL, check for help files
/// @param src Input file name
-char_u *home_replace_save(buf_T *buf, char_u *src) FUNC_ATTR_NONNULL_RET
+char *home_replace_save(buf_T *buf, char *src)
+ FUNC_ATTR_NONNULL_RET
{
size_t len = 3; // space for "~/" and trailing NUL
if (src != NULL) { // just in case
len += STRLEN(src);
}
- char_u *dst = xmalloc(len);
+ char *dst = xmalloc(len);
home_replace(buf, src, dst, len, true);
return dst;
}
-
/// Function given to ExpandGeneric() to obtain an environment variable name.
-char_u *get_env_name(expand_T *xp, int idx)
+char *get_env_name(expand_T *xp, int idx)
{
#define ENVNAMELEN 100
// this static buffer is needed to avoid a memory leak in ExpandGeneric
@@ -1169,7 +1166,7 @@ char_u *get_env_name(expand_T *xp, int idx)
if (envname) {
STRLCPY(name, envname, ENVNAMELEN);
xfree(envname);
- return name;
+ return (char *)name;
}
return NULL;
}
@@ -1193,7 +1190,7 @@ bool os_setenv_append_path(const char *fname)
internal_error("os_setenv_append_path()");
return false;
}
- const char *tail = (char *)path_tail_with_sep((char_u *)fname);
+ const char *tail = path_tail_with_sep((char *)fname);
size_t dirlen = (size_t)(tail - fname);
assert(tail >= fname && dirlen + 1 < sizeof(os_buf));
xstrlcpy(os_buf, fname, dirlen + 1);
@@ -1227,10 +1224,10 @@ bool os_shell_is_cmdexe(const char *sh)
}
if (striequal(sh, "$COMSPEC")) {
const char *comspec = os_getenv("COMSPEC");
- return striequal("cmd.exe", (char *)path_tail((char_u *)comspec));
+ return striequal("cmd.exe", path_tail(comspec));
}
if (striequal(sh, "cmd.exe") || striequal(sh, "cmd")) {
return true;
}
- return striequal("cmd.exe", (char *)path_tail((char_u *)sh));
+ return striequal("cmd.exe", path_tail(sh));
}
diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c
index 24c7678633..901a1bc5a6 100644
--- a/src/nvim/os/fs.c
+++ b/src/nvim/os/fs.c
@@ -40,8 +40,10 @@
bool did_try_to_free = false; \
uv_call_start: {} \
uv_fs_t req; \
+ fs_loop_lock(); \
ret = func(&fs_loop, &req, __VA_ARGS__); \
uv_fs_req_cleanup(&req); \
+ fs_loop_unlock(); \
if (ret == UV_ENOMEM && !did_try_to_free) { \
try_to_free_memory(); \
did_try_to_free = true; \
@@ -52,14 +54,27 @@ uv_call_start: {} \
// Many fs functions from libuv return that value on success.
static const int kLibuvSuccess = 0;
static uv_loop_t fs_loop;
-
+static uv_mutex_t fs_loop_mutex;
// Initialize the fs module
void fs_init(void)
{
uv_loop_init(&fs_loop);
+ uv_mutex_init_recursive(&fs_loop_mutex);
+}
+
+/// TODO(bfredl): some of these operations should
+/// be possible to do the private libuv loop of the
+/// thread, instead of contending the global fs loop
+void fs_loop_lock(void)
+{
+ uv_mutex_lock(&fs_loop_mutex);
}
+void fs_loop_unlock(void)
+{
+ uv_mutex_unlock(&fs_loop_mutex);
+}
/// Changes the current directory to `path`.
///
@@ -98,9 +113,12 @@ bool os_isrealdir(const char *name)
FUNC_ATTR_NONNULL_ALL
{
uv_fs_t request;
+ fs_loop_lock();
if (uv_fs_lstat(&fs_loop, &request, name, NULL) != kLibuvSuccess) {
+ fs_loop_unlock();
return false;
}
+ fs_loop_unlock();
if (S_ISLNK(request.statbuf.st_mode)) {
return false;
} else {
@@ -108,7 +126,7 @@ bool os_isrealdir(const char *name)
}
}
-/// Check if the given path is a directory or not.
+/// Check if the given path exists and is a directory.
///
/// @return `true` if `name` is a directory.
bool os_isdir(const char_u *name)
@@ -738,7 +756,9 @@ static int os_stat(const char *name, uv_stat_t *statbuf)
return UV_EINVAL;
}
uv_fs_t request;
+ fs_loop_lock();
int result = uv_fs_stat(&fs_loop, &request, name, NULL);
+ fs_loop_unlock();
if (result == kLibuvSuccess) {
*statbuf = request.statbuf;
}
@@ -771,6 +791,27 @@ int os_setperm(const char *const name, int perm)
return (r == kLibuvSuccess ? OK : FAIL);
}
+#ifdef UNIX
+/// Checks if the current user owns a file.
+///
+/// Uses both uv_fs_stat() and uv_fs_lstat() via os_fileinfo() and
+/// os_fileinfo_link() respectively for extra security.
+bool os_file_owned(const char *fname)
+ FUNC_ATTR_NONNULL_ALL
+{
+ uid_t uid = getuid();
+ FileInfo finfo;
+ bool file_owned = os_fileinfo(fname, &finfo) && finfo.stat.st_uid == uid;
+ bool link_owned = os_fileinfo_link(fname, &finfo) && finfo.stat.st_uid == uid;
+ return file_owned && link_owned;
+}
+#else
+bool os_file_owned(const char *fname)
+{
+ return true; // TODO(justinmk): Windows. #8244
+}
+#endif
+
/// Changes the owner and group of a file, like chown(2).
///
/// @return 0 on success, or libuv error code on failure.
@@ -894,7 +935,7 @@ int os_mkdir_recurse(const char *const dir, int32_t mode, char **const failed_di
const char *const real_end = e;
const char past_head_save = *past_head;
while (!os_isdir((char_u *)curdir)) {
- e = (char *)path_tail_with_sep((char_u *)curdir);
+ e = path_tail_with_sep(curdir);
if (e <= past_head) {
*past_head = NUL;
break;
@@ -935,9 +976,11 @@ int os_mkdtemp(const char *template, char *path)
FUNC_ATTR_NONNULL_ALL
{
uv_fs_t request;
+ fs_loop_lock();
int result = uv_fs_mkdtemp(&fs_loop, &request, template, NULL);
+ fs_loop_unlock();
if (result == kLibuvSuccess) {
- STRNCPY(path, request.path, TEMP_FILE_PATH_MAXLEN);
+ xstrlcpy(path, request.path, TEMP_FILE_PATH_MAXLEN);
}
uv_fs_req_cleanup(&request);
return result;
@@ -962,7 +1005,9 @@ int os_rmdir(const char *path)
bool os_scandir(Directory *dir, const char *path)
FUNC_ATTR_NONNULL_ALL
{
+ fs_loop_lock();
int r = uv_fs_scandir(&fs_loop, &dir->request, path, 0, NULL);
+ fs_loop_unlock();
if (r < 0) {
os_closedir(dir);
}
@@ -1023,7 +1068,9 @@ bool os_fileinfo_link(const char *path, FileInfo *file_info)
return false;
}
uv_fs_t request;
+ fs_loop_lock();
bool ok = uv_fs_lstat(&fs_loop, &request, path, NULL) == kLibuvSuccess;
+ fs_loop_unlock();
if (ok) {
file_info->stat = request.statbuf;
}
@@ -1041,6 +1088,7 @@ bool os_fileinfo_fd(int file_descriptor, FileInfo *file_info)
{
uv_fs_t request;
memset(file_info, 0, sizeof(*file_info));
+ fs_loop_lock();
bool ok = uv_fs_fstat(&fs_loop,
&request,
file_descriptor,
@@ -1049,6 +1097,7 @@ bool os_fileinfo_fd(int file_descriptor, FileInfo *file_info)
file_info->stat = request.statbuf;
}
uv_fs_req_cleanup(&request);
+ fs_loop_unlock();
return ok;
}
@@ -1165,6 +1214,7 @@ char *os_realpath(const char *name, char *buf)
FUNC_ATTR_NONNULL_ARG(1)
{
uv_fs_t request;
+ fs_loop_lock();
int result = uv_fs_realpath(&fs_loop, &request, name, NULL);
if (result == kLibuvSuccess) {
if (buf == NULL) {
@@ -1173,6 +1223,7 @@ char *os_realpath(const char *name, char *buf)
xstrlcpy(buf, request.ptr, MAXPATHL + 1);
}
uv_fs_req_cleanup(&request);
+ fs_loop_unlock();
return result == kLibuvSuccess ? buf : NULL;
}
@@ -1261,7 +1312,7 @@ shortcut_end:
return rfname;
}
-# define is_path_sep(c) ((c) == L'\\' || (c) == L'/')
+# define IS_PATH_SEP(c) ((c) == L'\\' || (c) == L'/')
/// Returns true if the path contains a reparse point (junction or symbolic
/// link). Otherwise false in returned.
bool os_is_reparse_point_include(const char *path)
@@ -1278,9 +1329,9 @@ bool os_is_reparse_point_include(const char *path)
}
p = utf16_path;
- if (isalpha(p[0]) && p[1] == L':' && is_path_sep(p[2])) {
+ if (isalpha(p[0]) && p[1] == L':' && IS_PATH_SEP(p[2])) {
p += 3;
- } else if (is_path_sep(p[0]) && is_path_sep(p[1])) {
+ } else if (IS_PATH_SEP(p[0]) && IS_PATH_SEP(p[1])) {
p += 2;
}
diff --git a/src/nvim/os/fs.h b/src/nvim/os/fs.h
new file mode 100644
index 0000000000..c68081da02
--- /dev/null
+++ b/src/nvim/os/fs.h
@@ -0,0 +1,10 @@
+#ifndef NVIM_OS_FS_H
+#define NVIM_OS_FS_H
+
+#include "nvim/os/fs_defs.h" // for uv_*
+#include "nvim/types.h" // for char_u
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "os/fs.h.generated.h"
+#endif
+#endif // NVIM_OS_FS_H
diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c
index 3790eba212..c47a891c18 100644
--- a/src/nvim/os/input.c
+++ b/src/nvim/os/input.c
@@ -13,12 +13,13 @@
#include "nvim/ex_cmds2.h"
#include "nvim/fileio.h"
#include "nvim/getchar.h"
-#include "nvim/keymap.h"
+#include "nvim/keycodes.h"
#include "nvim/main.h"
#include "nvim/mbyte.h"
#include "nvim/memory.h"
#include "nvim/msgpack_rpc/channel.h"
#include "nvim/os/input.h"
+#include "nvim/screen.h"
#include "nvim/state.h"
#include "nvim/ui.h"
#include "nvim/vim.h"
@@ -81,7 +82,7 @@ void input_stop(void)
static void cursorhold_event(void **argv)
{
- event_T event = State & INSERT ? EVENT_CURSORHOLDI : EVENT_CURSORHOLD;
+ event_T event = State & MODE_INSERT ? EVENT_CURSORHOLDI : EVENT_CURSORHOLD;
apply_autocmds(event, NULL, NULL, false, curbuf);
did_cursorhold = true;
}
@@ -98,7 +99,7 @@ static void create_cursorhold_event(bool events_enabled)
/// Low level input function
///
-/// wait until either the input buffer is non-empty or , if `events` is not NULL
+/// wait until either the input buffer is non-empty or, if `events` is not NULL
/// until `events` is non-empty.
int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *events)
{
@@ -106,6 +107,11 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *e
return (int)rbuffer_read(input_buffer, (char *)buf, (size_t)maxlen);
}
+ // No risk of a UI flood, so disable CTRL-C "interrupt" behavior if it's mapped.
+ if ((mapped_ctrl_c | curbuf->b_mapped_ctrl_c) & get_real_state()) {
+ ctrl_c_interrupts = false;
+ }
+
InbufPollResult result;
if (ms >= 0) {
if ((result = inbuf_poll(ms, events)) == kInputNone) {
@@ -127,6 +133,8 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *e
}
}
+ ctrl_c_interrupts = true;
+
// If input was put directly in typeahead buffer bail out here.
if (typebuf_changed(tb_change_cnt)) {
return 0;
@@ -171,15 +179,7 @@ void os_breakcheck(void)
return;
}
- int save_us = updating_screen;
- // We do not want screen_resize() to redraw here.
- // TODO(bfredl): we are already special casing redraw events, is this
- // hack still needed?
- updating_screen++;
-
loop_poll_events(&main_loop, 0);
-
- updating_screen = save_us;
}
#define BREAKCHECK_SKIP 1000
@@ -216,7 +216,6 @@ void veryfast_breakcheck(void)
}
}
-
/// Test whether a file descriptor refers to a terminal.
///
/// @param fd File descriptor.
@@ -234,13 +233,13 @@ size_t input_enqueue(String keys)
while (rbuffer_space(input_buffer) >= 19 && ptr < end) {
// A "<x>" form occupies at least 1 characters, and produces up
// to 19 characters (1 + 5 * 3 for the char and 3 for a modifier).
- // In the case of K_SPECIAL(0x80) or CSI(0x9B), 3 bytes are escaped and
- // needed, but since the keys are UTF-8, so the first byte cannot be
- // K_SPECIAL(0x80) or CSI(0x9B).
+ // In the case of K_SPECIAL(0x80), 3 bytes are escaped and needed,
+ // but since the keys are UTF-8, so the first byte cannot be
+ // K_SPECIAL(0x80).
uint8_t buf[19] = { 0 };
+ // Do not simplify the keys here. Simplification will be done later.
unsigned int new_size
- = trans_special((const uint8_t **)&ptr, (size_t)(end - ptr), buf, true,
- false);
+ = trans_special((const uint8_t **)&ptr, (size_t)(end - ptr), buf, FSK_KEYCODE, true, NULL);
if (new_size) {
new_size = handle_mouse_event(&ptr, buf, new_size);
@@ -263,12 +262,8 @@ size_t input_enqueue(String keys)
continue;
}
- // copy the character, escaping CSI and K_SPECIAL
- if ((uint8_t)*ptr == CSI) {
- rbuffer_write(input_buffer, (char *)&(uint8_t){ K_SPECIAL }, 1);
- rbuffer_write(input_buffer, (char *)&(uint8_t){ KS_EXTRA }, 1);
- rbuffer_write(input_buffer, (char *)&(uint8_t){ KE_CSI }, 1);
- } else if ((uint8_t)*ptr == K_SPECIAL) {
+ // copy the character, escaping K_SPECIAL
+ if ((uint8_t)(*ptr) == K_SPECIAL) {
rbuffer_write(input_buffer, (char *)&(uint8_t){ K_SPECIAL }, 1);
rbuffer_write(input_buffer, (char *)&(uint8_t){ KS_SPECIAL }, 1);
rbuffer_write(input_buffer, (char *)&(uint8_t){ KE_FILLER }, 1);
@@ -279,7 +274,7 @@ size_t input_enqueue(String keys)
}
size_t rv = (size_t)(ptr - keys.data);
- process_interrupts();
+ process_ctrl_c();
return rv;
}
@@ -292,8 +287,13 @@ static uint8_t check_multiclick(int code, int grid, int row, int col)
static int orig_mouse_row = 0;
static uint64_t orig_mouse_time = 0; // time of previous mouse click
- if (code == KE_LEFTRELEASE || code == KE_RIGHTRELEASE
- || code == KE_MIDDLERELEASE) {
+ if (code == KE_LEFTRELEASE
+ || code == KE_RIGHTRELEASE
+ || code == KE_MIDDLERELEASE
+ || code == KE_MOUSEDOWN
+ || code == KE_MOUSEUP
+ || code == KE_MOUSELEFT
+ || code == KE_MOUSERIGHT) {
return 0;
}
uint64_t mouse_time = os_hrtime(); // time of current mouse click (ns)
@@ -329,7 +329,6 @@ static uint8_t check_multiclick(int code, int grid, int row, int col)
return modifiers;
}
-
// Mouse event handling code(Extract row/col if available and detect multiple
// clicks)
static unsigned int handle_mouse_event(char **ptr, uint8_t *buf, unsigned int bufsize)
@@ -412,7 +411,7 @@ size_t input_enqueue_mouse(int code, uint8_t modifier, int grid, int row, int co
mouse_row = row;
mouse_col = col;
- size_t written = 3 + (size_t)(p-buf);
+ size_t written = 3 + (size_t)(p - buf);
rbuffer_write(input_buffer, (char *)buf, written);
return written;
}
@@ -479,15 +478,20 @@ static void input_read_cb(Stream *stream, RBuffer *buf, size_t c, void *data, bo
}
}
-static void process_interrupts(void)
+static void process_ctrl_c(void)
{
- if ((mapped_ctrl_c | curbuf->b_mapped_ctrl_c) & get_real_state()) {
+ if (!ctrl_c_interrupts) {
return;
}
size_t consume_count = 0;
RBUFFER_EACH_REVERSE(input_buffer, c, i) {
- if ((uint8_t)c == Ctrl_C) {
+ if ((uint8_t)c == Ctrl_C
+ || ((uint8_t)c == 'C' && i >= 3
+ && (uint8_t)(*rbuffer_get(input_buffer, i - 3)) == K_SPECIAL
+ && (uint8_t)(*rbuffer_get(input_buffer, i - 2)) == KS_MODIFIER
+ && (uint8_t)(*rbuffer_get(input_buffer, i - 1)) == MOD_MASK_CTRL)) {
+ *rbuffer_get(input_buffer, i) = Ctrl_C;
got_int = true;
consume_count = i;
break;
@@ -526,6 +530,7 @@ static bool input_ready(MultiQueue *events)
// Exit because of an input read error.
static void read_error_exit(void)
+ FUNC_ATTR_NORETURN
{
if (silent_mode) { // Normal way to exit for "nvim -es".
getout(0);
diff --git a/src/nvim/os/lang.c b/src/nvim/os/lang.c
index b63faacaae..28f43ff3af 100644
--- a/src/nvim/os/lang.c
+++ b/src/nvim/os/lang.c
@@ -3,9 +3,10 @@
#ifdef __APPLE__
# define Boolean CFBoolean // Avoid conflict with API's Boolean
-# include <CoreFoundation/CFLocale.h>
-# include <CoreFoundation/CFString.h>
+# define FileInfo CSFileInfo // Avoid conflict with API's Fileinfo
+# include <CoreServices/CoreServices.h>
# undef Boolean
+# undef FileInfo
#endif
#include "auto/config.h"
@@ -21,55 +22,24 @@ void lang_init(void)
{
#ifdef __APPLE__
if (os_getenv("LANG") == NULL) {
- const char *lang_region = NULL;
- CFTypeRef cf_lang_region = NULL;
-
- CFLocaleRef cf_locale = CFLocaleCopyCurrent();
- if (cf_locale) {
- cf_lang_region = CFLocaleGetValue(cf_locale, kCFLocaleIdentifier);
- CFRetain(cf_lang_region);
- lang_region = CFStringGetCStringPtr(cf_lang_region,
- kCFStringEncodingUTF8);
- CFRelease(cf_locale);
- } else {
- // Use the primary language defined in Preferences -> Language & Region
- CFArrayRef cf_langs = CFLocaleCopyPreferredLanguages();
- if (cf_langs && CFArrayGetCount(cf_langs) > 0) {
- cf_lang_region = CFArrayGetValueAtIndex(cf_langs, 0);
- CFRetain(cf_lang_region);
- CFRelease(cf_langs);
- lang_region = CFStringGetCStringPtr(cf_lang_region,
- kCFStringEncodingUTF8);
- } else {
- ELOG("$LANG is empty and your primary language cannot be inferred.");
- return;
- }
- }
-
char buf[50] = { 0 };
- bool set_lang;
- if (lang_region) {
- set_lang = true;
- xstrlcpy(buf, lang_region, sizeof(buf));
- } else {
- set_lang = CFStringGetCString(cf_lang_region, buf, 40,
- kCFStringEncodingUTF8);
- }
- if (set_lang) {
+
+ // $LANG is not set, either because it was unset or Nvim was started
+ // from the Dock. Query the system locale.
+ if (LocaleRefGetPartString(NULL,
+ kLocaleLanguageMask | kLocaleLanguageVariantMask |
+ kLocaleRegionMask | kLocaleRegionVariantMask,
+ sizeof(buf) - 10, buf) == noErr && *buf) {
if (strcasestr(buf, "utf-8") == NULL) {
xstrlcat(buf, ".UTF-8", sizeof(buf));
}
os_setenv("LANG", buf, true);
+ setlocale(LC_ALL, "");
+ // Make sure strtod() uses a decimal point, not a comma.
+ setlocale(LC_NUMERIC, "C");
+ } else {
+ ELOG("$LANG is empty and the macOS primary language cannot be inferred.");
}
- CFRelease(cf_lang_region);
-# ifdef HAVE_LOCALE_H
- setlocale(LC_ALL, "");
-
-# ifdef LC_NUMERIC
- // Make sure strtod() uses a decimal point, not a comma.
- setlocale(LC_NUMERIC, "C");
-# endif
-# endif
}
#endif
}
diff --git a/src/nvim/os/os.h b/src/nvim/os/os.h
index bff2936f8e..a7496130cc 100644
--- a/src/nvim/os/os.h
+++ b/src/nvim/os/os.h
@@ -16,4 +16,7 @@
# include "os/users.h.generated.h"
#endif
+#define ENV_LOGFILE "NVIM_LOG_FILE"
+#define ENV_NVIM "NVIM"
+
#endif // NVIM_OS_OS_H
diff --git a/src/nvim/os/os_defs.h b/src/nvim/os/os_defs.h
index dce4b0c187..a4361859ec 100644
--- a/src/nvim/os/os_defs.h
+++ b/src/nvim/os/os_defs.h
@@ -14,7 +14,7 @@
#endif
#if !defined(NAME_MAX) && defined(_XOPEN_NAME_MAX)
-#define NAME_MAX _XOPEN_NAME_MAX
+# define NAME_MAX _XOPEN_NAME_MAX
#endif
#define BASENAMELEN (NAME_MAX - 5)
diff --git a/src/nvim/os/os_win_console.c b/src/nvim/os/os_win_console.c
index 18e2e02b81..20b7f869f1 100644
--- a/src/nvim/os/os_win_console.c
+++ b/src/nvim/os/os_win_console.c
@@ -9,7 +9,6 @@
# include "os/os_win_console.c.generated.h"
#endif
-
int os_get_conin_fd(void)
{
const HANDLE conin_handle = CreateFile("CONIN$",
diff --git a/src/nvim/os/pty_process_unix.c b/src/nvim/os/pty_process_unix.c
index 3459646bad..c5d6af0ff6 100644
--- a/src/nvim/os/pty_process_unix.c
+++ b/src/nvim/os/pty_process_unix.c
@@ -16,11 +16,11 @@
#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
# include <util.h>
#elif defined(__sun)
-# include <sys/stream.h>
-# include <sys/syscall.h>
-# include <fcntl.h>
-# include <unistd.h>
-# include <signal.h>
+# include <fcntl.h>
+# include <signal.h>
+# include <sys/stream.h>
+# include <sys/syscall.h>
+# include <unistd.h>
#else
# include <pty.h>
#endif
@@ -49,10 +49,10 @@
// this header defines STR, just as nvim.h, but it is defined as ('S'<<8),
// to avoid #undef STR, #undef STR, #define STR ('S'<<8) just delay the
// inclusion of the header even though it gets include out of order.
-#include <sys/stropts.h>
+# include <sys/stropts.h>
-static int openpty(int *amaster, int *aslave, char *name,
- struct termios *termp, struct winsize *winp)
+static int openpty(int *amaster, int *aslave, char *name, struct termios *termp,
+ struct winsize *winp)
{
int slave = -1;
int master = open("/dev/ptmx", O_RDWR);
@@ -63,7 +63,7 @@ static int openpty(int *amaster, int *aslave, char *name,
// grantpt will invoke a setuid program to change permissions
// and might fail if SIGCHLD handler is set, temporarily reset
// while running
- void(*sig_saved)(int) = signal(SIGCHLD, SIG_DFL);
+ void (*sig_saved)(int) = signal(SIGCHLD, SIG_DFL);
int res = grantpt(master);
signal(SIGCHLD, sig_saved);
@@ -86,7 +86,7 @@ static int openpty(int *amaster, int *aslave, char *name,
ioctl(slave, I_PUSH, "ptem");
// ldterm provides most of the termio terminal interface
ioctl(slave, I_PUSH, "ldterm");
- // ttcompat compatability with older terminal ioctls
+ // ttcompat compatibility with older terminal ioctls
ioctl(slave, I_PUSH, "ttcompat");
if (termp) {
@@ -129,8 +129,7 @@ static int login_tty(int fd)
return 0;
}
-static pid_t forkpty(int *amaster, char *name,
- struct termios *termp, struct winsize *winp)
+static pid_t forkpty(int *amaster, char *name, struct termios *termp, struct winsize *winp)
{
int master, slave;
if (openpty(&master, &slave, name, termp, winp) == -1) {
@@ -164,10 +163,15 @@ static struct termios termios_default;
/// @param tty_fd TTY file descriptor, or -1 if not in a terminal.
void pty_process_save_termios(int tty_fd)
{
- DLOG("tty_fd=%d", tty_fd);
- if (tty_fd == -1 || tcgetattr(tty_fd, &termios_default) != 0) {
+ if (tty_fd == -1) {
return;
}
+ int rv = tcgetattr(tty_fd, &termios_default);
+ if (rv != 0) {
+ ELOG("tcgetattr failed (tty_fd=%d): %s", tty_fd, strerror(errno));
+ } else {
+ DLOG("tty_fd=%d", tty_fd);
+ }
}
/// @returns zero on success, or negative error code
diff --git a/src/nvim/os/pty_process_win.c b/src/nvim/os/pty_process_win.c
index f78f3e66f5..6233a90638 100644
--- a/src/nvim/os/pty_process_win.c
+++ b/src/nvim/os/pty_process_win.c
@@ -4,7 +4,6 @@
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
-#include <winpty_constants.h>
#include "nvim/ascii.h"
#include "nvim/mbyte.h" // for utf8_to_utf16, utf16_to_utf8
@@ -23,11 +22,7 @@ static void CALLBACK pty_process_finish1(void *context, BOOLEAN unused)
PtyProcess *ptyproc = (PtyProcess *)context;
Process *proc = (Process *)ptyproc;
- if (ptyproc->type == kConpty
- && ptyproc->object.conpty != NULL) {
- os_conpty_free(ptyproc->object.conpty);
- ptyproc->object.conpty = NULL;
- }
+ os_conpty_free(ptyproc->conpty);
uv_timer_init(&proc->loop->uv, &ptyproc->wait_eof_timer);
ptyproc->wait_eof_timer.data = (void *)ptyproc;
uv_timer_start(&ptyproc->wait_eof_timer, wait_eof_timer_cb, 200, 200);
@@ -39,10 +34,6 @@ int pty_process_spawn(PtyProcess *ptyproc)
{
Process *proc = (Process *)ptyproc;
int status = 0;
- winpty_error_ptr_t err = NULL;
- winpty_config_t *cfg = NULL;
- winpty_spawn_config_t *spawncfg = NULL;
- winpty_t *winpty_object = NULL;
conpty_t *conpty_object = NULL;
char *in_name = NULL;
char *out_name = NULL;
@@ -56,39 +47,11 @@ int pty_process_spawn(PtyProcess *ptyproc)
assert(proc->err.closed);
- if (os_has_conpty_working()) {
- if ((conpty_object =
- os_conpty_init(&in_name, &out_name,
- ptyproc->width, ptyproc->height)) != NULL) {
- ptyproc->type = kConpty;
- }
- }
-
- if (ptyproc->type == kWinpty) {
- cfg = winpty_config_new(WINPTY_FLAG_ALLOW_CURPROC_DESKTOP_CREATION, &err);
- if (cfg == NULL) {
- emsg = "winpty_config_new failed";
- goto cleanup;
- }
-
- winpty_config_set_initial_size(cfg, ptyproc->width, ptyproc->height);
- winpty_object = winpty_open(cfg, &err);
- if (winpty_object == NULL) {
- emsg = "winpty_open failed";
- goto cleanup;
- }
-
- status = utf16_to_utf8(winpty_conin_name(winpty_object), -1, &in_name);
- if (status != 0) {
- emsg = "utf16_to_utf8(winpty_conin_name) failed";
- goto cleanup;
- }
-
- status = utf16_to_utf8(winpty_conout_name(winpty_object), -1, &out_name);
- if (status != 0) {
- emsg = "utf16_to_utf8(winpty_conout_name) failed";
- goto cleanup;
- }
+ if (!os_has_conpty_working() || (conpty_object = os_conpty_init(&in_name,
+ &out_name, ptyproc->width,
+ ptyproc->height)) == NULL) {
+ status = UV_ENOSYS;
+ goto cleanup;
}
if (!proc->in.closed) {
@@ -131,44 +94,15 @@ int pty_process_spawn(PtyProcess *ptyproc)
goto cleanup;
}
- if (ptyproc->type == kConpty) {
- if (!os_conpty_spawn(conpty_object,
- &process_handle,
- NULL,
- cmd_line,
- cwd,
- env)) {
- emsg = "os_conpty_spawn failed";
- status = (int)GetLastError();
- goto cleanup;
- }
- } else {
- spawncfg = winpty_spawn_config_new(WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN,
- NULL, // Optional application name
- cmd_line,
- cwd,
- env,
- &err);
- if (spawncfg == NULL) {
- emsg = "winpty_spawn_config_new failed";
- goto cleanup;
- }
-
- DWORD win_err = 0;
- if (!winpty_spawn(winpty_object,
- spawncfg,
- &process_handle,
- NULL, // Optional thread handle
- &win_err,
- &err)) {
- if (win_err) {
- status = (int)win_err;
- emsg = "failed to spawn process";
- } else {
- emsg = "winpty_spawn failed";
- }
- goto cleanup;
- }
+ if (!os_conpty_spawn(conpty_object,
+ &process_handle,
+ NULL,
+ cmd_line,
+ cwd,
+ env)) {
+ emsg = "os_conpty_spawn failed";
+ status = (int)GetLastError();
+ goto cleanup;
}
proc->pid = (int)GetProcessId(process_handle);
@@ -187,11 +121,8 @@ int pty_process_spawn(PtyProcess *ptyproc)
uv_run(&proc->loop->uv, UV_RUN_ONCE);
}
- (ptyproc->type == kConpty) ?
- (void *)(ptyproc->object.conpty = conpty_object) :
- (void *)(ptyproc->object.winpty = winpty_object);
+ ptyproc->conpty = conpty_object;
ptyproc->process_handle = process_handle;
- winpty_object = NULL;
conpty_object = NULL;
process_handle = NULL;
@@ -201,16 +132,7 @@ cleanup:
ELOG("pty_process_spawn(%s): %s: error code: %d",
proc->argv[0], emsg, status);
status = os_translate_sys_error(status);
- } else if (err != NULL) {
- status = (int)winpty_error_code(err);
- ELOG("pty_process_spawn(%s): %s: error code: %d",
- proc->argv[0], emsg, status);
- status = translate_winpty_error(status);
}
- winpty_error_free(err);
- winpty_config_free(cfg);
- winpty_spawn_config_free(spawncfg);
- winpty_free(winpty_object);
os_conpty_free(conpty_object);
xfree(in_name);
xfree(out_name);
@@ -233,12 +155,7 @@ const char *pty_process_tty_name(PtyProcess *ptyproc)
void pty_process_resize(PtyProcess *ptyproc, uint16_t width, uint16_t height)
FUNC_ATTR_NONNULL_ALL
{
- if (ptyproc->type == kConpty
- && ptyproc->object.conpty != NULL) {
- os_conpty_set_size(ptyproc->object.conpty, width, height);
- } else if (ptyproc->object.winpty != NULL) {
- winpty_set_size(ptyproc->object.winpty, width, height, NULL);
- }
+ os_conpty_set_size(ptyproc->conpty, width, height);
}
void pty_process_close(PtyProcess *ptyproc)
@@ -255,18 +172,11 @@ void pty_process_close(PtyProcess *ptyproc)
void pty_process_close_master(PtyProcess *ptyproc)
FUNC_ATTR_NONNULL_ALL
-{
- if (ptyproc->type == kWinpty
- && ptyproc->object.winpty != NULL) {
- winpty_free(ptyproc->object.winpty);
- ptyproc->object.winpty = NULL;
- }
-}
+{}
void pty_process_teardown(Loop *loop)
FUNC_ATTR_NONNULL_ALL
-{
-}
+{}
static void pty_process_connect_cb(uv_connect_t *req, int status)
FUNC_ATTR_NONNULL_ALL
@@ -281,7 +191,7 @@ static void wait_eof_timer_cb(uv_timer_t *wait_eof_timer)
PtyProcess *ptyproc = wait_eof_timer->data;
Process *proc = (Process *)ptyproc;
- if (proc->out.closed || !uv_is_readable(proc->out.uvstream)) {
+ if (proc->out.closed || proc->out.did_eof || !uv_is_readable(proc->out.uvstream)) {
uv_timer_stop(&ptyproc->wait_eof_timer);
pty_process_finish2(ptyproc);
}
@@ -308,7 +218,7 @@ static void pty_process_finish2(PtyProcess *ptyproc)
/// Build the command line to pass to CreateProcessW.
///
/// @param[in] argv Array with string arguments.
-/// @param[out] cmd_line Location where saved builded cmd line.
+/// @param[out] cmd_line Location where saved built cmd line.
///
/// @returns zero on success, or error code of MultiByteToWideChar function.
///
@@ -435,40 +345,6 @@ static void quote_cmd_arg(char *dest, size_t dest_remaining, const char *src)
}
}
-/// Translate winpty error code to libuv error.
-///
-/// @param[in] winpty_errno Winpty error code returned by winpty_error_code
-/// function.
-///
-/// @returns Error code of libuv error.
-int translate_winpty_error(int winpty_errno)
-{
- if (winpty_errno <= 0) {
- return winpty_errno; // If < 0 then it's already a libuv error.
- }
-
- switch (winpty_errno) {
- case WINPTY_ERROR_OUT_OF_MEMORY:
- return UV_ENOMEM;
- case WINPTY_ERROR_SPAWN_CREATE_PROCESS_FAILED:
- return UV_EAI_FAIL;
- case WINPTY_ERROR_LOST_CONNECTION:
- return UV_ENOTCONN;
- case WINPTY_ERROR_AGENT_EXE_MISSING:
- return UV_ENOENT;
- case WINPTY_ERROR_UNSPECIFIED:
- return UV_UNKNOWN;
- case WINPTY_ERROR_AGENT_DIED:
- return UV_ESRCH;
- case WINPTY_ERROR_AGENT_TIMEOUT:
- return UV_ETIMEDOUT;
- case WINPTY_ERROR_AGENT_CREATION_FAILED:
- return UV_EAI_FAIL;
- default:
- return UV_UNKNOWN;
- }
-}
-
typedef struct EnvNode {
wchar_t *str;
size_t len;
@@ -485,7 +361,7 @@ static int build_env_block(dict_T *denv, wchar_t **env_block)
{
const size_t denv_size = (size_t)tv_dict_len(denv);
size_t env_block_len = 0;
- int rc;
+ int rc = 0;
char **env = tv_dict_to_env(denv);
QUEUE *q;
diff --git a/src/nvim/os/pty_process_win.h b/src/nvim/os/pty_process_win.h
index d1737fd63a..ed7d765ac7 100644
--- a/src/nvim/os/pty_process_win.h
+++ b/src/nvim/os/pty_process_win.h
@@ -2,25 +2,15 @@
#define NVIM_OS_PTY_PROCESS_WIN_H
#include <uv.h>
-#include <winpty.h>
#include "nvim/event/process.h"
#include "nvim/lib/queue.h"
#include "nvim/os/pty_conpty_win.h"
-typedef enum {
- kWinpty,
- kConpty,
-} PtyType;
-
typedef struct pty_process {
Process process;
uint16_t width, height;
- union {
- winpty_t *winpty;
- conpty_t *conpty;
- } object;
- PtyType type;
+ conpty_t *conpty;
HANDLE finish_wait;
HANDLE process_handle;
uv_timer_t wait_eof_timer;
@@ -38,8 +28,7 @@ static inline PtyProcess pty_process_init(Loop *loop, void *data)
rv.process = process_init(loop, kProcessTypePty, data);
rv.width = 80;
rv.height = 24;
- rv.object.winpty = NULL;
- rv.type = kWinpty;
+ rv.conpty = NULL;
rv.finish_wait = NULL;
rv.process_handle = NULL;
return rv;
diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c
index e618b2788b..9283ea2e42 100644
--- a/src/nvim/os/shell.c
+++ b/src/nvim/os/shell.c
@@ -9,10 +9,10 @@
#include "nvim/ascii.h"
#include "nvim/charset.h"
+#include "nvim/eval.h"
#include "nvim/event/libuv_process.h"
#include "nvim/event/loop.h"
#include "nvim/event/rstream.h"
-#include "nvim/eval.h"
#include "nvim/ex_cmds.h"
#include "nvim/fileio.h"
#include "nvim/lib/kvec.h"
@@ -27,8 +27,8 @@
#include "nvim/path.h"
#include "nvim/screen.h"
#include "nvim/strings.h"
-#include "nvim/types.h"
#include "nvim/tag.h"
+#include "nvim/types.h"
#include "nvim/ui.h"
#include "nvim/vim.h"
@@ -36,7 +36,7 @@
#define NS_1_SECOND 1000000000U // 1 second, in nanoseconds
#define OUT_DATA_THRESHOLD 1024 * 10U // 10KB, "a few screenfuls" of data.
-#define SHELL_SPECIAL (char_u *)"\t \"&'$;<>()\\|"
+#define SHELL_SPECIAL "\t \"&'$;<>()\\|"
typedef struct {
char *data;
@@ -73,7 +73,7 @@ static bool have_wildcard(int num, char_u **file)
static bool have_dollars(int num, char_u **file)
{
for (int i = 0; i < num; i++) {
- if (vim_strchr(file[i], '$') != NULL) {
+ if (vim_strchr((char *)file[i], '$') != NULL) {
return true;
}
}
@@ -151,7 +151,7 @@ int os_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file
// Don't allow the use of backticks in secure.
if (secure) {
for (i = 0; i < num_pat; i++) {
- if (vim_strchr(pat[i], '`') != NULL
+ if (vim_strchr((char *)pat[i], '`') != NULL
&& (check_secure())) {
return FAIL;
}
@@ -188,7 +188,7 @@ int os_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file
}
}
if (shell_style == STYLE_ECHO
- && strstr((char *)path_tail(p_sh), "sh") != NULL) {
+ && strstr(path_tail((char *)p_sh), "sh") != NULL) {
shell_style = STYLE_VIMGLOB;
}
@@ -405,7 +405,7 @@ int os_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file
while (*p != ' ' && *p != '\n') {
p++;
}
- p = skipwhite(p); // skip to next entry
+ p = (char_u *)skipwhite((char *)p); // skip to next entry
}
// file names are separated with NL
} else if (shell_style == STYLE_BT || shell_style == STYLE_VIMGLOB) {
@@ -418,7 +418,7 @@ int os_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file
if (*p != NUL) {
p++;
}
- p = skipwhite(p); // skip leading white space
+ p = (char_u *)skipwhite((char *)p); // skip leading white space
}
// file names are separated with NUL
} else {
@@ -483,7 +483,7 @@ int os_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file
*p = NUL;
} else {
*p++ = NUL;
- p = skipwhite(p); // skip to next entry
+ p = (char_u *)skipwhite((char *)p); // skip to next entry
}
} else { // NUL separates
while (*p && p < buffer + len) { // skip entry
@@ -644,7 +644,7 @@ int os_call_shell(char_u *cmd, ShellOpts opts, char_u *extra_args)
if (opts & (kShellOptHideMess | kShellOptExpand)) {
forward_output = false;
} else {
- State = EXTERNCMD;
+ State = MODE_EXTERNCMD;
if (opts & kShellOptWrite) {
read_input(&input);
@@ -746,7 +746,7 @@ char_u *get_cmd_output(char_u *cmd, char_u *infile, ShellOpts flags, size_t *ret
}
// Add the redirection stuff
- char_u *command = make_filter_cmd(cmd, infile, tempname);
+ char_u *command = (char_u *)make_filter_cmd((char *)cmd, (char *)infile, (char *)tempname);
// Call the shell to execute the command (errors are ignored).
// Don't check timestamps here.
@@ -854,9 +854,9 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu
// Failed, probably 'shell' is not executable.
if (!silent) {
msg_puts(_("\nshell failed to start: "));
- msg_outtrans((char_u *)os_strerror(status));
+ msg_outtrans((char *)os_strerror(status));
msg_puts(": ");
- msg_outtrans((char_u *)prog);
+ msg_outtrans(prog);
msg_putchar('\n');
}
multiqueue_free(events);
@@ -1099,8 +1099,8 @@ static void out_data_append_to_screen(char *output, size_t *count, bool eof)
// incomplete UTF-8 sequence that could be composing with the last
// complete sequence.
// This will be corrected when we switch to vterm based implementation
- int i = *p ? utfc_ptr2len_len((char_u *)p, (int)(end-p)) : 1;
- if (!eof && i == 1 && utf8len_tab_zero[*(uint8_t *)p] > (end-p)) {
+ int i = *p ? utfc_ptr2len_len((char_u *)p, (int)(end - p)) : 1;
+ if (!eof && i == 1 && utf8len_tab_zero[*(uint8_t *)p] > (end - p)) {
*count = (size_t)(p - output);
goto end;
}
@@ -1158,7 +1158,7 @@ static size_t tokenize(const char_u *const str, char **const argv)
}
argc++;
- p = (const char *)skipwhite((char_u *)(p + len));
+ p = (const char *)skipwhite((p + len));
}
return argc;
@@ -1213,7 +1213,7 @@ static void read_input(DynamicBuffer *buf)
dynamic_buffer_ensure(buf, buf->len + len);
buf->data[buf->len++] = NUL;
} else {
- char_u *s = vim_strchr(lp + written, NL);
+ char_u *s = (char_u *)vim_strchr((char *)lp + written, NL);
len = s == NULL ? l : (size_t)(s - (lp + written));
dynamic_buffer_ensure(buf, buf->len + len);
memcpy(buf->data + buf->len, lp + written, len);
@@ -1229,7 +1229,7 @@ static void read_input(DynamicBuffer *buf)
dynamic_buffer_ensure(buf, buf->len + 1);
buf->data[buf->len++] = NL;
}
- ++lnum;
+ lnum++;
if (lnum > curbuf->b_op_end.lnum) {
break;
}
@@ -1253,7 +1253,7 @@ static size_t write_output(char *output, size_t remaining, bool eof)
if (output[off] == NL) {
// Insert the line
output[off] = NUL;
- ml_append(curwin->w_cursor.lnum++, (char_u *)output, (int)off + 1,
+ ml_append(curwin->w_cursor.lnum++, output, (int)off + 1,
false);
size_t skip = off + 1;
output += skip;
@@ -1272,7 +1272,7 @@ static size_t write_output(char *output, size_t remaining, bool eof)
if (eof) {
if (remaining) {
// append unfinished line
- ml_append(curwin->w_cursor.lnum++, (char_u *)output, 0, false);
+ ml_append(curwin->w_cursor.lnum++, output, 0, false);
// remember that the NL was missing
curbuf->b_no_eol_lnum = curwin->w_cursor.lnum;
output += remaining;
@@ -1331,4 +1331,3 @@ static char *shell_xescape_xquote(const char *cmd)
return ncmd;
}
-
diff --git a/src/nvim/os/signal.c b/src/nvim/os/signal.c
index a8bf68a1a2..581f025a0f 100644
--- a/src/nvim/os/signal.c
+++ b/src/nvim/os/signal.c
@@ -21,7 +21,7 @@
#include "nvim/os/signal.h"
#include "nvim/vim.h"
-static SignalWatcher spipe, shup, squit, sterm, susr1;
+static SignalWatcher spipe, shup, squit, sterm, susr1, swinch;
#ifdef SIGPWR
static SignalWatcher spwr;
#endif
@@ -54,6 +54,9 @@ void signal_init(void)
#ifdef SIGUSR1
signal_watcher_init(&main_loop, &susr1, NULL);
#endif
+#ifdef SIGWINCH
+ signal_watcher_init(&main_loop, &swinch, NULL);
+#endif
signal_start();
}
@@ -70,6 +73,9 @@ void signal_teardown(void)
#ifdef SIGUSR1
signal_watcher_close(&susr1, NULL);
#endif
+#ifdef SIGWINCH
+ signal_watcher_close(&swinch, NULL);
+#endif
}
void signal_start(void)
@@ -88,6 +94,9 @@ void signal_start(void)
#ifdef SIGUSR1
signal_watcher_start(&susr1, on_signal, SIGUSR1);
#endif
+#ifdef SIGWINCH
+ signal_watcher_start(&swinch, on_signal, SIGWINCH);
+#endif
}
void signal_stop(void)
@@ -106,6 +115,9 @@ void signal_stop(void)
#ifdef SIGUSR1
signal_watcher_stop(&susr1);
#endif
+#ifdef SIGWINCH
+ signal_watcher_stop(&swinch);
+#endif
}
void signal_reject_deadly(void)
@@ -141,6 +153,10 @@ static char *signal_name(int signum)
case SIGUSR1:
return "SIGUSR1";
#endif
+#ifdef SIGWINCH
+ case SIGWINCH:
+ return "SIGWINCH";
+#endif
default:
return "Unknown";
}
@@ -149,15 +165,15 @@ static char *signal_name(int signum)
// This function handles deadly signals.
// It tries to preserve any swap files and exit properly.
// (partly from Elvis).
-// NOTE: Avoid unsafe functions, such as allocating memory, they can result in
-// a deadlock.
+// NOTE: this is scheduled on the event loop, not called directly from a signal handler.
static void deadly_signal(int signum)
+ FUNC_ATTR_NORETURN
{
// Set the v:dying variable.
set_vim_var_nr(VV_DYING, 1);
v_dying = 1;
- WLOG("got signal %d (%s)", signum, signal_name(signum));
+ ILOG("got signal %d (%s)", signum, signal_name(signum));
snprintf((char *)IObuff, sizeof(IObuff), "Vim: Caught deadly signal '%s'\r\n",
signal_name(signum));
@@ -193,8 +209,12 @@ static void on_signal(SignalWatcher *handle, int signum, void *data)
break;
#ifdef SIGUSR1
case SIGUSR1:
- apply_autocmds(EVENT_SIGNAL, (char_u *)"SIGUSR1", curbuf->b_fname, true,
- curbuf);
+ apply_autocmds(EVENT_SIGNAL, "SIGUSR1", curbuf->b_fname, true, curbuf);
+ break;
+#endif
+#ifdef SIGWINCH
+ case SIGWINCH:
+ apply_autocmds(EVENT_SIGNAL, "SIGWINCH", curbuf->b_fname, true, curbuf);
break;
#endif
default:
diff --git a/src/nvim/os/stdpaths.c b/src/nvim/os/stdpaths.c
index 5b824d23f4..59d315d44c 100644
--- a/src/nvim/os/stdpaths.c
+++ b/src/nvim/os/stdpaths.c
@@ -4,6 +4,7 @@
#include <stdbool.h>
#include "nvim/ascii.h"
+#include "nvim/fileio.h"
#include "nvim/memory.h"
#include "nvim/os/os.h"
#include "nvim/os/stdpaths_defs.h"
@@ -14,6 +15,7 @@ static const char *xdg_env_vars[] = {
[kXDGConfigHome] = "XDG_CONFIG_HOME",
[kXDGDataHome] = "XDG_DATA_HOME",
[kXDGCacheHome] = "XDG_CACHE_HOME",
+ [kXDGStateHome] = "XDG_STATE_HOME",
[kXDGRuntimeDir] = "XDG_RUNTIME_DIR",
[kXDGConfigDirs] = "XDG_CONFIG_DIRS",
[kXDGDataDirs] = "XDG_DATA_DIRS",
@@ -24,7 +26,8 @@ static const char *const xdg_defaults_env_vars[] = {
[kXDGConfigHome] = "LOCALAPPDATA",
[kXDGDataHome] = "LOCALAPPDATA",
[kXDGCacheHome] = "TEMP",
- [kXDGRuntimeDir] = NULL,
+ [kXDGStateHome] = "LOCALAPPDATA",
+ [kXDGRuntimeDir] = NULL, // Decided by vim_mktempdir().
[kXDGConfigDirs] = NULL,
[kXDGDataDirs] = NULL,
};
@@ -38,14 +41,16 @@ static const char *const xdg_defaults[] = {
[kXDGConfigHome] = "~\\AppData\\Local",
[kXDGDataHome] = "~\\AppData\\Local",
[kXDGCacheHome] = "~\\AppData\\Local\\Temp",
- [kXDGRuntimeDir] = NULL,
+ [kXDGStateHome] = "~\\AppData\\Local",
+ [kXDGRuntimeDir] = NULL, // Decided by vim_mktempdir().
[kXDGConfigDirs] = NULL,
[kXDGDataDirs] = NULL,
#else
[kXDGConfigHome] = "~/.config",
[kXDGDataHome] = "~/.local/share",
[kXDGCacheHome] = "~/.cache",
- [kXDGRuntimeDir] = NULL,
+ [kXDGStateHome] = "~/.local/state",
+ [kXDGRuntimeDir] = NULL, // Decided by vim_mktempdir().
[kXDGConfigDirs] = "/etc/xdg/",
[kXDGDataDirs] = "/usr/local/share/:/usr/share/",
#endif
@@ -78,7 +83,12 @@ char *stdpaths_get_xdg_var(const XDGVarType idx)
if (env_val != NULL) {
ret = xstrdup(env_val);
} else if (fallback) {
- ret = (char *)expand_env_save((char_u *)fallback);
+ ret = expand_env_save((char *)fallback);
+ } else if (idx == kXDGRuntimeDir) {
+ // Special-case: stdpath('run') is defined at startup.
+ ret = vim_gettempdir();
+ size_t len = strlen(ret);
+ ret = xstrndup(ret, len >= 2 ? len - 1 : 0); // Trim trailing slash.
}
return ret;
@@ -99,11 +109,16 @@ char *get_xdg_home(const XDGVarType idx)
if (dir) {
#if defined(WIN32)
dir = concat_fnames_realloc(dir,
- (idx == kXDGDataHome ? "nvim-data" : "nvim"),
+ ((idx == kXDGDataHome
+ || idx == kXDGStateHome) ? "nvim-data" : "nvim"),
true);
#else
dir = concat_fnames_realloc(dir, "nvim", true);
#endif
+
+#ifdef BACKSLASH_IN_FILENAME
+ slash_adjust((char_u *)dir);
+#endif
}
return dir;
}
@@ -133,15 +148,26 @@ char *stdpaths_user_conf_subpath(const char *fname)
/// Return subpath of $XDG_DATA_HOME
///
/// @param[in] fname New component of the path.
+///
+/// @return [allocated] `$XDG_DATA_HOME/nvim/{fname}`
+char *stdpaths_user_data_subpath(const char *fname)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
+{
+ return concat_fnames_realloc(get_xdg_home(kXDGDataHome), fname, true);
+}
+
+/// Return subpath of $XDG_STATE_HOME
+///
+/// @param[in] fname New component of the path.
/// @param[in] trailing_pathseps Amount of trailing path separators to add.
/// @param[in] escape_commas If true, all commas will be escaped.
///
-/// @return [allocated] `$XDG_DATA_HOME/nvim/{fname}`.
-char *stdpaths_user_data_subpath(const char *fname, const size_t trailing_pathseps,
- const bool escape_commas)
+/// @return [allocated] `$XDG_STATE_HOME/nvim/{fname}`.
+char *stdpaths_user_state_subpath(const char *fname, const size_t trailing_pathseps,
+ const bool escape_commas)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
{
- char *ret = concat_fnames_realloc(get_xdg_home(kXDGDataHome), fname, true);
+ char *ret = concat_fnames_realloc(get_xdg_home(kXDGStateHome), fname, true);
const size_t len = strlen(ret);
const size_t numcommas = (escape_commas ? memcnt(ret, ',', len) : 0);
if (numcommas || trailing_pathseps) {
diff --git a/src/nvim/os/stdpaths_defs.h b/src/nvim/os/stdpaths_defs.h
index 44c30df373..f94c511fe7 100644
--- a/src/nvim/os/stdpaths_defs.h
+++ b/src/nvim/os/stdpaths_defs.h
@@ -7,6 +7,7 @@ typedef enum {
kXDGConfigHome, ///< XDG_CONFIG_HOME
kXDGDataHome, ///< XDG_DATA_HOME
kXDGCacheHome, ///< XDG_CACHE_HOME
+ kXDGStateHome, ///< XDG_STATE_HOME
kXDGRuntimeDir, ///< XDG_RUNTIME_DIR
kXDGConfigDirs, ///< XDG_CONFIG_DIRS
kXDGDataDirs, ///< XDG_DATA_DIRS
diff --git a/src/nvim/os/time.c b/src/nvim/os/time.c
index d9f4fe9e37..396bf6986a 100644
--- a/src/nvim/os/time.c
+++ b/src/nvim/os/time.c
@@ -15,7 +15,6 @@
static uv_mutex_t delay_mutex;
static uv_cond_t delay_cond;
-
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "os/time.c.generated.h"
#endif
diff --git a/src/nvim/os/users.c b/src/nvim/os/users.c
index e0ce3fec31..bd34e917b2 100644
--- a/src/nvim/os/users.c
+++ b/src/nvim/os/users.c
@@ -30,7 +30,7 @@ static void add_user(garray_T *users, char *user, bool need_copy)
if (user_copy == NULL || *user_copy == NUL) {
if (need_copy) {
- xfree(user);
+ xfree(user_copy);
}
return;
}
@@ -112,9 +112,13 @@ int os_get_usernames(garray_T *users)
return OK;
}
-// Insert user name in s[len].
-// Return OK if a name found.
-int os_get_user_name(char *s, size_t len)
+/// Gets the username that owns the current Nvim process.
+///
+/// @param s[out] Username.
+/// @param len Length of `s`.
+///
+/// @return OK if a name found.
+int os_get_username(char *s, size_t len)
{
#ifdef UNIX
return os_get_uname((uv_uid_t)getuid(), s, len);
@@ -124,9 +128,13 @@ int os_get_user_name(char *s, size_t len)
#endif
}
-// Insert user name for "uid" in s[len].
-// Return OK if a name found.
-// If the name is not found, write the uid into s[len] and return FAIL.
+/// Gets the username associated with `uid`.
+///
+/// @param uid User id.
+/// @param s[out] Username, or `uid` on failure.
+/// @param len Length of `s`.
+///
+/// @return OK if a username was found, else FAIL.
int os_get_uname(uv_uid_t uid, char *s, size_t len)
{
#if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
@@ -142,10 +150,10 @@ int os_get_uname(uv_uid_t uid, char *s, size_t len)
return FAIL; // a number is not a name
}
-// Returns the user directory for the given username.
-// The caller has to free() the returned string.
-// If the username is not found, NULL is returned.
-char *os_get_user_directory(const char *name)
+/// Gets the user directory for the given username, or NULL on failure.
+///
+/// Caller must free() the returned string.
+char *os_get_userdir(const char *name)
{
#if defined(HAVE_GETPWNAM) && defined(HAVE_PWD_H)
if (name == NULL || *name == NUL) {
@@ -160,7 +168,6 @@ char *os_get_user_directory(const char *name)
return NULL;
}
-
#if defined(EXITFREE)
void free_users(void)
@@ -187,11 +194,11 @@ static void init_users(void)
}
/// Given to ExpandGeneric() to obtain an user names.
-char_u *get_users(expand_T *xp, int idx)
+char *get_users(expand_T *xp, int idx)
{
init_users();
if (idx < ga_users.ga_len) {
- return ((char_u **)ga_users.ga_data)[idx];
+ return ((char **)ga_users.ga_data)[idx];
}
return NULL;
}
diff --git a/src/nvim/os/win_defs.h b/src/nvim/os/win_defs.h
index efef77be7b..1ae86d6bbe 100644
--- a/src/nvim/os/win_defs.h
+++ b/src/nvim/os/win_defs.h
@@ -36,7 +36,7 @@
// Windows defines a RGB macro that produces 0x00bbggrr color values for use
// with GDI. Our macro is different, and we don't use GDI.
// Duplicated from macros.h to avoid include-order sensitivity.
-#define RGB_(r, g, b) ((r << 16) | (g << 8) | b)
+#define RGB_(r, g, b) (((r) << 16) | ((g) << 8) | (b))
#ifdef _MSC_VER
# ifndef inline