Skip to content

Commit

Permalink
Add vifm.stdout() function
Browse files Browse the repository at this point in the history
It returns stream to which Vifm's output was redirected (if it was
redirected, i.e. original output wasn't connected to a TTY or character
device on Windows).

Thanks to gruvw.

See https://q2a.vifm.info/1400/always-enable-choosedir
  • Loading branch information
xaizek committed Nov 7, 2023
1 parent adb8cd7 commit 60704b7
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 1 deletion.
4 changes: 4 additions & 0 deletions ChangeLog.LuaAPI
Expand Up @@ -28,6 +28,10 @@ documented in the regular ChangeLog.
Added vifm.abbrevs.add() that registers command-line abbreviations. Patch
by filterfalse.

Added vifm.stdout() to return stream to which Vifm's output was
redirected (if it was redirected, i.e. original output wasn't connected to
a TTY or character device on Windows). Thanks to gruvw.

0.13-beta to 0.13 (2023-04-04)

Added VifmView:select() and VifmView:unselect() that select and unselect
Expand Down
10 changes: 9 additions & 1 deletion data/vim/doc/app/vifm-lua.txt
@@ -1,4 +1,4 @@
*vifm-lua.txt* For Vifm version 1.0 Last change: 2023 Sep 26
*vifm-lua.txt* For Vifm version 1.0 Last change: 2023 Nov 7

Email for bugs and suggestions: <xaizek@posteo.net>

Expand Down Expand Up @@ -718,6 +718,14 @@ Return:~
Raises an error:~
If "iomode" has incorrect value.

vifm.stdout() *vifm-l_vifm.stdout()*
Retrieves stream to which Vifm's standard stream was redirected.

Return:~
The stream that can't be closed or `nil` if output stream wasn't redirected
to a TTY (character device on Windows). In the former case the same stream
is returned on each call.

vifm.input({info}) *vifm-l_vifm.input()*
Prompts user for input via command-line prompt.

Expand Down
47 changes: 47 additions & 0 deletions src/lua/vifm.c
Expand Up @@ -18,6 +18,8 @@

#include "vifm.h"

#include <unistd.h> /* isatty() */

#include "../cfg/info.h"
#include "../engine/options.h"
#include "../modes/dialogs/msg_dialog.h"
Expand Down Expand Up @@ -77,6 +79,8 @@ static int VLUA_API(vifm_input)(lua_State *lua);
static int VLUA_API(vifm_makepath)(lua_State *lua);
static int VLUA_API(vifm_run)(lua_State *lua);
static int VLUA_API(vifm_sessions_current)(lua_State *lua);
static int VLUA_API(vifm_stdout)(lua_State *lua);
static int VLUA_IMPL(stdout_closef)(lua_State *lua);

static int VLUA_API(api_is_at_least)(lua_State *lua);
static int VLUA_API(api_has)(lua_State *lua);
Expand All @@ -98,6 +102,7 @@ VLUA_DECLARE_SAFE(vifm_input);
VLUA_DECLARE_SAFE(vifm_makepath);
VLUA_DECLARE_SAFE(vifm_run);
VLUA_DECLARE_SAFE(vifm_sessions_current);
VLUA_DECLARE_SAFE(vifm_stdout);

VLUA_DECLARE_SAFE(api_is_at_least);
VLUA_DECLARE_SAFE(api_has);
Expand Down Expand Up @@ -129,6 +134,7 @@ static const struct luaL_Reg vifm_methods[] = {
{ "input", VLUA_REF(vifm_input) },
{ "makepath", VLUA_REF(vifm_makepath) },
{ "run", VLUA_REF(vifm_run) },
{ "stdout", VLUA_REF(vifm_stdout) },

/* Defined in other units. */
{ "addcolumntype", VLUA_REF(vifm_addcolumntype) },
Expand Down Expand Up @@ -418,6 +424,47 @@ VLUA_API(vifm_run)(lua_State *lua)
return 1;
}

/* Member of `vifm` that retrieves stream associated with application's output.
* Returns file stream object compatible with I/O library that is always the
* same and that cannot be closed. */
static int
VLUA_API(vifm_stdout)(lua_State *lua)
{
static char stdout_key;

if(isatty(fileno(curr_stats.original_stdout)))
{
lua_pushnil(lua);
return 1;
}

from_pointer(lua, &stdout_key);
if(lua_isnil(lua, -1))
{
luaL_Stream *stream = lua_newuserdatauv(lua, sizeof(*stream), 0);
stream->closef = VLUA_IREF(stdout_closef);
luaL_setmetatable(lua, LUA_FILEHANDLE);
stream->f = curr_stats.original_stdout;

set_pointer(lua, &stdout_key);
}

return 1;
}

/* Custom destructor for luaL_Stream that prevents closing the stream. Always
* raises an error. */
static int
VLUA_IMPL(stdout_closef)(lua_State *lua)
{
luaL_Stream *stream = luaL_checkudata(lua, 1, LUA_FILEHANDLE);
stream->closef = VLUA_IREF(stdout_closef);

luaL_pushfail(lua);
lua_pushliteral(lua, "cannot close standard file");
return 1;
}

/* Member of `vifm.sessions` that retrieves name of the current session.
* Returns string or nil. */
static int
Expand Down
1 change: 1 addition & 0 deletions src/tags.c
Expand Up @@ -768,6 +768,7 @@ const char *tags[] = {
"vifm-l_vifm.sessions",
"vifm-l_vifm.sessions.current",
"vifm-l_vifm.startjob()",
"vifm-l_vifm.stdout()",
"vifm-l_vifm.tabs",
"vifm-l_vifm.tabs.get()",
"vifm-l_vifm.tabs.getcount()",
Expand Down
26 changes: 26 additions & 0 deletions tests/lua/api.c
@@ -1,5 +1,7 @@
#include <stic.h>

#include <stdio.h> /* fclose() fopen() */

#include "../../src/cfg/config.h"
#include "../../src/engine/keys.h"
#include "../../src/engine/variables.h"
Expand Down Expand Up @@ -288,5 +290,29 @@ TEST(vifm_input)
view_teardown(&rwin);
}

TEST(vifm_stdout)
{
curr_stats.original_stdout = fopen(SANDBOX_PATH "/out", "w");
assert_non_null(curr_stats.original_stdout);

GLUA_EQ(vlua, "true",
"print(vifm.stdout() ~= nil)");

GLUA_EQ(vlua, "true",
"stream = vifm.stdout()"
"print(stream == vifm.stdout())");

GLUA_EQ(vlua, "",
"vifm.stdout():write('test')");

fclose(curr_stats.original_stdout);
curr_stats.original_stdout = NULL;

const char *lines[] = { "test" };
file_is(SANDBOX_PATH "/out", lines, 1);

remove_file(SANDBOX_PATH "/out");
}

/* vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab cinoptions-=(0 : */
/* vim: set cinoptions+=t0 : */

0 comments on commit 60704b7

Please sign in to comment.