aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/os
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/os')
-rw-r--r--src/nvim/os/input.c20
-rw-r--r--src/nvim/os/pty_process_unix.c39
-rw-r--r--src/nvim/os/pty_process_unix.h1
-rw-r--r--src/nvim/os/pty_process_win.c98
-rw-r--r--src/nvim/os/pty_process_win.h1
-rw-r--r--src/nvim/os/shell.c8
-rw-r--r--src/nvim/os/time.c19
7 files changed, 140 insertions, 46 deletions
diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c
index 9d6518841a..eca245650a 100644
--- a/src/nvim/os/input.c
+++ b/src/nvim/os/input.c
@@ -159,16 +159,28 @@ bool os_char_avail(void)
return inbuf_poll(0, NULL) == kInputAvail;
}
-// Check for CTRL-C typed by reading all available characters.
+/// Poll for fast events. `got_int` will be set to `true` if CTRL-C was typed.
+///
+/// This invokes a full libuv loop iteration which can be quite costly.
+/// Prefer `line_breakcheck()` if called in a busy inner loop.
+///
+/// Caller must at least check `got_int` before calling this function again.
+/// checking for other low-level input state like `input_available()` might
+/// also be relevant (i e to throttle idle processing when user input is
+/// available)
void os_breakcheck(void)
{
+ if (got_int) {
+ 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++;
- if (!got_int) {
- loop_poll_events(&main_loop, 0);
- }
+ loop_poll_events(&main_loop, 0);
updating_screen = save_us;
}
diff --git a/src/nvim/os/pty_process_unix.c b/src/nvim/os/pty_process_unix.c
index 4d7d9a45df..36d6dbe2db 100644
--- a/src/nvim/os/pty_process_unix.c
+++ b/src/nvim/os/pty_process_unix.c
@@ -20,6 +20,10 @@
# include <pty.h>
#endif
+#ifdef __APPLE__
+# include <crt_externs.h>
+#endif
+
#include <uv.h>
#include "nvim/lib/klist.h"
@@ -154,28 +158,14 @@ void pty_process_teardown(Loop *loop)
static void init_child(PtyProcess *ptyproc)
FUNC_ATTR_NONNULL_ALL
{
+#if defined(HAVE__NSGETENVIRON)
+#define environ (*_NSGetEnviron())
+#else
+ extern char **environ;
+#endif
// New session/process-group. #6530
setsid();
- os_unsetenv("COLUMNS");
- os_unsetenv("LINES");
- os_unsetenv("TERMCAP");
- os_unsetenv("COLORFGBG");
- // setting COLORTERM to "truecolor" if termguicolors is set and 256
- // otherwise, but only if it was set in the parent terminal at all
- if (os_env_exists("COLORTERM")) {
- const char *colorterm = os_getenv("COLORTERM");
- if (colorterm != NULL) {
- if (p_tgc) {
- os_setenv("COLORTERM", "truecolor", 1);
- } else {
- os_setenv("COLORTERM", "256", 1);
- }
- } else {
- os_unsetenv("COLORTERM");
- }
- }
-
signal(SIGCHLD, SIG_DFL);
signal(SIGHUP, SIG_DFL);
signal(SIGINT, SIG_DFL);
@@ -185,14 +175,17 @@ static void init_child(PtyProcess *ptyproc)
Process *proc = (Process *)ptyproc;
if (proc->cwd && os_chdir(proc->cwd) != 0) {
- ELOG("chdir failed: %s", strerror(errno));
+ ELOG("chdir(%s) failed: %s", proc->cwd, strerror(errno));
return;
}
char *prog = ptyproc->process.argv[0];
- os_setenv("TERM", ptyproc->term_name ? ptyproc->term_name : "ansi", 1);
- execvp(prog, ptyproc->process.argv);
- ELOG("execvp failed: %s: %s", strerror(errno), prog);
+
+ assert(proc->env);
+ environ = tv_dict_to_env(proc->env);
+ execvp(prog, proc->argv);
+ ELOG("execvp(%s) failed: %s", prog, strerror(errno));
+
_exit(122); // 122 is EXEC_FAILED in the Vim source.
}
diff --git a/src/nvim/os/pty_process_unix.h b/src/nvim/os/pty_process_unix.h
index f7c57b3839..8c822eafad 100644
--- a/src/nvim/os/pty_process_unix.h
+++ b/src/nvim/os/pty_process_unix.h
@@ -17,7 +17,6 @@ static inline PtyProcess pty_process_init(Loop *loop, void *data)
{
PtyProcess rv;
rv.process = process_init(loop, kProcessTypePty, data);
- rv.term_name = NULL;
rv.width = 80;
rv.height = 24;
rv.tty_fd = -1;
diff --git a/src/nvim/os/pty_process_win.c b/src/nvim/os/pty_process_win.c
index 6f7100e846..2bf73d08e6 100644
--- a/src/nvim/os/pty_process_win.c
+++ b/src/nvim/os/pty_process_win.c
@@ -52,6 +52,7 @@ int pty_process_spawn(PtyProcess *ptyproc)
uv_connect_t *out_req = NULL;
wchar_t *cmd_line = NULL;
wchar_t *cwd = NULL;
+ wchar_t *env = NULL;
const char *emsg = NULL;
assert(proc->err.closed);
@@ -124,13 +125,22 @@ int pty_process_spawn(PtyProcess *ptyproc)
goto cleanup;
}
+ if (proc->env != NULL) {
+ status = build_env_block(proc->env, &env);
+ }
+
+ if (status != 0) {
+ emsg = "build_env_block failed";
+ goto cleanup;
+ }
+
if (ptyproc->type == kConpty) {
if (!os_conpty_spawn(conpty_object,
&process_handle,
NULL,
cmd_line,
cwd,
- NULL)) {
+ env)) {
emsg = "os_conpty_spawn failed";
status = (int)GetLastError();
goto cleanup;
@@ -141,7 +151,7 @@ int pty_process_spawn(PtyProcess *ptyproc)
NULL, // Optional application name
cmd_line,
cwd,
- NULL, // Optional environment variables
+ env,
&err);
if (spawncfg == NULL) {
emsg = "winpty_spawn_config_new failed";
@@ -193,11 +203,13 @@ int pty_process_spawn(PtyProcess *ptyproc)
cleanup:
if (status) {
// In the case of an error of MultiByteToWideChar or CreateProcessW.
- ELOG("pty_process_spawn: %s: error code: %d", emsg, status);
+ 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: error code: %d", emsg, status);
+ ELOG("pty_process_spawn(%s): %s: error code: %d",
+ proc->argv[0], emsg, status);
status = translate_winpty_error(status);
}
winpty_error_free(err);
@@ -213,6 +225,7 @@ cleanup:
xfree(in_req);
xfree(out_req);
xfree(cmd_line);
+ xfree(env);
xfree(cwd);
return status;
}
@@ -332,19 +345,17 @@ static int build_cmd_line(char **argv, wchar_t **cmd_line, bool is_cmdexe)
utf8_cmd_line_len += argc;
char *utf8_cmd_line = xmalloc(utf8_cmd_line_len);
*utf8_cmd_line = NUL;
- while (1) {
- QUEUE *head = QUEUE_HEAD(&args_q);
- QUEUE_REMOVE(head);
- ArgNode *arg_node = QUEUE_DATA(head, ArgNode, node);
+ QUEUE *q;
+ QUEUE_FOREACH(q, &args_q, {
+ ArgNode *arg_node = QUEUE_DATA(q, ArgNode, node);
xstrlcat(utf8_cmd_line, arg_node->arg, utf8_cmd_line_len);
xfree(arg_node->arg);
xfree(arg_node);
- if (QUEUE_EMPTY(&args_q)) {
- break;
- } else {
+ QUEUE_REMOVE(q);
+ if (!QUEUE_EMPTY(&args_q)) {
xstrlcat(utf8_cmd_line, " ", utf8_cmd_line_len);
}
- }
+ })
int result = utf8_to_utf16(utf8_cmd_line, -1, cmd_line);
xfree(utf8_cmd_line);
@@ -454,3 +465,66 @@ int translate_winpty_error(int winpty_errno)
default: return UV_UNKNOWN;
}
}
+
+typedef struct EnvNode {
+ wchar_t *str;
+ size_t len;
+ QUEUE node;
+} EnvNode;
+
+/// Build the environment block to pass to CreateProcessW.
+///
+/// @param[in] denv Dict of environment name/value pairs
+/// @param[out] env Allocated environment block
+///
+/// @returns zero on success or error code of MultiByteToWideChar function.
+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;
+ char **env = tv_dict_to_env(denv);
+
+ QUEUE *q;
+ QUEUE env_q;
+ QUEUE_INIT(&env_q);
+ // Convert env vars to wchar_t and calculate how big the final env block
+ // needs to be
+ for (size_t i = 0; i < denv_size; i++) {
+ EnvNode *env_node = xmalloc(sizeof(*env_node));
+ rc = utf8_to_utf16(env[i], -1, &env_node->str);
+ if (rc != 0) {
+ goto cleanup;
+ }
+ env_node->len = wcslen(env_node->str) + 1;
+ env_block_len += env_node->len;
+ QUEUE_INSERT_TAIL(&env_q, &env_node->node);
+ }
+
+ // Additional '\0' after the final entry
+ env_block_len++;
+
+ *env_block = xmalloc(sizeof(**env_block) * env_block_len);
+ wchar_t *pos = *env_block;
+
+ QUEUE_FOREACH(q, &env_q, {
+ EnvNode *env_node = QUEUE_DATA(q, EnvNode, node);
+ memcpy(pos, env_node->str, env_node->len * sizeof(*pos));
+ pos += env_node->len;
+ })
+
+ *pos = L'\0';
+
+cleanup:
+ q = QUEUE_HEAD(&env_q);
+ while (q != &env_q) {
+ QUEUE *next = q->next;
+ EnvNode *env_node = QUEUE_DATA(q, EnvNode, node);
+ XFREE_CLEAR(env_node->str);
+ QUEUE_REMOVE(q);
+ xfree(env_node);
+ q = next;
+ }
+
+ return rc;
+}
diff --git a/src/nvim/os/pty_process_win.h b/src/nvim/os/pty_process_win.h
index 8ad5ba7286..f8ec79a3d6 100644
--- a/src/nvim/os/pty_process_win.h
+++ b/src/nvim/os/pty_process_win.h
@@ -37,7 +37,6 @@ static inline PtyProcess pty_process_init(Loop *loop, void *data)
{
PtyProcess rv;
rv.process = process_init(loop, kProcessTypePty, data);
- rv.term_name = NULL;
rv.width = 80;
rv.height = 24;
rv.object.winpty = NULL;
diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c
index b5d890bf52..2974245857 100644
--- a/src/nvim/os/shell.c
+++ b/src/nvim/os/shell.c
@@ -123,7 +123,7 @@ int os_expand_wildcards(int num_pat, char_u **pat, int *num_file,
int shell_style = STYLE_ECHO;
int check_spaces;
static bool did_find_nul = false;
- bool ampersent = false;
+ bool ampersand = false;
// vimglob() function to define for Posix shell
static char *sh_vimglob_func =
"vimglob() { while [ $# -ge 1 ]; do echo \"$1\"; shift; done }; vimglob >";
@@ -245,7 +245,7 @@ int os_expand_wildcards(int num_pat, char_u **pat, int *num_file,
p--;
}
if (*p == '&') { // remove trailing '&'
- ampersent = true;
+ ampersand = true;
*p = ' ';
}
STRCAT(command, ">");
@@ -309,7 +309,7 @@ int os_expand_wildcards(int num_pat, char_u **pat, int *num_file,
shellopts |= kShellOptHideMess;
}
- if (ampersent) {
+ if (ampersand) {
STRCAT(command, "&"); // put the '&' after the redirection
}
@@ -331,7 +331,7 @@ int os_expand_wildcards(int num_pat, char_u **pat, int *num_file,
// When running in the background, give it some time to create the temp
// file, but don't wait for it to finish.
- if (ampersent) {
+ if (ampersand) {
os_delay(10L, true);
}
diff --git a/src/nvim/os/time.c b/src/nvim/os/time.c
index 4b6533cd0c..9ea74716aa 100644
--- a/src/nvim/os/time.c
+++ b/src/nvim/os/time.c
@@ -62,6 +62,7 @@ uint64_t os_now(void)
/// @param ignoreinput If true, only SIGINT (CTRL-C) can interrupt.
void os_delay(uint64_t ms, bool ignoreinput)
{
+ DLOG("%" PRIu64 " ms", ms);
if (ignoreinput) {
if (ms > INT_MAX) {
ms = INT_MAX;
@@ -97,7 +98,7 @@ void os_microdelay(uint64_t us, bool ignoreinput)
const int rv = uv_cond_timedwait(&delay_cond, &delay_mutex, ns_delta);
if (0 != rv && UV_ETIMEDOUT != rv) {
- assert(false);
+ abort();
break;
} // Else: Timeout proceeded normally.
@@ -196,6 +197,22 @@ char *os_ctime(char *result, size_t result_len)
return os_ctime_r(&rawtime, result, result_len);
}
+/// Portable version of POSIX strptime()
+///
+/// @param str[in] string to convert
+/// @param format[in] format to parse "str"
+/// @param tm[out] time representation of "str"
+/// @return Pointer to first unprocessed character or NULL
+char *os_strptime(const char *str, const char *format, struct tm *tm)
+ FUNC_ATTR_NONNULL_ALL
+{
+#ifdef HAVE_STRPTIME
+ return strptime(str, format, tm);
+#else
+ return NULL;
+#endif
+}
+
/// Obtains the current Unix timestamp.
///
/// @return Seconds since epoch.