aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/os
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/os')
-rw-r--r--src/nvim/os/input.c12
-rw-r--r--src/nvim/os/pty_process.h9
-rw-r--r--src/nvim/os/pty_process_unix.c239
-rw-r--r--src/nvim/os/pty_process_unix.h31
-rw-r--r--src/nvim/os/pty_process_win.h28
-rw-r--r--src/nvim/os/shell.c7
-rw-r--r--src/nvim/os/signal.c11
-rw-r--r--src/nvim/os/time.c3
8 files changed, 325 insertions, 15 deletions
diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c
index 7687b14f02..0c46dc96ee 100644
--- a/src/nvim/os/input.c
+++ b/src/nvim/os/input.c
@@ -60,7 +60,7 @@ void input_start(int fd)
}
global_fd = fd;
- rstream_init_fd(&loop, &read_stream, fd, READ_BUFFER_SIZE, NULL);
+ rstream_init_fd(&main_loop, &read_stream, fd, READ_BUFFER_SIZE, NULL);
rstream_start(&read_stream, read_cb);
}
@@ -87,8 +87,8 @@ static void create_cursorhold_event(void)
// have been called(inbuf_poll would return kInputAvail)
// TODO(tarruda): Cursorhold should be implemented as a timer set during the
// `state_check` callback for the states where it can be triggered.
- assert(!events_enabled || queue_empty(loop.events));
- queue_put(loop.events, cursorhold_event, 0);
+ assert(!events_enabled || queue_empty(main_loop.events));
+ queue_put(main_loop.events, cursorhold_event, 0);
}
// Low level input function
@@ -147,7 +147,7 @@ bool os_char_avail(void)
void os_breakcheck(void)
{
if (!got_int) {
- loop_poll_events(&loop, 0);
+ loop_poll_events(&main_loop, 0);
}
}
@@ -322,7 +322,7 @@ static bool input_poll(int ms)
prof_inchar_enter();
}
- LOOP_PROCESS_EVENTS_UNTIL(&loop, NULL, ms, input_ready() || input_eof);
+ LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, ms, input_ready() || input_eof);
if (do_profiling == PROF_YES && ms) {
prof_inchar_exit();
@@ -419,5 +419,5 @@ static void read_error_exit(void)
static bool pending_events(void)
{
- return events_enabled && !queue_empty(loop.events);
+ return events_enabled && !queue_empty(main_loop.events);
}
diff --git a/src/nvim/os/pty_process.h b/src/nvim/os/pty_process.h
new file mode 100644
index 0000000000..94923499ca
--- /dev/null
+++ b/src/nvim/os/pty_process.h
@@ -0,0 +1,9 @@
+#ifndef NVIM_OS_PTY_PROCESS_H
+#define NVIM_OS_PTY_PROCESS_H
+
+#ifdef WIN32
+# include "nvim/os/pty_process_win.h"
+#else
+# include "nvim/os/pty_process_unix.h"
+#endif
+#endif // NVIM_OS_PTY_PROCESS_H
diff --git a/src/nvim/os/pty_process_unix.c b/src/nvim/os/pty_process_unix.c
new file mode 100644
index 0000000000..d0a38e663b
--- /dev/null
+++ b/src/nvim/os/pty_process_unix.c
@@ -0,0 +1,239 @@
+// Some of the code came from pangoterm and libuv
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <unistd.h>
+#include <termios.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/ioctl.h>
+
+// forkpty is not in POSIX, so headers are platform-specific
+#if defined(__FreeBSD__)
+# include <libutil.h>
+#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
+# include <util.h>
+#else
+# include <pty.h>
+#endif
+
+#include <uv.h>
+
+#include "nvim/lib/klist.h"
+
+#include "nvim/event/loop.h"
+#include "nvim/event/rstream.h"
+#include "nvim/event/wstream.h"
+#include "nvim/event/process.h"
+#include "nvim/os/pty_process_unix.h"
+#include "nvim/log.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "os/pty_process_unix.c.generated.h"
+#endif
+
+bool pty_process_spawn(PtyProcess *ptyproc)
+ FUNC_ATTR_NONNULL_ALL
+{
+ static struct termios termios;
+ if (!termios.c_cflag) {
+ init_termios(&termios);
+ }
+
+ Process *proc = (Process *)ptyproc;
+ assert(!proc->err);
+ uv_signal_start(&proc->loop->children_watcher, chld_handler, SIGCHLD);
+ ptyproc->winsize = (struct winsize){ ptyproc->height, ptyproc->width, 0, 0 };
+ uv_disable_stdio_inheritance();
+ int master;
+ int pid = forkpty(&master, NULL, &termios, &ptyproc->winsize);
+
+ if (pid < 0) {
+ ELOG("forkpty failed: %s", strerror(errno));
+ return false;
+ } else if (pid == 0) {
+ init_child(ptyproc);
+ abort();
+ }
+
+ // make sure the master file descriptor is non blocking
+ int master_status_flags = fcntl(master, F_GETFL);
+ if (master_status_flags == -1) {
+ ELOG("Failed to get master descriptor status flags: %s", strerror(errno));
+ goto error;
+ }
+ if (fcntl(master, F_SETFL, master_status_flags | O_NONBLOCK) == -1) {
+ ELOG("Failed to make master descriptor non-blocking: %s", strerror(errno));
+ goto error;
+ }
+
+ if (proc->in && !set_duplicating_descriptor(master, &proc->in->uv.pipe)) {
+ goto error;
+ }
+ if (proc->out && !set_duplicating_descriptor(master, &proc->out->uv.pipe)) {
+ goto error;
+ }
+
+ ptyproc->tty_fd = master;
+ proc->pid = pid;
+ return true;
+
+error:
+ close(master);
+ kill(pid, SIGKILL);
+ waitpid(pid, NULL, 0);
+ return false;
+}
+
+void pty_process_resize(PtyProcess *ptyproc, uint16_t width, uint16_t height)
+ FUNC_ATTR_NONNULL_ALL
+{
+ ptyproc->winsize = (struct winsize){ height, width, 0, 0 };
+ ioctl(ptyproc->tty_fd, TIOCSWINSZ, &ptyproc->winsize);
+}
+
+void pty_process_close(PtyProcess *ptyproc)
+ FUNC_ATTR_NONNULL_ALL
+{
+ pty_process_close_master(ptyproc);
+ Process *proc = (Process *)ptyproc;
+ if (proc->internal_close_cb) {
+ proc->internal_close_cb(proc);
+ }
+}
+
+void pty_process_close_master(PtyProcess *ptyproc) FUNC_ATTR_NONNULL_ALL
+{
+ if (ptyproc->tty_fd >= 0) {
+ close(ptyproc->tty_fd);
+ ptyproc->tty_fd = -1;
+ }
+}
+
+void pty_process_teardown(Loop *loop)
+{
+ uv_signal_stop(&loop->children_watcher);
+}
+
+static void init_child(PtyProcess *ptyproc) FUNC_ATTR_NONNULL_ALL
+{
+ unsetenv("COLUMNS");
+ unsetenv("LINES");
+ unsetenv("TERMCAP");
+ unsetenv("COLORTERM");
+ unsetenv("COLORFGBG");
+
+ signal(SIGCHLD, SIG_DFL);
+ signal(SIGHUP, SIG_DFL);
+ signal(SIGINT, SIG_DFL);
+ signal(SIGQUIT, SIG_DFL);
+ signal(SIGTERM, SIG_DFL);
+ signal(SIGALRM, SIG_DFL);
+
+ setenv("TERM", ptyproc->term_name ? ptyproc->term_name : "ansi", 1);
+ execvp(ptyproc->process.argv[0], ptyproc->process.argv);
+ fprintf(stderr, "execvp failed: %s\n", strerror(errno));
+}
+
+static void init_termios(struct termios *termios) FUNC_ATTR_NONNULL_ALL
+{
+ // Taken from pangoterm
+ termios->c_iflag = ICRNL|IXON;
+ termios->c_oflag = OPOST|ONLCR;
+#ifdef TAB0
+ termios->c_oflag |= TAB0;
+#endif
+ termios->c_cflag = CS8|CREAD;
+ termios->c_lflag = ISIG|ICANON|IEXTEN|ECHO|ECHOE|ECHOK;
+
+ cfsetspeed(termios, 38400);
+
+#ifdef IUTF8
+ termios->c_iflag |= IUTF8;
+#endif
+#ifdef NL0
+ termios->c_oflag |= NL0;
+#endif
+#ifdef CR0
+ termios->c_oflag |= CR0;
+#endif
+#ifdef BS0
+ termios->c_oflag |= BS0;
+#endif
+#ifdef VT0
+ termios->c_oflag |= VT0;
+#endif
+#ifdef FF0
+ termios->c_oflag |= FF0;
+#endif
+#ifdef ECHOCTL
+ termios->c_lflag |= ECHOCTL;
+#endif
+#ifdef ECHOKE
+ termios->c_lflag |= ECHOKE;
+#endif
+
+ termios->c_cc[VINTR] = 0x1f & 'C';
+ termios->c_cc[VQUIT] = 0x1f & '\\';
+ termios->c_cc[VERASE] = 0x7f;
+ termios->c_cc[VKILL] = 0x1f & 'U';
+ termios->c_cc[VEOF] = 0x1f & 'D';
+ termios->c_cc[VEOL] = _POSIX_VDISABLE;
+ termios->c_cc[VEOL2] = _POSIX_VDISABLE;
+ termios->c_cc[VSTART] = 0x1f & 'Q';
+ termios->c_cc[VSTOP] = 0x1f & 'S';
+ termios->c_cc[VSUSP] = 0x1f & 'Z';
+ termios->c_cc[VREPRINT] = 0x1f & 'R';
+ termios->c_cc[VWERASE] = 0x1f & 'W';
+ termios->c_cc[VLNEXT] = 0x1f & 'V';
+ termios->c_cc[VMIN] = 1;
+ termios->c_cc[VTIME] = 0;
+}
+
+static bool set_duplicating_descriptor(int fd, uv_pipe_t *pipe)
+ FUNC_ATTR_NONNULL_ALL
+{
+ int fd_dup = dup(fd);
+ if (fd_dup < 0) {
+ ELOG("Failed to dup descriptor %d: %s", fd, strerror(errno));
+ return false;
+ }
+ int uv_result = uv_pipe_open(pipe, fd_dup);
+ if (uv_result) {
+ ELOG("Failed to set pipe to descriptor %d: %s",
+ fd_dup, uv_strerror(uv_result));
+ close(fd_dup);
+ return false;
+ }
+ return true;
+}
+
+static void chld_handler(uv_signal_t *handle, int signum)
+{
+ int stat = 0;
+ int pid;
+
+ do {
+ pid = waitpid(-1, &stat, WNOHANG);
+ } while (pid < 0 && errno == EINTR);
+
+ if (pid <= 0) {
+ return;
+ }
+
+ Loop *loop = handle->loop->data;
+
+ kl_iter(WatcherPtr, loop->children, current) {
+ Process *proc = (*current)->data;
+ if (proc->pid == pid) {
+ if (WIFEXITED(stat)) {
+ proc->status = WEXITSTATUS(stat);
+ } else if (WIFSIGNALED(stat)) {
+ proc->status = WTERMSIG(stat);
+ }
+ proc->internal_exit_cb(proc);
+ break;
+ }
+ }
+}
diff --git a/src/nvim/os/pty_process_unix.h b/src/nvim/os/pty_process_unix.h
new file mode 100644
index 0000000000..f7c57b3839
--- /dev/null
+++ b/src/nvim/os/pty_process_unix.h
@@ -0,0 +1,31 @@
+#ifndef NVIM_OS_PTY_PROCESS_UNIX_H
+#define NVIM_OS_PTY_PROCESS_UNIX_H
+
+#include <sys/ioctl.h>
+
+#include "nvim/event/process.h"
+
+typedef struct pty_process {
+ Process process;
+ char *term_name;
+ uint16_t width, height;
+ struct winsize winsize;
+ int tty_fd;
+} PtyProcess;
+
+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;
+ return rv;
+}
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "os/pty_process_unix.h.generated.h"
+#endif
+
+#endif // NVIM_OS_PTY_PROCESS_UNIX_H
diff --git a/src/nvim/os/pty_process_win.h b/src/nvim/os/pty_process_win.h
new file mode 100644
index 0000000000..20cc589925
--- /dev/null
+++ b/src/nvim/os/pty_process_win.h
@@ -0,0 +1,28 @@
+#ifndef NVIM_OS_PTY_PROCESS_WIN_H
+#define NVIM_OS_PTY_PROCESS_WIN_H
+
+#include "nvim/event/libuv_process.h"
+
+typedef struct pty_process {
+ Process process;
+ char *term_name;
+ uint16_t width, height;
+} PtyProcess;
+
+#define pty_process_spawn(job) libuv_process_spawn((LibuvProcess *)job)
+#define pty_process_close(job) libuv_process_close((LibuvProcess *)job)
+#define pty_process_close_master(job) libuv_process_close((LibuvProcess *)job)
+#define pty_process_resize(job, width, height)
+#define pty_process_teardown(loop)
+
+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;
+ return rv;
+}
+
+#endif // NVIM_OS_PTY_PROCESS_WIN_H
diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c
index f5a1637c94..988620b145 100644
--- a/src/nvim/os/shell.c
+++ b/src/nvim/os/shell.c
@@ -14,6 +14,7 @@
#include "nvim/os/shell.h"
#include "nvim/os/signal.h"
#include "nvim/types.h"
+#include "nvim/main.h"
#include "nvim/vim.h"
#include "nvim/message.h"
#include "nvim/memory.h"
@@ -205,16 +206,16 @@ static int do_os_system(char **argv,
xstrlcpy(prog, argv[0], MAXPATHL);
Stream in, out, err;
- LibuvProcess uvproc = libuv_process_init(&loop, &buf);
+ LibuvProcess uvproc = libuv_process_init(&main_loop, &buf);
Process *proc = &uvproc.process;
- Queue *events = queue_new_child(loop.events);
+ Queue *events = queue_new_child(main_loop.events);
proc->events = events;
proc->argv = argv;
proc->in = input != NULL ? &in : NULL;
proc->out = &out;
proc->err = &err;
if (!process_spawn(proc)) {
- loop_poll_events(&loop, 0);
+ loop_poll_events(&main_loop, 0);
// Failed, probably due to `sh` not being executable
if (!silent) {
MSG_PUTS(_("\nCannot execute "));
diff --git a/src/nvim/os/signal.c b/src/nvim/os/signal.c
index 0ff6016e32..4abc9cfc36 100644
--- a/src/nvim/os/signal.c
+++ b/src/nvim/os/signal.c
@@ -8,6 +8,7 @@
#include "nvim/globals.h"
#include "nvim/memline.h"
#include "nvim/eval.h"
+#include "nvim/main.h"
#include "nvim/memory.h"
#include "nvim/misc1.h"
#include "nvim/misc2.h"
@@ -28,10 +29,10 @@ static bool rejecting_deadly;
void signal_init(void)
{
- signal_watcher_init(&loop, &spipe, NULL);
- signal_watcher_init(&loop, &shup, NULL);
- signal_watcher_init(&loop, &squit, NULL);
- signal_watcher_init(&loop, &sterm, NULL);
+ signal_watcher_init(&main_loop, &spipe, NULL);
+ signal_watcher_init(&main_loop, &shup, NULL);
+ signal_watcher_init(&main_loop, &squit, NULL);
+ signal_watcher_init(&main_loop, &sterm, NULL);
#ifdef SIGPIPE
signal_watcher_start(&spipe, on_signal, SIGPIPE);
#endif
@@ -41,7 +42,7 @@ void signal_init(void)
#endif
signal_watcher_start(&sterm, on_signal, SIGTERM);
#ifdef SIGPWR
- signal_watcher_init(&loop, &spwr, NULL);
+ signal_watcher_init(&main_loop, &spwr, NULL);
signal_watcher_start(&spwr, on_signal, SIGPWR);
#endif
}
diff --git a/src/nvim/os/time.c b/src/nvim/os/time.c
index 188f0802c9..2205ad0958 100644
--- a/src/nvim/os/time.c
+++ b/src/nvim/os/time.c
@@ -9,6 +9,7 @@
#include "nvim/os/time.h"
#include "nvim/event/loop.h"
#include "nvim/vim.h"
+#include "nvim/main.h"
static uv_mutex_t delay_mutex;
static uv_cond_t delay_cond;
@@ -43,7 +44,7 @@ void os_delay(uint64_t milliseconds, bool ignoreinput)
if (milliseconds > INT_MAX) {
milliseconds = INT_MAX;
}
- LOOP_PROCESS_EVENTS_UNTIL(&loop, NULL, (int)milliseconds, got_int);
+ LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, (int)milliseconds, got_int);
} else {
os_microdelay(milliseconds * 1000);
}