diff options
Diffstat (limited to 'src/nvim/os')
-rw-r--r-- | src/nvim/os/fs.c | 1 | ||||
-rw-r--r-- | src/nvim/os/input.c | 35 | ||||
-rw-r--r-- | src/nvim/os/os_defs.h | 4 | ||||
-rw-r--r-- | src/nvim/os/pty_process_unix.c | 6 | ||||
-rw-r--r-- | src/nvim/os/shell.c | 113 | ||||
-rw-r--r-- | src/nvim/os/signal.c | 1 | ||||
-rw-r--r-- | src/nvim/os/users.c | 60 |
7 files changed, 214 insertions, 6 deletions
diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index e9963516fc..24c7678633 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -21,7 +21,6 @@ #include "nvim/assert.h" #include "nvim/memory.h" #include "nvim/message.h" -#include "nvim/misc1.h" #include "nvim/option.h" #include "nvim/os/os.h" #include "nvim/os/os_defs.h" diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index 5b231f205b..3790eba212 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -17,7 +17,6 @@ #include "nvim/main.h" #include "nvim/mbyte.h" #include "nvim/memory.h" -#include "nvim/misc1.h" #include "nvim/msgpack_rpc/channel.h" #include "nvim/os/input.h" #include "nvim/state.h" @@ -183,6 +182,40 @@ void os_breakcheck(void) updating_screen = save_us; } +#define BREAKCHECK_SKIP 1000 +static int breakcheck_count = 0; + +/// Check for CTRL-C pressed, but only once in a while. +/// +/// Should be used instead of os_breakcheck() for functions that check for +/// each line in the file. Calling os_breakcheck() each time takes too much +/// time, because it will use system calls to check for input. +void line_breakcheck(void) +{ + if (++breakcheck_count >= BREAKCHECK_SKIP) { + breakcheck_count = 0; + os_breakcheck(); + } +} + +/// Like line_breakcheck() but check 10 times less often. +void fast_breakcheck(void) +{ + if (++breakcheck_count >= BREAKCHECK_SKIP * 10) { + breakcheck_count = 0; + os_breakcheck(); + } +} + +/// Like line_breakcheck() but check 100 times less often. +void veryfast_breakcheck(void) +{ + if (++breakcheck_count >= BREAKCHECK_SKIP * 100) { + breakcheck_count = 0; + os_breakcheck(); + } +} + /// Test whether a file descriptor refers to a terminal. /// diff --git a/src/nvim/os/os_defs.h b/src/nvim/os/os_defs.h index 8049b3b80e..dce4b0c187 100644 --- a/src/nvim/os/os_defs.h +++ b/src/nvim/os/os_defs.h @@ -13,6 +13,10 @@ # include "nvim/os/unix_defs.h" #endif +#if !defined(NAME_MAX) && defined(_XOPEN_NAME_MAX) +#define NAME_MAX _XOPEN_NAME_MAX +#endif + #define BASENAMELEN (NAME_MAX - 5) // Use the system path length if it makes sense. diff --git a/src/nvim/os/pty_process_unix.c b/src/nvim/os/pty_process_unix.c index 24ecf5c24f..450bc75ffb 100644 --- a/src/nvim/os/pty_process_unix.c +++ b/src/nvim/os/pty_process_unix.c @@ -15,7 +15,7 @@ # include <libutil.h> #elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) # include <util.h> -#else +#elif !defined(__sun) # include <pty.h> #endif @@ -198,7 +198,9 @@ static void init_termios(struct termios *termios) FUNC_ATTR_NONNULL_ALL termios->c_cflag = CS8|CREAD; termios->c_lflag = ISIG|ICANON|IEXTEN|ECHO|ECHOE|ECHOK; - cfsetspeed(termios, 38400); + // not using cfsetspeed, not available on all platforms + cfsetispeed(termios, 38400); + cfsetospeed(termios, 38400); #ifdef IUTF8 termios->c_iflag |= IUTF8; diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c index 6ef0aa1091..e618b2788b 100644 --- a/src/nvim/os/shell.c +++ b/src/nvim/os/shell.c @@ -12,6 +12,7 @@ #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" @@ -20,7 +21,6 @@ #include "nvim/memline.h" #include "nvim/memory.h" #include "nvim/message.h" -#include "nvim/misc1.h" #include "nvim/option_defs.h" #include "nvim/os/shell.h" #include "nvim/os/signal.h" @@ -28,6 +28,7 @@ #include "nvim/screen.h" #include "nvim/strings.h" #include "nvim/types.h" +#include "nvim/tag.h" #include "nvim/ui.h" #include "nvim/vim.h" @@ -681,6 +682,116 @@ int os_call_shell(char_u *cmd, ShellOpts opts, char_u *extra_args) return exitcode; } +/// os_call_shell() wrapper. Handles 'verbose', :profile, and v:shell_error. +/// Invalidates cached tags. +/// +/// @return shell command exit code +int call_shell(char_u *cmd, ShellOpts opts, char_u *extra_shell_arg) +{ + int retval; + proftime_T wait_time; + + if (p_verbose > 3) { + verbose_enter(); + smsg(_("Executing command: \"%s\""), cmd == NULL ? p_sh : cmd); + msg_putchar('\n'); + verbose_leave(); + } + + if (do_profiling == PROF_YES) { + prof_child_enter(&wait_time); + } + + if (*p_sh == NUL) { + emsg(_(e_shellempty)); + retval = -1; + } else { + // The external command may update a tags file, clear cached tags. + tag_freematch(); + + retval = os_call_shell(cmd, opts, extra_shell_arg); + } + + set_vim_var_nr(VV_SHELL_ERROR, (varnumber_T)retval); + if (do_profiling == PROF_YES) { + prof_child_exit(&wait_time); + } + + return retval; +} + +/// Get the stdout of an external command. +/// If "ret_len" is NULL replace NUL characters with NL. When "ret_len" is not +/// NULL store the length there. +/// +/// @param cmd command to execute +/// @param infile optional input file name +/// @param flags can be kShellOptSilent or 0 +/// @param ret_len length of the stdout +/// +/// @return an allocated string, or NULL for error. +char_u *get_cmd_output(char_u *cmd, char_u *infile, ShellOpts flags, size_t *ret_len) +{ + char_u *buffer = NULL; + + if (check_secure()) { + return NULL; + } + + // get a name for the temp file + char_u *tempname = vim_tempname(); + if (tempname == NULL) { + emsg(_(e_notmp)); + return NULL; + } + + // Add the redirection stuff + char_u *command = make_filter_cmd(cmd, infile, tempname); + + // Call the shell to execute the command (errors are ignored). + // Don't check timestamps here. + no_check_timestamps++; + call_shell(command, kShellOptDoOut | kShellOptExpand | flags, NULL); + no_check_timestamps--; + + xfree(command); + + // read the names from the file into memory + FILE *fd = os_fopen((char *)tempname, READBIN); + + if (fd == NULL) { + semsg(_(e_notopen), tempname); + goto done; + } + + fseek(fd, 0L, SEEK_END); + size_t len = (size_t)ftell(fd); // get size of temp file + fseek(fd, 0L, SEEK_SET); + + buffer = xmalloc(len + 1); + size_t i = fread((char *)buffer, 1, len, fd); + fclose(fd); + os_remove((char *)tempname); + if (i != len) { + semsg(_(e_notread), tempname); + XFREE_CLEAR(buffer); + } else if (ret_len == NULL) { + // Change NUL into SOH, otherwise the string is truncated. + for (i = 0; i < len; i++) { + if (buffer[i] == NUL) { + buffer[i] = 1; + } + } + + buffer[len] = NUL; // make sure the buffer is terminated + } else { + *ret_len = len; + } + +done: + xfree(tempname); + return buffer; +} /// os_system - synchronously execute a command in the shell /// /// example: diff --git a/src/nvim/os/signal.c b/src/nvim/os/signal.c index 0d125ec964..a8bf68a1a2 100644 --- a/src/nvim/os/signal.c +++ b/src/nvim/os/signal.c @@ -18,7 +18,6 @@ #include "nvim/main.h" #include "nvim/memline.h" #include "nvim/memory.h" -#include "nvim/misc1.h" #include "nvim/os/signal.h" #include "nvim/vim.h" diff --git a/src/nvim/os/users.c b/src/nvim/os/users.c index 9952e2b387..e0ce3fec31 100644 --- a/src/nvim/os/users.c +++ b/src/nvim/os/users.c @@ -18,6 +18,9 @@ # include <lm.h> #endif +// All user names (for ~user completion as done by shell). +static garray_T ga_users = GA_EMPTY_INIT_VALUE; + // Add a user name to the list of users in garray_T *users. // Do nothing if user name is NULL or empty. static void add_user(garray_T *users, char *user, bool need_copy) @@ -157,3 +160,60 @@ char *os_get_user_directory(const char *name) return NULL; } + +#if defined(EXITFREE) + +void free_users(void) +{ + ga_clear_strings(&ga_users); +} + +#endif + +/// Find all user names for user completion. +/// +/// Done only once and then cached. +static void init_users(void) +{ + static int lazy_init_done = false; + + if (lazy_init_done) { + return; + } + + lazy_init_done = true; + + os_get_usernames(&ga_users); +} + +/// Given to ExpandGeneric() to obtain an user names. +char_u *get_users(expand_T *xp, int idx) +{ + init_users(); + if (idx < ga_users.ga_len) { + return ((char_u **)ga_users.ga_data)[idx]; + } + return NULL; +} + +/// Check whether name matches a user name. +/// +/// @return 0 if name does not match any user name. +/// 1 if name partially matches the beginning of a user name. +/// 2 is name fully matches a user name. +int match_user(char_u *name) +{ + int n = (int)STRLEN(name); + int result = 0; + + init_users(); + for (int i = 0; i < ga_users.ga_len; i++) { + if (STRCMP(((char_u **)ga_users.ga_data)[i], name) == 0) { + return 2; // full match + } + if (STRNCMP(((char_u **)ga_users.ga_data)[i], name, n) == 0) { + result = 1; // partial match + } + } + return result; +} |