diff options
Diffstat (limited to 'src')
33 files changed, 380 insertions, 204 deletions
diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index 548d8171a5..1ab441bed3 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -35,7 +35,7 @@ Buffer window_get_buffer(Window window, Error *err) /// @return the (row, col) tuple Position window_get_cursor(Window window, Error *err) { - Position rv = {.row = 0, .col = 0}; + Position rv = POSITION_INIT; win_T *win = find_window_by_handle(window, err); if (win) { @@ -245,7 +245,7 @@ void window_set_option(Window window, String name, Object value, Error *err) /// @return The (row, col) tuple with the window position Position window_get_position(Window window, Error *err) { - Position rv; + Position rv = POSITION_INIT; win_T *win = find_window_by_handle(window, err); if (win) { diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 77bed67d5f..3c7fd777bd 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -1314,7 +1314,7 @@ buflist_new ( * for hard links. */ FileID file_id; bool file_id_valid = (sfname != NULL && - os_get_file_id((char *)sfname, &file_id)); + os_fileid((char *)sfname, &file_id)); if (ffname != NULL && !(flags & BLN_DUMMY) && (buf = buflist_findname_file_id(ffname, &file_id, file_id_valid)) != NULL) { @@ -1671,7 +1671,7 @@ buf_T *buflist_findname_exp(char_u *fname) buf_T *buflist_findname(char_u *ffname) { FileID file_id; - bool file_id_valid = os_get_file_id((char *)ffname, &file_id); + bool file_id_valid = os_fileid((char *)ffname, &file_id); return buflist_findname_file_id(ffname, &file_id, file_id_valid); } @@ -2221,7 +2221,7 @@ setfname ( * - if the buffer is loaded, fail * - if the buffer is not loaded, delete it from the list */ - file_id_valid = os_get_file_id((char *)ffname, &file_id); + file_id_valid = os_fileid((char *)ffname, &file_id); if (!(buf->b_flags & BF_DUMMY)) { obuf = buflist_findname_file_id(ffname, &file_id, file_id_valid); } @@ -2399,7 +2399,7 @@ static int otherfile_buf(buf_T *buf, char_u *ffname, /* If no struct stat given, get it now */ if (file_id_p == NULL) { file_id_p = &file_id; - file_id_valid = os_get_file_id((char *)ffname, file_id_p); + file_id_valid = os_fileid((char *)ffname, file_id_p); } if (!file_id_valid) { // file_id not valid, assume files are different. @@ -2429,7 +2429,7 @@ void buf_set_file_id(buf_T *buf) { FileID file_id; if (buf->b_fname != NULL - && os_get_file_id((char *)buf->b_fname, &file_id)) { + && os_fileid((char *)buf->b_fname, &file_id)) { buf->file_id_valid = true; buf->file_id = file_id; } else { @@ -2441,7 +2441,7 @@ void buf_set_file_id(buf_T *buf) static bool buf_same_file_id(buf_T *buf, FileID *file_id) { return buf->file_id_valid - && os_file_id_equal(&(buf->file_id), file_id); + && os_fileid_equal(&(buf->file_id), file_id); } /* diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index a2d496469e..de1b0985bb 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -512,7 +512,7 @@ struct file_buffer { long b_mtime; /* last change time of original file */ long b_mtime_read; /* last change time when reading */ - off_t b_orig_size; /* size of original file in bytes */ + uint64_t b_orig_size; /* size of original file in bytes */ int b_orig_mode; /* mode of original file */ pos_T b_namedm[NMARKS]; /* current named marks (mark.c) */ diff --git a/src/nvim/diff.c b/src/nvim/diff.c index ab0c80112f..73b5731ad0 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -947,9 +947,10 @@ void ex_diffpatch(exarg_T *eap) os_remove((char *)buf); // Only continue if the output file was created. - off_t file_size; - bool file_size_success = os_get_file_size((char *)tmp_new, &file_size); - if (!file_size_success || file_size == 0) { + FileInfo file_info; + bool info_ok = os_fileinfo((char *)tmp_new, &file_info); + uint64_t filesize = os_fileinfo_size(&file_info); + if (!info_ok || filesize == 0) { EMSG(_("E816: Cannot read patch output")); } else { if (curbuf->b_fname != NULL) { diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 04d90e255d..a61f082e59 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -6494,8 +6494,8 @@ static struct fst { {"searchpair", 3, 7, f_searchpair}, {"searchpairpos", 3, 7, f_searchpairpos}, {"searchpos", 1, 4, f_searchpos}, - {"send_call", 3, 3, f_send_call}, - {"send_event", 3, 3, f_send_event}, + {"send_call", 2, 64, f_send_call}, + {"send_event", 2, 64, f_send_event}, {"setbufvar", 3, 3, f_setbufvar}, {"setcmdpos", 1, 1, f_setcmdpos}, {"setline", 2, 2, f_setline}, @@ -9166,15 +9166,16 @@ static void f_getfsize(typval_T *argvars, typval_T *rettv) rettv->v_type = VAR_NUMBER; - off_t file_size; - if (os_get_file_size(fname, &file_size)) { + FileInfo file_info; + if (os_fileinfo(fname, &file_info)) { + uint64_t filesize = os_fileinfo_size(&file_info); if (os_isdir((char_u *)fname)) rettv->vval.v_number = 0; else { - rettv->vval.v_number = (varnumber_T)file_size; + rettv->vval.v_number = (varnumber_T)filesize; /* non-perfect check for overflow */ - if ((off_t)rettv->vval.v_number != file_size) { + if ((uint64_t)rettv->vval.v_number != filesize) { rettv->vval.v_number = -2; } } @@ -9191,7 +9192,7 @@ static void f_getftime(typval_T *argvars, typval_T *rettv) char *fname = (char *)get_tv_string(&argvars[0]); FileInfo file_info; - if (os_get_file_info(fname, &file_info)) { + if (os_fileinfo(fname, &file_info)) { rettv->vval.v_number = (varnumber_T)file_info.stat.st_mtim.tv_sec; } else { rettv->vval.v_number = -1; @@ -9211,7 +9212,7 @@ static void f_getftype(typval_T *argvars, typval_T *rettv) rettv->v_type = VAR_STRING; FileInfo file_info; - if (os_get_file_info_link((char *)fname, &file_info)) { + if (os_fileinfo_link((char *)fname, &file_info)) { uint64_t mode = file_info.stat.st_mode; #ifdef S_ISREG if (S_ISREG(mode)) @@ -12700,13 +12701,19 @@ static void f_send_call(typval_T *argvars, typval_T *rettv) return; } + Array args = ARRAY_DICT_INIT; + + for (typval_T *tv = argvars + 2; tv->v_type != VAR_UNKNOWN; tv++) { + ADD(args, vim_to_object(tv)); + } + bool errored; Object result; if (!channel_send_call((uint64_t)argvars[0].vval.v_number, - (char *)argvars[1].vval.v_string, - vim_to_object(&argvars[2]), - &result, - &errored)) { + (char *)argvars[1].vval.v_string, + args, + &result, + &errored)) { EMSG2(_(e_invarg2), "Channel doesn't exist"); return; } @@ -12741,9 +12748,15 @@ static void f_send_event(typval_T *argvars, typval_T *rettv) return; } + Array args = ARRAY_DICT_INIT; + + for (typval_T *tv = argvars + 2; tv->v_type != VAR_UNKNOWN; tv++) { + ADD(args, vim_to_object(tv)); + } + if (!channel_send_event((uint64_t)argvars[0].vval.v_number, (char *)argvars[1].vval.v_string, - vim_to_object(&argvars[2]))) { + args)) { EMSG2(_(e_invarg2), "Channel doesn't exist"); return; } @@ -19217,7 +19230,9 @@ static void apply_job_autocmds(Job *job, char *name, char *type, char *str) static void script_host_eval(char *method, typval_T *argvars, typval_T *rettv) { - Object result = provider_call(method, vim_to_object(argvars)); + Array args = ARRAY_DICT_INIT; + ADD(args, vim_to_object(argvars)); + Object result = provider_call(method, args); if (result.type == kObjectTypeNil) { return; diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 5b6604fc93..18216f6924 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -1533,7 +1533,7 @@ void write_viminfo(char_u *file, int forceit) */ FileInfo old_info; // FileInfo of existing viminfo file - if (os_get_file_info((char *)fname, &old_info) + if (os_fileinfo((char *)fname, &old_info) && getuid() != ROOT_UID && !(old_info.stat.st_uid == getuid() ? (old_info.stat.st_mode & 0200) diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index e0b0b55f41..ac91b2a6ac 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -2417,13 +2417,13 @@ do_source ( */ save_current_SID = current_SID; FileID file_id; - bool file_id_ok = os_get_file_id((char *)fname_exp, &file_id); + bool file_id_ok = os_fileid((char *)fname_exp, &file_id); for (current_SID = script_items.ga_len; current_SID > 0; --current_SID) { si = &SCRIPT_ITEM(current_SID); // Compare dev/ino when possible, it catches symbolic links. // Also compare file names, the inode may change when the file was edited. bool file_id_equal = file_id_ok && si->file_id_valid - && os_file_id_equal(&(si->file_id), &file_id); + && os_fileid_equal(&(si->file_id), &file_id); if (si->sn_name != NULL && (file_id_equal || fnamecmp(si->sn_name, fname_exp) == 0)) { break; @@ -3251,8 +3251,9 @@ static void script_host_execute(char *method, exarg_T *eap) char *script = (char *)script_get(eap, eap->arg); if (!eap->skip) { - String str = cstr_to_string(script ? script : (char *)eap->arg); - Object result = provider_call(method, STRING_OBJ(str)); + Array args = ARRAY_DICT_INIT; + ADD(args, STRING_OBJ(cstr_to_string(script ? script : (char *)eap->arg))); + Object result = provider_call(method, args); // We don't care about the result, so free it just in case a bad provider // returned something msgpack_rpc_free_object(result); @@ -3266,18 +3267,19 @@ static void script_host_execute_file(char *method, exarg_T *eap) char buffer[MAXPATHL]; vim_FullName(eap->arg, (uint8_t *)buffer, sizeof(buffer), false); - String file = cstr_to_string(buffer); - Object result = provider_call(method, STRING_OBJ(file)); + Array args = ARRAY_DICT_INIT; + ADD(args, STRING_OBJ(cstr_to_string(buffer))); + Object result = provider_call(method, args); msgpack_rpc_free_object(result); } static void script_host_do_range(char *method, exarg_T *eap) { - Array arg = {0, 0, 0}; - ADD(arg, INTEGER_OBJ(eap->line1)); - ADD(arg, INTEGER_OBJ(eap->line2)); - ADD(arg, STRING_OBJ(cstr_to_string((char *)eap->arg))); - Object result = provider_call(method, ARRAY_OBJ(arg)); + Array args = ARRAY_DICT_INIT; + ADD(args, INTEGER_OBJ(eap->line1)); + ADD(args, INTEGER_OBJ(eap->line2)); + ADD(args, STRING_OBJ(cstr_to_string((char *)eap->arg))); + Object result = provider_call(method, args); msgpack_rpc_free_object(result); } diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 74f3edc8d9..69fb1d344a 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -2011,6 +2011,10 @@ void free_cmdline_buf(void) */ static void draw_cmdline(int start, int len) { + if (embedded_mode) { + return; + } + int i; if (cmdline_star > 0) diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c index c7e1f5cbbc..955b0b0a68 100644 --- a/src/nvim/file_search.c +++ b/src/nvim/file_search.c @@ -1097,7 +1097,7 @@ static int ff_check_visited(ff_visited_T **visited_list, char_u *fname, char_u * url = true; } else { ff_expand_buffer[0] = NUL; - if (!os_get_file_id((char *)fname, &file_id)) { + if (!os_fileid((char *)fname, &file_id)) { return FAIL; } } @@ -1106,7 +1106,7 @@ static int ff_check_visited(ff_visited_T **visited_list, char_u *fname, char_u * for (vp = *visited_list; vp != NULL; vp = vp->ffv_next) { if ((url && fnamecmp(vp->ffv_fname, ff_expand_buffer) == 0) || (!url && vp->file_id_valid - && os_file_id_equal(&(vp->file_id), &file_id))) { + && os_fileid_equal(&(vp->file_id), &file_id))) { /* are the wildcard parts equal */ if (ff_wc_equal(vp->ffv_wc_path, wc_path) == TRUE) /* already visited */ diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 2e932e9695..0a05b2a4db 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -472,7 +472,7 @@ readfile ( if (newfile && !read_stdin && !read_buffer) { /* Remember time of file. */ FileInfo file_info; - if (os_get_file_info((char *)fname, &file_info)) { + if (os_fileinfo((char *)fname, &file_info)) { buf_store_file_info(curbuf, &file_info); curbuf->b_mtime_read = curbuf->b_mtime; #ifdef UNIX @@ -2583,7 +2583,7 @@ buf_write ( #if defined(UNIX) perm = -1; FileInfo file_info_old; - if (!os_get_file_info((char *)fname, &file_info_old)) { + if (!os_fileinfo((char *)fname, &file_info_old)) { newfile = TRUE; } else { perm = file_info_old.stat.st_mode; @@ -2629,7 +2629,7 @@ buf_write ( goto fail; } if (overwriting) { - os_get_file_info((char *)fname, &file_info_old); + os_fileinfo((char *)fname, &file_info_old); } } @@ -2712,9 +2712,9 @@ buf_write ( * - it's a symbolic link * - we don't have write permission in the directory */ - if (file_info_old.stat.st_nlink > 1 - || !os_get_file_info_link((char *)fname, &file_info) - || !os_file_info_id_equal(&file_info, &file_info_old)) { + if (os_fileinfo_hardlinks(&file_info_old) > 1 + || !os_fileinfo_link((char *)fname, &file_info) + || !os_fileinfo_id_equal(&file_info, &file_info_old)) { backup_copy = TRUE; } else # endif @@ -2728,7 +2728,7 @@ buf_write ( STRCPY(IObuff, fname); for (i = 4913;; i += 123) { sprintf((char *)path_tail(IObuff), "%d", i); - if (!os_get_file_info_link((char *)IObuff, &file_info)) { + if (!os_fileinfo_link((char *)IObuff, &file_info)) { break; } } @@ -2739,7 +2739,7 @@ buf_write ( else { # ifdef UNIX os_fchown(fd, file_info_old.stat.st_uid, file_info_old.stat.st_gid); - if (!os_get_file_info((char *)IObuff, &file_info) + if (!os_fileinfo((char *)IObuff, &file_info) || file_info.stat.st_uid != file_info_old.stat.st_uid || file_info.stat.st_gid != file_info_old.stat.st_gid || (long)file_info.stat.st_mode != perm) { @@ -2759,20 +2759,20 @@ buf_write ( */ if ((bkc_flags & BKC_BREAKSYMLINK) || (bkc_flags & BKC_BREAKHARDLINK)) { # ifdef UNIX - bool file_info_link_ok = os_get_file_info_link((char *)fname, &file_info); + bool file_info_link_ok = os_fileinfo_link((char *)fname, &file_info); /* Symlinks. */ if ((bkc_flags & BKC_BREAKSYMLINK) && file_info_link_ok - && !os_file_info_id_equal(&file_info, &file_info_old)) { + && !os_fileinfo_id_equal(&file_info, &file_info_old)) { backup_copy = FALSE; } /* Hardlinks. */ if ((bkc_flags & BKC_BREAKHARDLINK) - && file_info_old.stat.st_nlink > 1 + && os_fileinfo_hardlinks(&file_info_old) > 1 && (!file_info_link_ok - || os_file_info_id_equal(&file_info, &file_info_old))) { + || os_fileinfo_id_equal(&file_info, &file_info_old))) { backup_copy = FALSE; } # endif @@ -2837,14 +2837,14 @@ buf_write ( /* * Check if backup file already exists. */ - if (os_get_file_info((char *)backup, &file_info_new)) { + if (os_fileinfo((char *)backup, &file_info_new)) { /* * Check if backup file is same as original file. * May happen when modname() gave the same file back (e.g. silly * link). If we don't check here, we either ruin the file when * copying or erase it after writing. */ - if (os_file_info_id_equal(&file_info_new, &file_info_old)) { + if (os_fileinfo_id_equal(&file_info_new, &file_info_old)) { free(backup); backup = NULL; /* no backup file to delete */ } @@ -2861,7 +2861,7 @@ buf_write ( wp = backup; *wp = 'z'; while (*wp > 'a' - && os_get_file_info((char *)backup, &file_info_new)) { + && os_fileinfo((char *)backup, &file_info_new)) { --*wp; } /* They all exist??? Must be something wrong. */ @@ -3201,9 +3201,9 @@ nobackup: FileInfo file_info; /* Don't delete the file when it's a hard or symbolic link. */ - if ((!newfile && file_info_old.stat.st_nlink > 1) - || (os_get_file_info_link((char *)fname, &file_info) - && !os_file_info_id_equal(&file_info, &file_info_old))) { + if ((!newfile && os_fileinfo_hardlinks(&file_info) > 1) + || (os_fileinfo_link((char *)fname, &file_info) + && !os_fileinfo_id_equal(&file_info, &file_info_old))) { errmsg = (char_u *)_("E166: Can't open linked file for writing"); } else #endif @@ -3416,7 +3416,7 @@ restore_backup: /* don't change the owner when it's already OK, some systems remove * permission or ACL stuff */ FileInfo file_info; - if (!os_get_file_info((char *)wfname, &file_info) + if (!os_fileinfo((char *)wfname, &file_info) || file_info.stat.st_uid != file_info_old.stat.st_uid || file_info.stat.st_gid != file_info_old.stat.st_gid) { os_fchown(fd, file_info_old.stat.st_uid, file_info_old.stat.st_gid); @@ -3713,7 +3713,7 @@ nofail: /* Update the timestamp to avoid an "overwrite changed file" * prompt when writing again. */ - if (os_get_file_info((char *)fname, &file_info_old)) { + if (os_fileinfo((char *)fname, &file_info_old)) { buf_store_file_info(buf, &file_info_old); buf->b_mtime_read = buf->b_mtime; } @@ -4536,7 +4536,7 @@ int vim_rename(char_u *from, char_u *to) // Fail if the "from" file doesn't exist. Avoids that "to" is deleted. FileInfo from_info; - if (!os_get_file_info((char *)from, &from_info)) { + if (!os_fileinfo((char *)from, &from_info)) { return -1; } @@ -4544,8 +4544,8 @@ int vim_rename(char_u *from, char_u *to) // This happens when "from" and "to" differ in case and are on a FAT32 // filesystem. In that case go through a temp file name. FileInfo to_info; - if (os_get_file_info((char *)to, &to_info) - && os_file_info_id_equal(&from_info, &to_info)) { + if (os_fileinfo((char *)to, &to_info) + && os_fileinfo_id_equal(&from_info, &to_info)) { use_tmp_file = true; } @@ -4790,7 +4790,7 @@ buf_check_timestamp ( int helpmesg = FALSE; int reload = FALSE; int can_reload = FALSE; - off_t orig_size = buf->b_orig_size; + uint64_t orig_size = buf->b_orig_size; int orig_mode = buf->b_orig_mode; static int busy = FALSE; int n; @@ -4812,7 +4812,7 @@ buf_check_timestamp ( bool file_info_ok; if (!(buf->b_flags & BF_NOTEDITED) && buf->b_mtime != 0 - && (!(file_info_ok = os_get_file_info((char *)buf->b_ffname, &file_info)) + && (!(file_info_ok = os_fileinfo((char *)buf->b_ffname, &file_info)) || time_differs((long)file_info.stat.st_mtim.tv_sec, buf->b_mtime) || (int)file_info.stat.st_mode != buf->b_orig_mode )) { @@ -5127,9 +5127,10 @@ void buf_reload(buf_T *buf, int orig_mode) } void buf_store_file_info(buf_T *buf, FileInfo *file_info) + FUNC_ATTR_NONNULL_ALL { buf->b_mtime = (long)file_info->stat.st_mtim.tv_sec; - buf->b_orig_size = file_info->stat.st_size; + buf->b_orig_size = os_fileinfo_size(file_info); buf->b_orig_mode = (int)file_info->stat.st_mode; } diff --git a/src/nvim/globals.h b/src/nvim/globals.h index ad65f7e6fd..1ff8887598 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -1233,6 +1233,9 @@ EXTERN char *ignoredp; * os_unix.c */ EXTERN int curr_tmode INIT(= TMODE_COOK); /* contains current terminal mode */ +// If a msgpack-rpc channel should be started over stdin/stdout +EXTERN bool embedded_mode INIT(= false); + /// Used to track the status of external functions. /// Currently only used for iconv(). typedef enum { diff --git a/src/nvim/if_cscope.c b/src/nvim/if_cscope.c index 9e07a60ee1..667e6512f3 100644 --- a/src/nvim/if_cscope.c +++ b/src/nvim/if_cscope.c @@ -473,7 +473,7 @@ cs_add_common ( fname = (char *)vim_strnsave((char_u *)fname, len); free(fbuf); FileInfo file_info; - bool file_info_ok = os_get_file_info(fname, &file_info); + bool file_info_ok = os_fileinfo(fname, &file_info); if (!file_info_ok) { staterr: if (p_csverbose) @@ -504,7 +504,7 @@ staterr: else (void)sprintf(fname2, "%s/%s", fname, CSCOPE_DBFILE); - file_info_ok = os_get_file_info(fname2, &file_info); + file_info_ok = os_fileinfo(fname2, &file_info); if (!file_info_ok) { if (p_csverbose) cs_stat_emsg(fname2); @@ -1181,7 +1181,7 @@ static int cs_insert_filelist(char *fname, char *ppath, char *flags, i = -1; /* can be set to the index of an empty item in csinfo */ for (j = 0; j < csinfo_size; j++) { if (csinfo[j].fname != NULL - && os_file_id_equal_file_info(&(csinfo[j].file_id), file_info)) { + && os_fileid_equal_fileinfo(&(csinfo[j].file_id), file_info)) { if (p_csverbose) (void)EMSG(_("E568: duplicate cscope database not added")); return -1; @@ -1224,7 +1224,7 @@ static int cs_insert_filelist(char *fname, char *ppath, char *flags, } else csinfo[i].flags = NULL; - os_file_info_get_id(file_info, &(csinfo[i].file_id)); + os_fileinfo_id(file_info, &(csinfo[i].file_id)); return i; } /* cs_insert_filelist */ diff --git a/src/nvim/main.c b/src/nvim/main.c index 1de4b04a07..9ab46b1ce2 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -256,10 +256,10 @@ int main(int argc, char **argv) TIME_MSG("shell init"); - /* - * Print a warning if stdout is not a terminal. - */ - check_tty(¶ms); + if (!embedded_mode) { + // Print a warning if stdout is not a terminal. + check_tty(¶ms); + } /* This message comes before term inits, but after setting "silent_mode" * when the input is not a tty. */ @@ -267,8 +267,16 @@ int main(int argc, char **argv) printf(_("%d files to edit\n"), GARGCOUNT); if (params.want_full_screen && !silent_mode) { - termcapinit(params.term); /* set terminal name and get terminal - capabilities (will set full_screen) */ + if (embedded_mode) { + // In embedded mode don't do terminal-related initializations, assume an + // initial screen size of 80x20 + full_screen = true; + set_shellsize(80, 20, false); + } else { + // set terminal name and get terminal capabilities (will set full_screen) + // Do some initialization of the screen + termcapinit(params.term); + } screen_start(); /* don't know where cursor is now */ TIME_MSG("Termcap init"); } @@ -405,14 +413,18 @@ int main(int argc, char **argv) TIME_MSG("waiting for return"); } - starttermcap(); /* start termcap if not done by wait_return() */ - TIME_MSG("start termcap"); - may_req_ambiguous_char_width(); + if (!embedded_mode) { + starttermcap(); // start termcap if not done by wait_return() + TIME_MSG("start termcap"); + may_req_ambiguous_char_width(); + setmouse(); // may start using the mouse - setmouse(); /* may start using the mouse */ - if (scroll_region) - scroll_region_reset(); /* In case Rows changed */ - scroll_start(); /* may scroll the screen to the right position */ + if (scroll_region) { + scroll_region_reset(); // In case Rows changed + } + + scroll_start(); // may scroll the screen to the right position + } /* * Don't clear the screen when starting in Ex mode, unless using the GUI. @@ -1015,11 +1027,13 @@ static void command_line_scan(mparm_T *parmp) msg_putchar('\n'); msg_didout = FALSE; mch_exit(0); - } else if (STRICMP(argv[0] + argv_idx, "api-msgpack-metadata") == 0) { + } else if (STRICMP(argv[0] + argv_idx, "api-msgpack-metadata") == 0) { for (unsigned int i = 0; i<msgpack_metadata_size; i++) { putchar(msgpack_metadata[i]); } mch_exit(0); + } else if (STRICMP(argv[0] + argv_idx, "embedded-mode") == 0) { + embedded_mode = true; } else if (STRNICMP(argv[0] + argv_idx, "literal", 7) == 0) { #if !defined(UNIX) parmp->literal = TRUE; @@ -2080,9 +2094,9 @@ static int file_owned(char *fname) { uid_t uid = getuid(); FileInfo file_info; - bool file_owned = os_get_file_info(fname, &file_info) + bool file_owned = os_fileinfo(fname, &file_info) && file_info.stat.st_uid == uid; - bool link_owned = os_get_file_info_link(fname, &file_info) + bool link_owned = os_fileinfo_link(fname, &file_info) && file_info.stat.st_uid == uid; return file_owned && link_owned; } @@ -2200,6 +2214,8 @@ static void usage(void) main_msg(_("--startuptime <file>\tWrite startup timing messages to <file>")); main_msg(_("-i <viminfo>\t\tUse <viminfo> instead of .viminfo")); main_msg(_("--api-msgpack-metadata\tDump API metadata information and exit")); + main_msg(_("--embedded-mode\tUse stdin/stdout as a msgpack-rpc channel. " + "This can be used for embedding Neovim into other programs")); main_msg(_("-h or --help\tPrint Help (this message) and exit")); main_msg(_("--version\t\tPrint version information and exit")); diff --git a/src/nvim/memfile.c b/src/nvim/memfile.c index 82369b739a..827cff2299 100644 --- a/src/nvim/memfile.c +++ b/src/nvim/memfile.c @@ -122,11 +122,11 @@ memfile_T *mf_open(char_u *fname, int flags) * mf_blocknr_max must be rounded up. */ FileInfo file_info; - if (mfp->mf_fd >= 0 - && os_get_file_info_fd(mfp->mf_fd, &file_info) - && file_info.stat.st_blksize >= MIN_SWAP_PAGE_SIZE - && file_info.stat.st_blksize <= MAX_SWAP_PAGE_SIZE) { - mfp->mf_page_size = file_info.stat.st_blksize; + if (mfp->mf_fd >= 0 && os_fileinfo_fd(mfp->mf_fd, &file_info)) { + uint64_t blocksize = os_fileinfo_blocksize(&file_info); + if (blocksize >= MIN_SWAP_PAGE_SIZE && blocksize <= MAX_SWAP_PAGE_SIZE) { + mfp->mf_page_size = blocksize; + } } if (mfp->mf_fd < 0 || (flags & (O_TRUNC|O_EXCL)) @@ -1017,7 +1017,7 @@ mf_do_open ( */ FileInfo file_info; if ((flags & O_CREAT) - && os_get_file_info_link((char *)mfp->mf_fname, &file_info)) { + && os_fileinfo_link((char *)mfp->mf_fname, &file_info)) { mfp->mf_fd = -1; EMSG(_("E300: Swap file already exists (symlink attack?)")); } else { diff --git a/src/nvim/memline.c b/src/nvim/memline.c index 229de4ae1c..04ee0d7f55 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -686,9 +686,9 @@ static void set_b0_fname(ZERO_BL *b0p, buf_T *buf) } } FileInfo file_info; - if (os_get_file_info((char *)buf->b_ffname, &file_info)) { + if (os_fileinfo((char *)buf->b_ffname, &file_info)) { long_to_char((long)file_info.stat.st_mtim.tv_sec, b0p->b0_mtime); - long_to_char((long)os_file_info_get_inode(&file_info), b0p->b0_ino); + long_to_char((long)os_fileinfo_inode(&file_info), b0p->b0_ino); buf_store_file_info(buf, &file_info); buf->b_mtime_read = buf->b_mtime; } else { @@ -961,8 +961,8 @@ void ml_recover(void) FileInfo swp_file_info; mtime = char_to_long(b0p->b0_mtime); if (curbuf->b_ffname != NULL - && os_get_file_info((char *)curbuf->b_ffname, &org_file_info) - && ((os_get_file_info((char *)mfp->mf_fname, &swp_file_info) + && os_fileinfo((char *)curbuf->b_ffname, &org_file_info) + && ((os_fileinfo((char *)mfp->mf_fname, &swp_file_info) && org_file_info.stat.st_mtim.tv_sec > swp_file_info.stat.st_mtim.tv_sec) || org_file_info.stat.st_mtim.tv_sec != mtime)) { @@ -1494,7 +1494,7 @@ static time_t swapfile_info(char_u *fname) /* print the swap file date */ FileInfo file_info; - if (os_get_file_info((char *)fname, &file_info)) { + if (os_fileinfo((char *)fname, &file_info)) { #ifdef UNIX /* print name of owner of the file */ if (os_get_uname(file_info.stat.st_uid, uname, B0_UNAME_SIZE) == OK) { @@ -1630,9 +1630,9 @@ void ml_sync_all(int check_file, int check_char) * call ml_preserve() to get rid of all negative numbered blocks. */ FileInfo file_info; - if (!os_get_file_info((char *)buf->b_ffname, &file_info) + if (!os_fileinfo((char *)buf->b_ffname, &file_info) || file_info.stat.st_mtim.tv_sec != buf->b_mtime_read - || (off_t)file_info.stat.st_size != buf->b_orig_size) { + || os_fileinfo_size(&file_info) != buf->b_orig_size) { ml_preserve(buf, FALSE); did_check_timestamps = FALSE; need_check_timestamps = TRUE; /* give message later */ @@ -3180,7 +3180,7 @@ attention_message ( msg_outtrans(buf->b_fname); MSG_PUTS("\"\n"); FileInfo file_info; - if (os_get_file_info((char *)buf->b_fname, &file_info)) { + if (os_fileinfo((char *)buf->b_fname, &file_info)) { MSG_PUTS(_(" dated: ")); x = file_info.stat.st_mtim.tv_sec; p = ctime(&x); // includes '\n' @@ -3294,7 +3294,7 @@ findswapname ( // Extra security check: When a swap file is a symbolic link, this // is most likely a symlink attack. FileInfo file_info; - bool file_or_link_found = os_get_file_info_link((char *)fname, &file_info); + bool file_or_link_found = os_fileinfo_link((char *)fname, &file_info); if (!file_or_link_found) { break; } @@ -3558,8 +3558,8 @@ fnamecmp_ino ( int retval_s; /* flag: buf_s valid */ FileInfo file_info; - if (os_get_file_info((char *)fname_c, &file_info)) { - ino_c = os_file_info_get_inode(&file_info); + if (os_fileinfo((char *)fname_c, &file_info)) { + ino_c = os_fileinfo_inode(&file_info); } /* @@ -3567,8 +3567,8 @@ fnamecmp_ino ( * the swap file may be outdated. If that fails (e.g. this path is not * valid on this machine), use the inode from block 0. */ - if (os_get_file_info((char *)fname_s, &file_info)) { - ino_s = os_file_info_get_inode(&file_info); + if (os_fileinfo((char *)fname_s, &file_info)) { + ino_s = os_fileinfo_inode(&file_info); } else { ino_s = (uint64_t)ino_block0; } diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c index 986374b352..8669977ea1 100644 --- a/src/nvim/misc1.c +++ b/src/nvim/misc1.c @@ -503,7 +503,7 @@ open_line ( break; } } - if (lead_len) { + if (lead_len > 0) { /* allocate buffer (may concatenate p_extra later) */ leader = xmalloc(lead_len + lead_repl_len + extra_space + extra_len + (second_line_indent > 0 ? second_line_indent : 0) + 1); diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 0b0a913a95..f1cb34577b 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -5232,7 +5232,8 @@ static void get_clipboard(int name) struct yankreg *reg = &y_regs[CLIP_REGISTER]; free_register(reg); - Object result = provider_call("clipboard_get", NIL); + Array args = ARRAY_DICT_INIT; + Object result = provider_call("clipboard_get", args); if (result.type != kObjectTypeArray) { goto err; @@ -5278,12 +5279,15 @@ static void set_clipboard(int name) copy_register(reg, &y_regs[0]); } - Array lines = {0, 0, 0}; + Array lines = ARRAY_DICT_INIT; for (int i = 0; i < reg->y_size; i++) { ADD(lines, STRING_OBJ(cstr_to_string((char *)reg->y_array[i]))); } - Object result = provider_call("clipboard_set", ARRAY_OBJ(lines)); + Array args = ARRAY_DICT_INIT; + ADD(args, ARRAY_OBJ(lines)); + + Object result = provider_call("clipboard_set", args); msgpack_rpc_free_object(result); } diff --git a/src/nvim/os/channel.c b/src/nvim/os/channel.c index 1a2efca513..bad82bc272 100644 --- a/src/nvim/os/channel.c +++ b/src/nvim/os/channel.c @@ -20,11 +20,14 @@ #include "nvim/vim.h" #include "nvim/ascii.h" #include "nvim/memory.h" +#include "nvim/os_unix.h" #include "nvim/message.h" #include "nvim/map.h" #include "nvim/log.h" #include "nvim/lib/kvec.h" +#define CHANNEL_BUFFER_SIZE 0xffff + typedef struct { uint64_t request_id; bool errored; @@ -64,6 +67,10 @@ void channel_init(void) channels = pmap_new(uint64_t)(); event_strings = pmap_new(cstr_t)(); msgpack_sbuffer_init(&out_buffer); + + if (embedded_mode) { + channel_from_stdio(); + } } /// Teardown the module @@ -117,7 +124,10 @@ void channel_from_stream(uv_stream_t *stream) stream->data = NULL; channel->is_job = false; // read stream - channel->data.streams.read = rstream_new(parse_msgpack, 1024, channel, NULL); + channel->data.streams.read = rstream_new(parse_msgpack, + CHANNEL_BUFFER_SIZE, + channel, + NULL); rstream_set_stream(channel->data.streams.read, stream); rstream_start(channel->data.streams.read); // write stream @@ -133,40 +143,48 @@ bool channel_exists(uint64_t id) && channel->enabled; } -/// Sends event/data to channel +/// Sends event/arguments to channel /// /// @param id The channel id. If 0, the event will be sent to all /// channels that have subscribed to the event type /// @param name The event name, an arbitrary string -/// @param arg The event arg -/// @return True if the data was sent successfully, false otherwise. -bool channel_send_event(uint64_t id, char *name, Object arg) +/// @param args Array with event arguments +/// @return True if the event was sent successfully, false otherwise. +bool channel_send_event(uint64_t id, char *name, Array args) { Channel *channel = NULL; if (id > 0) { if (!(channel = pmap_get(uint64_t)(channels, id)) || !channel->enabled) { - msgpack_rpc_free_object(arg); + msgpack_rpc_free_array(args); return false; } - send_event(channel, name, arg); + send_event(channel, name, args); } else { - broadcast_event(name, arg); + broadcast_event(name, args); } return true; } +/// Sends a method call to a channel +/// +/// @param id The channel id +/// @param name The method name, an arbitrary string +/// @param args Array with method arguments +/// @param[out] result Pointer to return value received from the channel +/// @param[out] error True if the return value is an error +/// @return True if the call was sent successfully, false otherwise. bool channel_send_call(uint64_t id, char *name, - Object arg, + Array args, Object *result, bool *errored) { Channel *channel = NULL; if (!(channel = pmap_get(uint64_t)(channels, id)) || !channel->enabled) { - msgpack_rpc_free_object(arg); + msgpack_rpc_free_array(args); return false; } @@ -176,17 +194,16 @@ bool channel_send_call(uint64_t id, char buf[256]; snprintf(buf, sizeof(buf), - "Channel %" PRIu64 " was closed due to a high stack depth " - "while processing a RPC call", + "Channel %" PRIu64 " crossed maximum stack depth", channel->id); *result = STRING_OBJ(cstr_to_string(buf)); - msgpack_rpc_free_object(arg); + msgpack_rpc_free_array(args); return false; } uint64_t request_id = channel->next_request_id++; // Send the msgpack-rpc request - send_request(channel, request_id, name, arg); + send_request(channel, request_id, name, args); EventSource channel_source = channel->is_job ? job_event_source(channel->data.job) @@ -205,14 +222,6 @@ bool channel_send_call(uint64_t id, channel->enabled && // the channel is still enabled kv_size(channel->call_stack) >= size); // the call didn't return - if (!(kv_size(channel->call_stack) - || channel->enabled - || channel->rpc_call_level)) { - // Close the channel if it has been disabled and we have not been called - // by `parse_msgpack`(It would be unsafe to close the channel otherwise) - close_channel(channel); - } - *errored = frame.errored; *result = frame.result; @@ -256,6 +265,25 @@ void channel_unsubscribe(uint64_t id, char *event) unsubscribe(channel, event); } +/// Creates an API channel from stdin/stdout. This is used when embedding +/// Neovim +static void channel_from_stdio(void) +{ + Channel *channel = register_channel(); + channel->is_job = false; + // read stream + channel->data.streams.read = rstream_new(parse_msgpack, + CHANNEL_BUFFER_SIZE, + channel, + NULL); + rstream_set_file(channel->data.streams.read, 0); + rstream_start(channel->data.streams.read); + // write stream + channel->data.streams.write = wstream_new(0); + wstream_set_file(channel->data.streams.write, 1); + channel->data.streams.uv = NULL; +} + static void job_out(RStream *rstream, void *data, bool eof) { Job *job = data; @@ -278,6 +306,7 @@ static void job_err(RStream *rstream, void *data, bool eof) static void parse_msgpack(RStream *rstream, void *data, bool eof) { Channel *channel = data; + channel->rpc_call_level++; if (eof) { char buf[256]; @@ -287,10 +316,9 @@ static void parse_msgpack(RStream *rstream, void *data, bool eof) "closed by the client", channel->id); call_set_error(channel, buf); - return; + goto end; } - channel->rpc_call_level++; uint32_t count = rstream_available(rstream); DLOG("Feeding the msgpack parser with %u bytes of data from RStream(%p)", count, @@ -386,21 +414,21 @@ static void send_error(Channel *channel, uint64_t id, char *err) static void send_request(Channel *channel, uint64_t id, char *name, - Object arg) + Array args) { String method = {.size = strlen(name), .data = name}; - channel_write(channel, serialize_request(id, method, arg, &out_buffer, 1)); + channel_write(channel, serialize_request(id, method, args, &out_buffer, 1)); } static void send_event(Channel *channel, char *name, - Object arg) + Array args) { String method = {.size = strlen(name), .data = name}; - channel_write(channel, serialize_request(0, method, arg, &out_buffer, 1)); + channel_write(channel, serialize_request(0, method, args, &out_buffer, 1)); } -static void broadcast_event(char *name, Object arg) +static void broadcast_event(char *name, Array args) { kvec_t(Channel *) subscribed; kv_init(subscribed); @@ -413,14 +441,14 @@ static void broadcast_event(char *name, Object arg) }); if (!kv_size(subscribed)) { - msgpack_rpc_free_object(arg); + msgpack_rpc_free_array(args); goto end; } String method = {.size = strlen(name), .data = name}; WBuffer *buffer = serialize_request(0, method, - arg, + args, &out_buffer, kv_size(subscribed)); @@ -469,7 +497,12 @@ static void close_channel(Channel *channel) } else { rstream_free(channel->data.streams.read); wstream_free(channel->data.streams.write); - uv_close((uv_handle_t *)channel->data.streams.uv, close_cb); + if (channel->data.streams.uv) { + uv_close((uv_handle_t *)channel->data.streams.uv, close_cb); + } else { + // When the stdin channel closes, it's time to go + mch_exit(0); + } } free(channel); diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index aca7005064..bb4e897887 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -258,20 +258,6 @@ int os_file_is_writable(const char *name) return 0; } -/// Get the size of a file in bytes. -/// -/// @param[out] size pointer to an off_t to put the size into. -/// @return `true` for success, `false` for failure. -bool os_get_file_size(const char *name, off_t *size) -{ - uv_stat_t statbuf; - if (os_stat(name, &statbuf)) { - *size = statbuf.st_size; - return true; - } - return false; -} - /// Rename a file or directory. /// /// @return `OK` for success, `FAIL` for failure. @@ -345,7 +331,7 @@ int os_remove(const char *path) /// @param path Path to the file. /// @param[out] file_info Pointer to a FileInfo to put the information in. /// @return `true` on success, `false` for failure. -bool os_get_file_info(const char *path, FileInfo *file_info) +bool os_fileinfo(const char *path, FileInfo *file_info) { return os_stat(path, &(file_info->stat)); } @@ -355,7 +341,7 @@ bool os_get_file_info(const char *path, FileInfo *file_info) /// @param path Path to the file. /// @param[out] file_info Pointer to a FileInfo to put the information in. /// @return `true` on success, `false` for failure. -bool os_get_file_info_link(const char *path, FileInfo *file_info) +bool os_fileinfo_link(const char *path, FileInfo *file_info) { uv_fs_t request; int result = uv_fs_lstat(uv_default_loop(), &request, path, NULL); @@ -369,7 +355,7 @@ bool os_get_file_info_link(const char *path, FileInfo *file_info) /// @param file_descriptor File descriptor of the file. /// @param[out] file_info Pointer to a FileInfo to put the information in. /// @return `true` on success, `false` for failure. -bool os_get_file_info_fd(int file_descriptor, FileInfo *file_info) +bool os_fileinfo_fd(int file_descriptor, FileInfo *file_info) { uv_fs_t request; int result = uv_fs_fstat(uv_default_loop(), &request, file_descriptor, NULL); @@ -381,7 +367,7 @@ bool os_get_file_info_fd(int file_descriptor, FileInfo *file_info) /// Compare the inodes of two FileInfos /// /// @return `true` if the two FileInfos represent the same file. -bool os_file_info_id_equal(const FileInfo *file_info_1, +bool os_fileinfo_id_equal(const FileInfo *file_info_1, const FileInfo *file_info_2) { return file_info_1->stat.st_ino == file_info_2->stat.st_ino @@ -392,7 +378,7 @@ bool os_file_info_id_equal(const FileInfo *file_info_1, /// /// @param file_info Pointer to the `FileInfo` /// @param[out] file_id Pointer to a `FileID` -void os_file_info_get_id(const FileInfo *file_info, FileID *file_id) +void os_fileinfo_id(const FileInfo *file_info, FileID *file_id) { file_id->inode = file_info->stat.st_ino; file_id->device_id = file_info->stat.st_dev; @@ -403,17 +389,44 @@ void os_file_info_get_id(const FileInfo *file_info, FileID *file_id) /// @deprecated Use `FileID` instead, this function is only needed in memline.c /// @param file_info Pointer to the `FileInfo` /// @return the inode number -uint64_t os_file_info_get_inode(const FileInfo *file_info) +uint64_t os_fileinfo_inode(const FileInfo *file_info) { return file_info->stat.st_ino; } +/// Get the size of a file from a `FileInfo`. +/// +/// @return filesize in bytes. +uint64_t os_fileinfo_size(const FileInfo *file_info) + FUNC_ATTR_NONNULL_ALL +{ + return file_info->stat.st_size; +} + +/// Get the number of hardlinks from a `FileInfo`. +/// +/// @return number of hardlinks. +uint64_t os_fileinfo_hardlinks(const FileInfo *file_info) + FUNC_ATTR_NONNULL_ALL +{ + return file_info->stat.st_nlink; +} + +/// Get the blocksize from a `FileInfo`. +/// +/// @return blocksize in bytes. +uint64_t os_fileinfo_blocksize(const FileInfo *file_info) + FUNC_ATTR_NONNULL_ALL +{ + return file_info->stat.st_blksize; +} + /// Get the `FileID` for a given path /// /// @param path Path to the file. /// @param[out] file_info Pointer to a `FileID` to fill in. /// @return `true` on sucess, `false` for failure. -bool os_get_file_id(const char *path, FileID *file_id) +bool os_fileid(const char *path, FileID *file_id) { uv_stat_t statbuf; if (os_stat(path, &statbuf)) { @@ -429,7 +442,7 @@ bool os_get_file_id(const char *path, FileID *file_id) /// @param file_id_1 Pointer to first `FileID` /// @param file_id_2 Pointer to second `FileID` /// @return `true` if the two `FileID`s represent te same file. -bool os_file_id_equal(const FileID *file_id_1, const FileID *file_id_2) +bool os_fileid_equal(const FileID *file_id_1, const FileID *file_id_2) { return file_id_1->inode == file_id_2->inode && file_id_1->device_id == file_id_2->device_id; @@ -440,7 +453,7 @@ bool os_file_id_equal(const FileID *file_id_1, const FileID *file_id_2) /// @param file_id Pointer to a `FileID` /// @param file_info Pointer to a `FileInfo` /// @return `true` if the `FileID` and the `FileInfo` represent te same file. -bool os_file_id_equal_file_info(const FileID *file_id, +bool os_fileid_equal_fileinfo(const FileID *file_id, const FileInfo *file_info) { return file_id->inode == file_info->stat.st_ino diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index 15aebdbf3d..53024d1389 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -6,6 +6,7 @@ #include "nvim/os/input.h" #include "nvim/os/event.h" +#include "nvim/os/signal.h" #include "nvim/os/rstream_defs.h" #include "nvim/os/rstream.h" #include "nvim/ascii.h" @@ -34,6 +35,10 @@ static bool eof = false, started_reading = false; void input_init(void) { + if (embedded_mode) { + return; + } + read_stream = rstream_new(read_cb, READ_BUFFER_SIZE, NULL, NULL); rstream_set_file(read_stream, read_cmd_fd); } @@ -41,18 +46,30 @@ void input_init(void) // Listen for input void input_start(void) { + if (embedded_mode) { + return; + } + rstream_start(read_stream); } // Stop listening for input void input_stop(void) { + if (embedded_mode) { + return; + } + rstream_stop(read_stream); } // Copies (at most `count`) of was read from `read_cmd_fd` into `buf` uint32_t input_read(char *buf, uint32_t count) { + if (embedded_mode) { + return 0; + } + return rstream_read(read_stream, buf, count); } @@ -129,6 +146,11 @@ bool os_isatty(int fd) static bool input_poll(int32_t ms) { + if (embedded_mode) { + EventSource input_sources[] = { signal_event_source(), NULL }; + return event_poll(ms, input_sources); + } + EventSource input_sources[] = { rstream_event_source(read_stream), NULL diff --git a/src/nvim/os/msgpack_rpc.c b/src/nvim/os/msgpack_rpc.c index c03d8dccca..c6e2af2f1c 100644 --- a/src/nvim/os/msgpack_rpc.c +++ b/src/nvim/os/msgpack_rpc.c @@ -39,15 +39,14 @@ WBuffer *msgpack_rpc_call(uint64_t channel_id, return serialize_response(response_id, err, NIL, sbuffer); } - uint64_t method_id = req->via.array.ptr[2].via.u64; - - if (method_id == 0) { + if (req->via.array.ptr[2].type == MSGPACK_OBJECT_POSITIVE_INTEGER + && req->via.array.ptr[2].via.u64 == 0) { return serialize_metadata(response_id, channel_id, sbuffer); } // dispatch the call Error error = { .set = false }; - Object rv = msgpack_rpc_dispatch(channel_id, method_id, req, &error); + Object rv = msgpack_rpc_dispatch(channel_id, req, &error); // send the response msgpack_packer response; msgpack_packer_init(&response, sbuffer, msgpack_sbuffer_write); @@ -119,7 +118,7 @@ void msgpack_rpc_error(char *msg, msgpack_packer *res) /// Serializes a msgpack-rpc request or notification(id == 0) WBuffer *serialize_request(uint64_t request_id, String method, - Object arg, + Array args, msgpack_sbuffer *sbuffer, size_t refcount) FUNC_ATTR_NONNULL_ARG(4) @@ -135,12 +134,12 @@ WBuffer *serialize_request(uint64_t request_id, msgpack_pack_raw(&pac, method.size); msgpack_pack_raw_body(&pac, method.data, method.size); - msgpack_rpc_from_object(arg, &pac); + msgpack_rpc_from_array(args, &pac); WBuffer *rv = wstream_new_buffer(xmemdup(sbuffer->data, sbuffer->size), sbuffer->size, refcount, free); - msgpack_rpc_free_object(arg); + msgpack_rpc_free_array(args); msgpack_sbuffer_clear(sbuffer); return rv; } @@ -235,8 +234,9 @@ static char *msgpack_rpc_validate(uint64_t *response_id, msgpack_object *req) return "Message type must be 0"; } - if (req->via.array.ptr[2].type != MSGPACK_OBJECT_POSITIVE_INTEGER) { - return "Method id must be a positive integer"; + if (req->via.array.ptr[2].type != MSGPACK_OBJECT_POSITIVE_INTEGER + && req->via.array.ptr[2].type != MSGPACK_OBJECT_RAW) { + return "Method must be a positive integer or a string"; } if (req->via.array.ptr[3].type != MSGPACK_OBJECT_ARRAY) { diff --git a/src/nvim/os/msgpack_rpc.h b/src/nvim/os/msgpack_rpc.h index 5aca900d2e..35f175d2a0 100644 --- a/src/nvim/os/msgpack_rpc.h +++ b/src/nvim/os/msgpack_rpc.h @@ -21,6 +21,11 @@ typedef Object (*rpc_method_handler_fn)(uint64_t channel_id, msgpack_object *req, Error *error); + +/// Initializes the msgpack-rpc method table +void msgpack_rpc_init(void); + + /// Dispatches to the actual API function after basic payload validation by /// `msgpack_rpc_call`. It is responsible for validating/converting arguments /// to C types, and converting the return value back to msgpack types. @@ -33,11 +38,11 @@ typedef Object (*rpc_method_handler_fn)(uint64_t channel_id, /// @param error Pointer to error structure /// @return Some object Object msgpack_rpc_dispatch(uint64_t channel_id, - uint64_t method_id, msgpack_object *req, Error *error) FUNC_ATTR_NONNULL_ARG(2) FUNC_ATTR_NONNULL_ARG(3); + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "os/msgpack_rpc.h.generated.h" #endif diff --git a/src/nvim/os/provider.c b/src/nvim/os/provider.c index d94203f683..07e757fe0e 100644 --- a/src/nvim/os/provider.c +++ b/src/nvim/os/provider.c @@ -98,7 +98,7 @@ bool provider_register(char *method, uint64_t channel_id) return true; } -Object provider_call(char *method, Object arg) +Object provider_call(char *method, Array args) { uint64_t channel_id = get_provider_for(method); @@ -109,13 +109,13 @@ Object provider_call(char *method, Object arg) "Provider for \"%s\" is not available", method); report_error(buf); - msgpack_rpc_free_object(arg); + msgpack_rpc_free_array(args); return NIL; } bool error = false; Object result = NIL; - channel_send_call(channel_id, method, arg, &result, &error); + channel_send_call(channel_id, method, args, &result, &error); if (error) { report_error(result.data.string.data); diff --git a/src/nvim/os/signal.c b/src/nvim/os/signal.c index 17f270a5cc..2f93cfb08a 100644 --- a/src/nvim/os/signal.c +++ b/src/nvim/os/signal.c @@ -39,7 +39,10 @@ void signal_init(void) uv_signal_start(&shup, signal_cb, SIGHUP); uv_signal_start(&squit, signal_cb, SIGQUIT); uv_signal_start(&sterm, signal_cb, SIGTERM); - uv_signal_start(&swinch, signal_cb, SIGWINCH); + if (!embedded_mode) { + // TODO(tarruda): There must be an API function for resizing window + uv_signal_start(&swinch, signal_cb, SIGWINCH); + } #ifdef SIGPWR uv_signal_init(uv_default_loop(), &spwr); uv_signal_start(&spwr, signal_cb, SIGPWR); diff --git a/src/nvim/os/wstream.c b/src/nvim/os/wstream.c index 194bf757e4..44463c7c88 100644 --- a/src/nvim/os/wstream.c +++ b/src/nvim/os/wstream.c @@ -1,6 +1,7 @@ #include <assert.h> #include <stdint.h> #include <stdbool.h> +#include <stdlib.h> #include <uv.h> @@ -20,7 +21,7 @@ struct wstream { size_t maxmem; // Number of pending requests size_t pending_reqs; - bool freed; + bool freed, free_handle; // (optional) Write callback and data wstream_cb cb; void *data; @@ -60,6 +61,7 @@ WStream * wstream_new(size_t maxmem) rv->curmem = 0; rv->pending_reqs = 0; rv->freed = false; + rv->free_handle = false; rv->cb = NULL; return rv; @@ -68,9 +70,13 @@ WStream * wstream_new(size_t maxmem) /// Frees all memory allocated for a WStream instance /// /// @param wstream The `WStream` instance -void wstream_free(WStream *wstream) -{ +void wstream_free(WStream *wstream) { if (!wstream->pending_reqs) { + handle_set_wstream((uv_handle_t *)wstream->stream, NULL); + if (wstream->free_handle) { + uv_close((uv_handle_t *)wstream->stream, close_cb); + } + free(wstream); } else { wstream->freed = true; @@ -87,6 +93,24 @@ void wstream_set_stream(WStream *wstream, uv_stream_t *stream) wstream->stream = stream; } +/// Sets the underlying file descriptor that will be written to. Only pipes +/// are supported for now. +/// +/// @param wstream The `WStream` instance +/// @param file The file descriptor +void wstream_set_file(WStream *wstream, uv_file file) +{ + uv_handle_type type = uv_guess_handle(file); + + assert(type == UV_NAMED_PIPE || type == UV_TTY); + wstream->stream = xmalloc(sizeof(uv_pipe_t)); + uv_pipe_init(uv_default_loop(), (uv_pipe_t *)wstream->stream, 0); + uv_pipe_open((uv_pipe_t *)wstream->stream, file); + wstream->stream->data = NULL; + handle_set_wstream((uv_handle_t *)wstream->stream, wstream); + wstream->free_handle = true; +} + /// Sets a callback that will be called on completion of a write request, /// indicating failure/success. /// @@ -211,3 +235,16 @@ static void release_wbuffer(WBuffer *buffer) free(buffer); } } + +static void close_cb(uv_handle_t *handle) +{ + WStream *wstream = handle_get_wstream(handle); + + if (wstream) { + free(wstream); + } + + free(handle->data); + free(handle); +} + diff --git a/src/nvim/os_unix.c b/src/nvim/os_unix.c index af17676ebf..3fa8b803b2 100644 --- a/src/nvim/os_unix.c +++ b/src/nvim/os_unix.c @@ -54,6 +54,7 @@ #include "nvim/os/shell.h" #include "nvim/os/signal.h" #include "nvim/os/job.h" +#include "nvim/os/msgpack_rpc.h" #if defined(HAVE_SYS_IOCTL_H) # include <sys/ioctl.h> @@ -88,6 +89,18 @@ static int did_set_icon = FALSE; */ void mch_write(char_u *s, int len) { + if (embedded_mode) { + // TODO(tarruda): This is a temporary hack to stop Neovim from writing + // messages to stdout in embedded mode. In the future, embedded mode will + // be the only possibility(GUIs will always start neovim with a msgpack-rpc + // over stdio) and this function won't exist. + // + // The reason for this is because before Neovim fully migrates to a + // msgpack-rpc-driven architecture, we must have a fully functional + // UI working + return; + } + ignored = (int)write(1, (char *)s, len); if (p_wd) /* Unix is too fast, slow down a bit more */ os_microdelay(p_wd, false); @@ -152,6 +165,7 @@ void mch_init(void) mac_conv_init(); #endif + msgpack_rpc_init(); event_init(); } @@ -314,7 +328,7 @@ int len /* buffer size, only used when name gets longer */ struct dirent *dp; FileInfo file_info; - if (os_get_file_info_link((char *)name, &file_info)) { + if (os_fileinfo_link((char *)name, &file_info)) { /* Open the directory where the file is located. */ slash = vim_strrchr(name, '/'); if (slash == NULL) { @@ -340,8 +354,8 @@ int len /* buffer size, only used when name gets longer */ STRLCPY(newname + (tail - name), dp->d_name, MAXPATHL - (tail - name) + 1); FileInfo file_info_new; - if (os_get_file_info_link((char *)newname, &file_info_new) - && os_file_info_id_equal(&file_info, &file_info_new)) { + if (os_fileinfo_link((char *)newname, &file_info_new) + && os_fileinfo_id_equal(&file_info, &file_info_new)) { STRCPY(tail, dp->d_name); break; } diff --git a/src/nvim/path.c b/src/nvim/path.c index 0c18ab7bd4..4e05c506f8 100644 --- a/src/nvim/path.c +++ b/src/nvim/path.c @@ -61,10 +61,10 @@ FileComparison path_full_compare(char_u *s1, char_u *s2, int checkname) FileID file_id_1, file_id_2; expand_env(s1, exp1, MAXPATHL); - bool id_ok_1 = os_get_file_id((char *)exp1, &file_id_1); - bool id_ok_2 = os_get_file_id((char *)s2, &file_id_2); + bool id_ok_1 = os_fileid((char *)exp1, &file_id_1); + bool id_ok_2 = os_fileid((char *)s2, &file_id_2); if (!id_ok_1 && !id_ok_2) { - // If os_get_file_id() doesn't work, may compare the names. + // If os_fileid() doesn't work, may compare the names. if (checkname) { vim_FullName(exp1, full1, MAXPATHL, FALSE); vim_FullName(s2, full2, MAXPATHL, FALSE); @@ -77,7 +77,7 @@ FileComparison path_full_compare(char_u *s1, char_u *s2, int checkname) if (!id_ok_1 || !id_ok_2) { return kOneFileMissing; } - if (os_file_id_equal(&file_id_1, &file_id_2)) { + if (os_fileid_equal(&file_id_1, &file_id_2)) { return kEqualFiles; } return kDifferentFiles; @@ -1304,7 +1304,7 @@ void simplify_filename(char_u *filename) saved_char = p[-1]; p[-1] = NUL; FileInfo file_info; - if (!os_get_file_info_link((char *)filename, &file_info)) { + if (!os_fileinfo_link((char *)filename, &file_info)) { do_strip = TRUE; } p[-1] = saved_char; @@ -1327,7 +1327,7 @@ void simplify_filename(char_u *filename) * components. */ saved_char = *tail; *tail = NUL; - if (os_get_file_info((char *)filename, &file_info)) { + if (os_fileinfo((char *)filename, &file_info)) { do_strip = TRUE; } else @@ -1343,15 +1343,15 @@ void simplify_filename(char_u *filename) * component's parent directory.) */ FileInfo new_file_info; if (p == start && relative) { - os_get_file_info(".", &new_file_info); + os_fileinfo(".", &new_file_info); } else { saved_char = *p; *p = NUL; - os_get_file_info((char *)filename, &new_file_info); + os_fileinfo((char *)filename, &new_file_info); *p = saved_char; } - if (!os_file_info_id_equal(&file_info, &new_file_info)) { + if (!os_fileinfo_id_equal(&file_info, &new_file_info)) { do_strip = FALSE; /* We don't disable stripping of later * components since the unstripped path name is diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 2415858e0f..876d4e73d1 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -2564,7 +2564,7 @@ static char_u *get_mef_name(void) STRCAT(name, p + 2); // Don't accept a symbolic link, its a security risk. FileInfo file_info; - bool file_or_link_found = os_get_file_info_link((char *)name, &file_info); + bool file_or_link_found = os_fileinfo_link((char *)name, &file_info); if (!file_or_link_found) { break; } diff --git a/src/nvim/term.c b/src/nvim/term.c index 36e433d624..d2c524e2e8 100644 --- a/src/nvim/term.c +++ b/src/nvim/term.c @@ -2360,6 +2360,9 @@ void set_shellsize(int width, int height, int mustset) */ void settmode(int tmode) { + if (embedded_mode) { + return; + } if (full_screen) { /* diff --git a/src/nvim/testdir/test105.in b/src/nvim/testdir/test105.in index 73d92e899d..bfb4b65fbb 100644 --- a/src/nvim/testdir/test105.in +++ b/src/nvim/testdir/test105.in @@ -7,7 +7,7 @@ STARTTEST :set shellslash :let tab="\t" :command -nargs=1 Put :let expr=<q-args> | $put =expr.tab.strtrans(string(eval(expr))) -:let $HOME=fnamemodify('.', ':p:h:h:h:h') +:let $HOME=fnamemodify('.', ':p:h:h:h') :Put fnamemodify('.', ':p' )[-1:] :Put fnamemodify('.', ':p:h' )[-1:] :Put fnamemodify('test.out', ':p' )[-1:] @@ -23,7 +23,7 @@ STARTTEST :Put fnamemodify('abc.fb2.tar.gz', ':r' ) :Put fnamemodify('abc.fb2.tar.gz', ':r:r' ) :Put fnamemodify('abc.fb2.tar.gz', ':r:r:r' ) -:Put substitute(fnamemodify('abc.fb2.tar.gz', ':p:r:r'), '.*\(src/nvim/testdir/.*\)', '\1', '') +:Put substitute(fnamemodify('abc.fb2.tar.gz', ':p:r:r'), '.*\(nvim/testdir/.*\)', '\1', '') :Put fnamemodify('abc.fb2.tar.gz', ':e' ) :Put fnamemodify('abc.fb2.tar.gz', ':e:e' ) :Put fnamemodify('abc.fb2.tar.gz', ':e:e:e' ) diff --git a/src/nvim/testdir/test105.ok b/src/nvim/testdir/test105.ok index be1eca8f8f..0b30ee4281 100644 --- a/src/nvim/testdir/test105.ok +++ b/src/nvim/testdir/test105.ok @@ -3,8 +3,8 @@ fnamemodify('.', ':p:h' )[-1:] 'r' fnamemodify('test.out', ':p' )[-1:] 't' fnamemodify('test.out', ':.' ) 'test.out' fnamemodify('../testdir/a', ':.' ) 'a' -fnamemodify('test.out', ':~' ) '~/src/nvim/testdir/test.out' -fnamemodify('../testdir/a', ':~' ) '~/src/nvim/testdir/a' +fnamemodify('test.out', ':~' ) '~/nvim/testdir/test.out' +fnamemodify('../testdir/a', ':~' ) '~/nvim/testdir/a' fnamemodify('../testdir/a', ':t' ) 'a' fnamemodify('.', ':p:t' ) '' fnamemodify('test.out', ':p:t' ) 'test.out' @@ -13,7 +13,7 @@ fnamemodify('test.out', ':p:t:e' ) 'out' fnamemodify('abc.fb2.tar.gz', ':r' ) 'abc.fb2.tar' fnamemodify('abc.fb2.tar.gz', ':r:r' ) 'abc.fb2' fnamemodify('abc.fb2.tar.gz', ':r:r:r' ) 'abc' -substitute(fnamemodify('abc.fb2.tar.gz', ':p:r:r'), '.*\(src/nvim/testdir/.*\)', '\1', '') 'src/nvim/testdir/abc.fb2' +substitute(fnamemodify('abc.fb2.tar.gz', ':p:r:r'), '.*\(nvim/testdir/.*\)', '\1', '') 'nvim/testdir/abc.fb2' fnamemodify('abc.fb2.tar.gz', ':e' ) 'gz' fnamemodify('abc.fb2.tar.gz', ':e:e' ) 'tar.gz' fnamemodify('abc.fb2.tar.gz', ':e:e:e' ) 'fb2.tar.gz' diff --git a/src/nvim/undo.c b/src/nvim/undo.c index 8c7b5b38e9..d7a691aa83 100644 --- a/src/nvim/undo.c +++ b/src/nvim/undo.c @@ -1116,8 +1116,8 @@ void u_write_undo(char_u *name, int forceit, buf_T *buf, char_u *hash) */ FileInfo file_info_old; FileInfo file_info_new; - if (os_get_file_info((char *)buf->b_ffname, &file_info_old) - && os_get_file_info((char *)file_name, &file_info_new) + if (os_fileinfo((char *)buf->b_ffname, &file_info_old) + && os_fileinfo((char *)file_name, &file_info_new) && file_info_old.stat.st_gid != file_info_new.stat.st_gid && os_fchown(fd, -1, file_info_old.stat.st_gid) != 0) { os_setperm(file_name, (perm & 0707) | ((perm & 07) << 3)); @@ -1249,8 +1249,8 @@ void u_read_undo(char_u *name, char_u *hash, char_u *orig_name) * owner of the text file or equal to the current user. */ FileInfo file_info_orig; FileInfo file_info_undo; - if (os_get_file_info((char *)orig_name, &file_info_orig) - && os_get_file_info((char *)file_name, &file_info_undo) + if (os_fileinfo((char *)orig_name, &file_info_orig) + && os_fileinfo((char *)file_name, &file_info_undo) && file_info_orig.stat.st_uid != file_info_undo.stat.st_uid && file_info_undo.stat.st_uid != getuid()) { if (p_verbose > 0) { diff --git a/src/nvim/version.c b/src/nvim/version.c index 8132d5dfcc..75b4ac4b4d 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -375,7 +375,7 @@ static int included_patches[] = { //223 NA //222 NA 221, - //220, + 220, 219, 218, //217 NA |