diff options
author | b-r-o-c-k <brockmammen@gmail.com> | 2018-04-14 14:17:51 -0500 |
---|---|---|
committer | b-r-o-c-k <brockmammen@gmail.com> | 2018-04-14 14:17:51 -0500 |
commit | ad999eaa775d7d4b0cacedb30c6ea3a0ee699a6f (patch) | |
tree | 92de2079e80f5f289dd87a54af123cb7d90c3058 /src/nvim/lua | |
parent | 78bc52ea5397c092d01cd08296fe1dc85d998329 (diff) | |
parent | ef4feab0e75be19c5f41d70a001db980b72090f5 (diff) | |
download | rneovim-ad999eaa775d7d4b0cacedb30c6ea3a0ee699a6f.tar.gz rneovim-ad999eaa775d7d4b0cacedb30c6ea3a0ee699a6f.tar.bz2 rneovim-ad999eaa775d7d4b0cacedb30c6ea3a0ee699a6f.zip |
Merge branch 'master' into s-dash-stdin
Diffstat (limited to 'src/nvim/lua')
-rw-r--r-- | src/nvim/lua/converter.c | 51 | ||||
-rw-r--r-- | src/nvim/lua/executor.c | 438 | ||||
-rw-r--r-- | src/nvim/lua/vim.lua | 68 |
3 files changed, 247 insertions, 310 deletions
diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c index cacba3ce87..5da6d2c0a0 100644 --- a/src/nvim/lua/converter.c +++ b/src/nvim/lua/converter.c @@ -211,20 +211,28 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv) size_t len; const char *s = lua_tolstring(lstate, -2, &len); if (cur.special) { - list_T *const kv_pair = tv_list_alloc(); - tv_list_append_list(cur.tv->vval.v_list, kv_pair); - listitem_T *const key = tv_list_item_alloc(); - key->li_tv = decode_string(s, len, kTrue, false, false); - tv_list_append(kv_pair, key); - if (key->li_tv.v_type == VAR_UNKNOWN) { + list_T *const kv_pair = tv_list_alloc(2); + + typval_T s_tv = decode_string(s, len, kTrue, false, false); + if (s_tv.v_type == VAR_UNKNOWN) { ret = false; tv_list_unref(kv_pair); continue; } - listitem_T *const val = tv_list_item_alloc(); - tv_list_append(kv_pair, val); + tv_list_append_owned_tv(kv_pair, s_tv); + + // Value: not populated yet, need to create list item to push. + tv_list_append_owned_tv(kv_pair, (typval_T) { + .v_type = VAR_UNKNOWN, + }); kv_push(stack, cur); - cur = (TVPopStackItem) { &val->li_tv, false, false, 0 }; + tv_list_append_list(cur.tv->vval.v_list, kv_pair); + cur = (TVPopStackItem) { + .tv = TV_LIST_ITEM_TV(tv_list_last(kv_pair)), + .container = false, + .special = false, + .idx = 0, + }; } else { dictitem_T *const di = tv_dict_item_alloc_len(s, len); if (tv_dict_add(cur.tv->vval.v_dict, di) == FAIL) { @@ -239,15 +247,23 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv) } } else { assert(cur.tv->v_type == VAR_LIST); - lua_rawgeti(lstate, -1, cur.tv->vval.v_list->lv_len + 1); + lua_rawgeti(lstate, -1, tv_list_len(cur.tv->vval.v_list) + 1); if (lua_isnil(lstate, -1)) { lua_pop(lstate, 2); continue; } - listitem_T *const li = tv_list_item_alloc(); - tv_list_append(cur.tv->vval.v_list, li); + // Not populated yet, need to create list item to push. + tv_list_append_owned_tv(cur.tv->vval.v_list, (typval_T) { + .v_type = VAR_UNKNOWN, + }); kv_push(stack, cur); - cur = (TVPopStackItem) { &li->li_tv, false, false, 0 }; + // TODO(ZyX-I): Use indexes, here list item *will* be reallocated. + cur = (TVPopStackItem) { + .tv = TV_LIST_ITEM_TV(tv_list_last(cur.tv->vval.v_list)), + .container = false, + .special = false, + .idx = 0, + }; } } assert(!cur.container); @@ -305,8 +321,8 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv) switch (table_props.type) { case kObjectTypeArray: { cur.tv->v_type = VAR_LIST; - cur.tv->vval.v_list = tv_list_alloc(); - cur.tv->vval.v_list->lv_refcount++; + cur.tv->vval.v_list = tv_list_alloc((ptrdiff_t)table_props.maxidx); + tv_list_ref(cur.tv->vval.v_list); if (table_props.maxidx != 0) { cur.container = true; cur.idx = lua_gettop(lstate); @@ -322,7 +338,8 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv) } else { cur.special = table_props.has_string_with_nul; if (table_props.has_string_with_nul) { - decode_create_map_special_dict(cur.tv); + decode_create_map_special_dict( + cur.tv, (ptrdiff_t)table_props.string_keys_num); assert(cur.tv->v_type == VAR_DICT); dictitem_T *const val_di = tv_dict_find(cur.tv->vval.v_dict, S_LEN("_VAL")); @@ -406,7 +423,7 @@ nlua_pop_typval_table_processing_end: #define TYPVAL_ENCODE_CONV_STR_STRING TYPVAL_ENCODE_CONV_STRING #define TYPVAL_ENCODE_CONV_EXT_STRING(tv, str, len, type) \ - TYPVAL_ENCODE_CONV_NIL() + TYPVAL_ENCODE_CONV_NIL(tv) #define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \ do { \ diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 8e7b8a1824..02eabb9c89 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -40,66 +40,6 @@ typedef struct { /// Name of the run code for use in messages #define NLUA_EVAL_NAME "<VimL compiled string>" -/// Call C function which does not expect any arguments -/// -/// @param function Called function -/// @param numret Number of returned arguments -#define NLUA_CALL_C_FUNCTION_0(lstate, function, numret) \ - do { \ - lua_pushcfunction(lstate, &function); \ - lua_call(lstate, 0, numret); \ - } while (0) -/// Call C function which expects one argument -/// -/// @param function Called function -/// @param numret Number of returned arguments -/// @param a… Supplied argument (should be a void* pointer) -#define NLUA_CALL_C_FUNCTION_1(lstate, function, numret, a1) \ - do { \ - lua_pushcfunction(lstate, &function); \ - lua_pushlightuserdata(lstate, a1); \ - lua_call(lstate, 1, numret); \ - } while (0) -/// Call C function which expects two arguments -/// -/// @param function Called function -/// @param numret Number of returned arguments -/// @param a… Supplied argument (should be a void* pointer) -#define NLUA_CALL_C_FUNCTION_2(lstate, function, numret, a1, a2) \ - do { \ - lua_pushcfunction(lstate, &function); \ - lua_pushlightuserdata(lstate, a1); \ - lua_pushlightuserdata(lstate, a2); \ - lua_call(lstate, 2, numret); \ - } while (0) -/// Call C function which expects three arguments -/// -/// @param function Called function -/// @param numret Number of returned arguments -/// @param a… Supplied argument (should be a void* pointer) -#define NLUA_CALL_C_FUNCTION_3(lstate, function, numret, a1, a2, a3) \ - do { \ - lua_pushcfunction(lstate, &function); \ - lua_pushlightuserdata(lstate, a1); \ - lua_pushlightuserdata(lstate, a2); \ - lua_pushlightuserdata(lstate, a3); \ - lua_call(lstate, 3, numret); \ - } while (0) -/// Call C function which expects five arguments -/// -/// @param function Called function -/// @param numret Number of returned arguments -/// @param a… Supplied argument (should be a void* pointer) -#define NLUA_CALL_C_FUNCTION_4(lstate, function, numret, a1, a2, a3, a4) \ - do { \ - lua_pushcfunction(lstate, &function); \ - lua_pushlightuserdata(lstate, a1); \ - lua_pushlightuserdata(lstate, a2); \ - lua_pushlightuserdata(lstate, a3); \ - lua_pushlightuserdata(lstate, a4); \ - lua_call(lstate, 4, numret); \ - } while (0) - /// Convert lua error into a Vim error message /// /// @param lstate Lua interpreter state. @@ -163,123 +103,6 @@ static int nlua_stricmp(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL return 1; } -/// Evaluate lua string -/// -/// Expects two values on the stack: string to evaluate, pointer to the -/// location where result is saved. Always returns nothing (from the lua point -/// of view). -static int nlua_exec_lua_string(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL -{ - const String *const str = (const String *)lua_touserdata(lstate, 1); - typval_T *const ret_tv = (typval_T *)lua_touserdata(lstate, 2); - lua_pop(lstate, 2); - - if (luaL_loadbuffer(lstate, str->data, str->size, NLUA_EVAL_NAME)) { - nlua_error(lstate, _("E5104: Error while creating lua chunk: %.*s")); - return 0; - } - if (lua_pcall(lstate, 0, 1, 0)) { - nlua_error(lstate, _("E5105: Error while calling lua chunk: %.*s")); - return 0; - } - if (!nlua_pop_typval(lstate, ret_tv)) { - return 0; - } - return 0; -} - -/// Evaluate lua string for each line in range -/// -/// Expects two values on the stack: string to evaluate and pointer to integer -/// array with line range. Always returns nothing (from the lua point of view). -static int nlua_exec_luado_string(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL -{ - const String *const str = (const String *)lua_touserdata(lstate, 1); - const linenr_T *const range = (const linenr_T *)lua_touserdata(lstate, 2); - lua_pop(lstate, 2); - -#define DOSTART "return function(line, linenr) " -#define DOEND " end" - const size_t lcmd_len = (str->size - + (sizeof(DOSTART) - 1) - + (sizeof(DOEND) - 1)); - char *lcmd; - if (lcmd_len < IOSIZE) { - lcmd = (char *)IObuff; - } else { - lcmd = xmalloc(lcmd_len + 1); - } - memcpy(lcmd, DOSTART, sizeof(DOSTART) - 1); - memcpy(lcmd + sizeof(DOSTART) - 1, str->data, str->size); - memcpy(lcmd + sizeof(DOSTART) - 1 + str->size, DOEND, sizeof(DOEND) - 1); -#undef DOSTART -#undef DOEND - - if (luaL_loadbuffer(lstate, lcmd, lcmd_len, NLUA_EVAL_NAME)) { - nlua_error(lstate, _("E5109: Error while creating lua chunk: %.*s")); - if (lcmd_len >= IOSIZE) { - xfree(lcmd); - } - return 0; - } - if (lcmd_len >= IOSIZE) { - xfree(lcmd); - } - if (lua_pcall(lstate, 0, 1, 0)) { - nlua_error(lstate, _("E5110: Error while creating lua function: %.*s")); - return 0; - } - for (linenr_T l = range[0]; l <= range[1]; l++) { - if (l > curbuf->b_ml.ml_line_count) { - break; - } - lua_pushvalue(lstate, -1); - lua_pushstring(lstate, (const char *)ml_get_buf(curbuf, l, false)); - lua_pushnumber(lstate, (lua_Number)l); - if (lua_pcall(lstate, 2, 1, 0)) { - nlua_error(lstate, _("E5111: Error while calling lua function: %.*s")); - break; - } - if (lua_isstring(lstate, -1)) { - size_t new_line_len; - const char *const new_line = lua_tolstring(lstate, -1, &new_line_len); - char *const new_line_transformed = xmemdupz(new_line, new_line_len); - for (size_t i = 0; i < new_line_len; i++) { - if (new_line_transformed[i] == NUL) { - new_line_transformed[i] = '\n'; - } - } - ml_replace(l, (char_u *)new_line_transformed, false); - changed_bytes(l, 0); - } - lua_pop(lstate, 1); - } - lua_pop(lstate, 1); - check_cursor(); - update_screen(NOT_VALID); - return 0; -} - -/// Evaluate lua file -/// -/// Expects one value on the stack: file to evaluate. Always returns nothing -/// (from the lua point of view). -static int nlua_exec_lua_file(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL -{ - const char *const filename = (const char *)lua_touserdata(lstate, 1); - lua_pop(lstate, 1); - - if (luaL_loadfile(lstate, filename)) { - nlua_error(lstate, _("E5112: Error while creating lua chunk: %.*s")); - return 0; - } - if (lua_pcall(lstate, 0, 0, 0)) { - nlua_error(lstate, _("E5113: Error while calling lua chunk: %.*s")); - return 0; - } - return 0; -} - /// Initialize lua interpreter state /// /// Called by lua interpreter itself to initialize state. @@ -327,7 +150,7 @@ static lua_State *nlua_init(void) preserve_exit(); } luaL_openlibs(lstate); - NLUA_CALL_C_FUNCTION_0(lstate, nlua_state_init, 0); + nlua_state_init(lstate); return lstate; } @@ -378,108 +201,18 @@ static lua_State *nlua_enter(void) void executor_exec_lua(const String str, typval_T *const ret_tv) FUNC_ATTR_NONNULL_ALL { - NLUA_CALL_C_FUNCTION_2(nlua_enter(), nlua_exec_lua_string, 0, - (void *)&str, ret_tv); -} + lua_State *const lstate = nlua_enter(); -/// Evaluate lua string -/// -/// Used for luaeval(). Expects three values on the stack: -/// -/// 1. String to evaluate. -/// 2. _A value. -/// 3. Pointer to location where result is saved. -/// -/// @param[in,out] lstate Lua interpreter state. -static int nlua_eval_lua_string(lua_State *const lstate) - FUNC_ATTR_NONNULL_ALL -{ - const String *const str = (const String *)lua_touserdata(lstate, 1); - typval_T *const arg = (typval_T *)lua_touserdata(lstate, 2); - typval_T *const ret_tv = (typval_T *)lua_touserdata(lstate, 3); - lua_pop(lstate, 3); - - garray_T str_ga; - ga_init(&str_ga, 1, 80); -#define EVALHEADER "local _A=select(1,...) return (" - const size_t lcmd_len = sizeof(EVALHEADER) - 1 + str->size + 1; - char *lcmd; - if (lcmd_len < IOSIZE) { - lcmd = (char *)IObuff; - } else { - lcmd = xmalloc(lcmd_len); - } - memcpy(lcmd, EVALHEADER, sizeof(EVALHEADER) - 1); - memcpy(lcmd + sizeof(EVALHEADER) - 1, str->data, str->size); - lcmd[lcmd_len - 1] = ')'; -#undef EVALHEADER - if (luaL_loadbuffer(lstate, lcmd, lcmd_len, NLUA_EVAL_NAME)) { - nlua_error(lstate, - _("E5107: Error while creating lua chunk for luaeval(): %.*s")); - if (lcmd != (char *)IObuff) { - xfree(lcmd); - } - return 0; - } - if (lcmd != (char *)IObuff) { - xfree(lcmd); - } - - if (arg == NULL || arg->v_type == VAR_UNKNOWN) { - lua_pushnil(lstate); - } else { - nlua_push_typval(lstate, arg); - } - if (lua_pcall(lstate, 1, 1, 0)) { - nlua_error(lstate, - _("E5108: Error while calling lua chunk for luaeval(): %.*s")); - return 0; - } - if (!nlua_pop_typval(lstate, ret_tv)) { - return 0; - } - - return 0; -} - -/// Evaluate lua string -/// -/// Expects four values on the stack: string to evaluate, pointer to args array, -/// and locations where result and error are saved, respectively. Always -/// returns nothing (from the lua point of view). -static int nlua_exec_lua_string_api(lua_State *const lstate) - FUNC_ATTR_NONNULL_ALL -{ - const String *str = (const String *)lua_touserdata(lstate, 1); - const Array *args = (const Array *)lua_touserdata(lstate, 2); - Object *retval = (Object *)lua_touserdata(lstate, 3); - Error *err = (Error *)lua_touserdata(lstate, 4); - - lua_pop(lstate, 4); - - if (luaL_loadbuffer(lstate, str->data, str->size, "<nvim>")) { - size_t len; - const char *str = lua_tolstring(lstate, -1, &len); - api_set_error(err, kErrorTypeValidation, - "Error loading lua: %.*s", (int)len, str); - return 0; - } - - for (size_t i = 0; i < args->size; i++) { - nlua_push_Object(lstate, args->items[i]); + if (luaL_loadbuffer(lstate, str.data, str.size, NLUA_EVAL_NAME)) { + nlua_error(lstate, _("E5104: Error while creating lua chunk: %.*s")); + return; } - - if (lua_pcall(lstate, (int)args->size, 1, 0)) { - size_t len; - const char *str = lua_tolstring(lstate, -1, &len); - api_set_error(err, kErrorTypeException, - "Error executing lua: %.*s", (int)len, str); - return 0; + if (lua_pcall(lstate, 0, 1, 0)) { + nlua_error(lstate, _("E5105: Error while calling lua chunk: %.*s")); + return; } - *retval = nlua_pop_Object(lstate, err); - - return 0; + nlua_pop_typval(lstate, ret_tv); } /// Print as a Vim message @@ -617,8 +350,46 @@ void executor_eval_lua(const String str, typval_T *const arg, typval_T *const ret_tv) FUNC_ATTR_NONNULL_ALL { - NLUA_CALL_C_FUNCTION_3(nlua_enter(), nlua_eval_lua_string, 0, - (void *)&str, arg, ret_tv); + lua_State *const lstate = nlua_enter(); + + garray_T str_ga; + ga_init(&str_ga, 1, 80); +#define EVALHEADER "local _A=select(1,...) return (" + const size_t lcmd_len = sizeof(EVALHEADER) - 1 + str.size + 1; + char *lcmd; + if (lcmd_len < IOSIZE) { + lcmd = (char *)IObuff; + } else { + lcmd = xmalloc(lcmd_len); + } + memcpy(lcmd, EVALHEADER, sizeof(EVALHEADER) - 1); + memcpy(lcmd + sizeof(EVALHEADER) - 1, str.data, str.size); + lcmd[lcmd_len - 1] = ')'; +#undef EVALHEADER + if (luaL_loadbuffer(lstate, lcmd, lcmd_len, NLUA_EVAL_NAME)) { + nlua_error(lstate, + _("E5107: Error while creating lua chunk for luaeval(): %.*s")); + if (lcmd != (char *)IObuff) { + xfree(lcmd); + } + return; + } + if (lcmd != (char *)IObuff) { + xfree(lcmd); + } + + if (arg->v_type == VAR_UNKNOWN) { + lua_pushnil(lstate); + } else { + nlua_push_typval(lstate, arg); + } + if (lua_pcall(lstate, 1, 1, 0)) { + nlua_error(lstate, + _("E5108: Error while calling lua chunk for luaeval(): %.*s")); + return; + } + + nlua_pop_typval(lstate, ret_tv); } /// Execute lua string @@ -632,10 +403,29 @@ void executor_eval_lua(const String str, typval_T *const arg, /// @return Return value of the execution. Object executor_exec_lua_api(const String str, const Array args, Error *err) { - Object retval = NIL; - NLUA_CALL_C_FUNCTION_4(nlua_enter(), nlua_exec_lua_string_api, 0, - (void *)&str, (void *)&args, &retval, err); - return retval; + lua_State *const lstate = nlua_enter(); + + if (luaL_loadbuffer(lstate, str.data, str.size, "<nvim>")) { + size_t len; + const char *errstr = lua_tolstring(lstate, -1, &len); + api_set_error(err, kErrorTypeValidation, + "Error loading lua: %.*s", (int)len, errstr); + return NIL; + } + + for (size_t i = 0; i < args.size; i++) { + nlua_push_Object(lstate, args.items[i]); + } + + if (lua_pcall(lstate, (int)args.size, 1, 0)) { + size_t len; + const char *errstr = lua_tolstring(lstate, -1, &len); + api_set_error(err, kErrorTypeException, + "Error executing lua: %.*s", (int)len, errstr); + return NIL; + } + + return nlua_pop_Object(lstate, err); } @@ -671,13 +461,70 @@ void ex_luado(exarg_T *const eap) EMSG(_("cannot save undo information")); return; } - const String cmd = { - .size = STRLEN(eap->arg), - .data = (char *)eap->arg, - }; - const linenr_T range[] = { eap->line1, eap->line2 }; - NLUA_CALL_C_FUNCTION_2(nlua_enter(), nlua_exec_luado_string, 0, - (void *)&cmd, (void *)range); + const char *const cmd = (const char *)eap->arg; + const size_t cmd_len = strlen(cmd); + + lua_State *const lstate = nlua_enter(); + +#define DOSTART "return function(line, linenr) " +#define DOEND " end" + const size_t lcmd_len = (cmd_len + + (sizeof(DOSTART) - 1) + + (sizeof(DOEND) - 1)); + char *lcmd; + if (lcmd_len < IOSIZE) { + lcmd = (char *)IObuff; + } else { + lcmd = xmalloc(lcmd_len + 1); + } + memcpy(lcmd, DOSTART, sizeof(DOSTART) - 1); + memcpy(lcmd + sizeof(DOSTART) - 1, cmd, cmd_len); + memcpy(lcmd + sizeof(DOSTART) - 1 + cmd_len, DOEND, sizeof(DOEND) - 1); +#undef DOSTART +#undef DOEND + + if (luaL_loadbuffer(lstate, lcmd, lcmd_len, NLUA_EVAL_NAME)) { + nlua_error(lstate, _("E5109: Error while creating lua chunk: %.*s")); + if (lcmd_len >= IOSIZE) { + xfree(lcmd); + } + return; + } + if (lcmd_len >= IOSIZE) { + xfree(lcmd); + } + if (lua_pcall(lstate, 0, 1, 0)) { + nlua_error(lstate, _("E5110: Error while creating lua function: %.*s")); + return; + } + for (linenr_T l = eap->line1; l <= eap->line2; l++) { + if (l > curbuf->b_ml.ml_line_count) { + break; + } + lua_pushvalue(lstate, -1); + lua_pushstring(lstate, (const char *)ml_get_buf(curbuf, l, false)); + lua_pushnumber(lstate, (lua_Number)l); + if (lua_pcall(lstate, 2, 1, 0)) { + nlua_error(lstate, _("E5111: Error while calling lua function: %.*s")); + break; + } + if (lua_isstring(lstate, -1)) { + size_t new_line_len; + const char *const new_line = lua_tolstring(lstate, -1, &new_line_len); + char *const new_line_transformed = xmemdupz(new_line, new_line_len); + for (size_t i = 0; i < new_line_len; i++) { + if (new_line_transformed[i] == NUL) { + new_line_transformed[i] = '\n'; + } + } + ml_replace(l, (char_u *)new_line_transformed, false); + changed_bytes(l, 0); + } + lua_pop(lstate, 1); + } + lua_pop(lstate, 1); + check_cursor(); + update_screen(NOT_VALID); } /// Run lua file @@ -688,6 +535,15 @@ void ex_luado(exarg_T *const eap) void ex_luafile(exarg_T *const eap) FUNC_ATTR_NONNULL_ALL { - NLUA_CALL_C_FUNCTION_1(nlua_enter(), nlua_exec_lua_file, 0, - (void *)eap->arg); + lua_State *const lstate = nlua_enter(); + + if (luaL_loadfile(lstate, (const char *)eap->arg)) { + nlua_error(lstate, _("E5112: Error while creating lua chunk: %.*s")); + return; + } + + if (lua_pcall(lstate, 0, 0, 0)) { + nlua_error(lstate, _("E5113: Error while calling lua chunk: %.*s")); + return; + } } diff --git a/src/nvim/lua/vim.lua b/src/nvim/lua/vim.lua index c7952520b0..e1bbb03d3f 100644 --- a/src/nvim/lua/vim.lua +++ b/src/nvim/lua/vim.lua @@ -1,3 +1,62 @@ +-- Internal-only until comments in #8107 are addressed. +-- Returns: +-- {errcode}, {output} +local function _system(cmd) + local out = vim.api.nvim_call_function('system', { cmd }) + local err = vim.api.nvim_get_vvar('shell_error') + return err, out +end + +-- Gets process info from the `ps` command. +-- Used by nvim_get_proc() as a fallback. +local function _os_proc_info(pid) + if pid == nil or pid <= 0 or type(pid) ~= 'number' then + error('invalid pid') + end + local cmd = { 'ps', '-p', pid, '-o', 'ucomm=', } + local err, name = _system(cmd) + if 1 == err and string.gsub(name, '%s*', '') == '' then + return {} -- Process not found. + elseif 0 ~= err then + local args_str = vim.api.nvim_call_function('string', { cmd }) + error('command failed: '..args_str) + end + local _, ppid = _system({ 'ps', '-p', pid, '-o', 'ppid=', }) + -- Remove trailing whitespace. + name = string.gsub(name, '%s+$', '') + ppid = string.gsub(ppid, '%s+$', '') + ppid = tonumber(ppid) == nil and -1 or tonumber(ppid) + return { + name = name, + pid = pid, + ppid = ppid, + } +end + +-- Gets process children from the `pgrep` command. +-- Used by nvim_get_proc_children() as a fallback. +local function _os_proc_children(ppid) + if ppid == nil or ppid <= 0 or type(ppid) ~= 'number' then + error('invalid ppid') + end + local cmd = { 'pgrep', '-P', ppid, } + local err, rv = _system(cmd) + if 1 == err and string.gsub(rv, '%s*', '') == '' then + return {} -- Process not found. + elseif 0 ~= err then + local args_str = vim.api.nvim_call_function('string', { cmd }) + error('command failed: '..args_str) + end + local children = {} + for s in string.gmatch(rv, '%S+') do + local i = tonumber(s) + if i ~= nil then + table.insert(children, i) + end + end + return children +end + -- TODO(ZyX-I): Create compatibility layer. --{{{1 package.path updater function -- Last inserted paths. Used to clear out items from package.[c]path when they @@ -58,7 +117,12 @@ local function _update_package_paths() end last_nvim_paths = cur_nvim_paths end ---{{{1 Module definition -return { + +local module = { _update_package_paths = _update_package_paths, + _os_proc_children = _os_proc_children, + _os_proc_info = _os_proc_info, + _system = _system, } + +return module |