xaizek / vifm (License: GPLv2+) (since 2018-12-07)
Vifm is a file manager with curses interface, which provides Vi[m]-like environment for managing objects within file systems, extended with some useful ideas from mutt.
<root> / src / lua / vifmentry.c (1263c8e8f7eb087ee15800c3435152b60c75ae91) (5,069B) (mode 100644) [raw]
/* vifm
 * Copyright (C) 2021 xaizek.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include "vifmentry.h"

#include <stdlib.h> /* free() */
#include <string.h> /* strdup() */

#include "../int/file_magic.h"
#include "../ui/ui.h"
#include "../utils/fs.h"
#include "../filelist.h"
#include "../types.h"
#include "lua/lauxlib.h"
#include "lua/lua.h"
#include "api.h"
#include "common.h"

/* User data of view entry object. */
typedef struct
{
	char *full_path; /* Full path to the file. */
	FileType type;   /* Type of the file. */
}
vifm_entry_t;

static int VLUA_API(vifmentry_gc)(lua_State *lua);
static int VLUA_API(vifmentry_gettarget)(lua_State *lua);
static int VLUA_API(vifmentry_mimetype)(lua_State *lua);

VLUA_DECLARE_SAFE(vifmentry_gc);
VLUA_DECLARE_SAFE(vifmentry_gettarget);
VLUA_DECLARE_SAFE(vifmentry_mimetype);

/* Methods of VifmEntry type. */
static const luaL_Reg vifmentry_methods[] = {
	{ "__gc", VLUA_REF(vifmentry_gc) },
	{ NULL,   NULL                   }
};

void
vifmentry_init(lua_State *lua)
{
	vlua_cmn_make_metatable(lua, "VifmEntry");
	luaL_setfuncs(lua, vifmentry_methods, 0);
	lua_pop(lua, 1);
}

void
vifmentry_new(lua_State *lua, const dir_entry_t *entry)
{
	lua_createtable(lua, /*narr=*/0, /*nrec=*/16); /* entry */

	lua_pushstring(lua, entry->name);
	lua_setfield(lua, -2, "name");
	lua_pushstring(lua, entry->origin);
	lua_setfield(lua, -2, "location");
	lua_pushinteger(lua, entry->size);
	lua_setfield(lua, -2, "size");
	lua_pushinteger(lua, entry->mtime);
	lua_setfield(lua, -2, "mtime");
	lua_pushinteger(lua, entry->atime);
	lua_setfield(lua, -2, "atime");
	lua_pushinteger(lua, entry->ctime);
	lua_setfield(lua, -2, "ctime");
	lua_pushstring(lua, get_type_str(entry->type));
	lua_setfield(lua, -2, "type");
	lua_pushboolean(lua, fentry_is_dir(entry));
	lua_setfield(lua, -2, "isdir");

	int match = (entry->search_match != 0);
	lua_pushboolean(lua, match);
	lua_setfield(lua, -2, "match");
	lua_pushinteger(lua, (match ? entry->match_left + 1 : 0));
	lua_setfield(lua, -2, "matchstart");
	lua_pushinteger(lua, (match ? entry->match_right + 1 : 0));
	lua_setfield(lua, -2, "matchend");

	lua_pushboolean(lua, entry->selected);
	lua_setfield(lua, -2, "selected");

	lua_pushboolean(lua, entry->folded);
	lua_setfield(lua, -2, "folded");

	const char *prefix, *suffix;
	ui_get_decors(entry, &prefix, &suffix);
	lua_createtable(lua, /*narr=*/0, /*nrec=*/2); /* entry.classify */
	lua_pushstring(lua, prefix);
	lua_setfield(lua, -2, "prefix");   /* entry.classify.prefix */
	lua_pushstring(lua, suffix);
	lua_setfield(lua, -2, "suffix");   /* entry.classify.suffix */
	lua_setfield(lua, -2, "classify"); /* entry.classify */

	vifm_entry_t *vifm_entry = lua_newuserdatauv(lua, sizeof(*vifm_entry), 0);
	luaL_getmetatable(lua, "VifmEntry");
	lua_setmetatable(lua, -2);

	lua_pushcclosure(lua, VLUA_REF(vifmentry_gettarget), 1);
	lua_setfield(lua, -2, "gettarget");

	lua_pushlightuserdata(lua, vifm_entry);
	lua_pushcclosure(lua, VLUA_REF(vifmentry_mimetype), 1);
	lua_setfield(lua, -2, "mimetype");

	char full_path[PATH_MAX + 1];
	get_full_path_of(entry, sizeof(full_path), full_path);

	vifm_entry->full_path = strdup(full_path);
	vifm_entry->type = entry->type;
}

/* Frees memory allocated to vifm_entry_t fields. */
static int
VLUA_API(vifmentry_gc)(lua_State *lua)
{
	vifm_entry_t *vifm_entry = luaL_checkudata(lua, 1, "VifmEntry");
	free(vifm_entry->full_path);
	return 0;
}

/* Gets target of a symbolic link. */
static int
VLUA_API(vifmentry_gettarget)(lua_State *lua)
{
	vifm_entry_t *vifm_entry = vlua_cmn_check_this(lua, lua_upvalueindex(1));

	if(vifm_entry->type != FT_LINK)
	{
		return luaL_error(lua, "%s", "Entry is not a symbolic link");
	}

	char link_to[PATH_MAX + 1];
	if(get_link_target(vifm_entry->full_path, link_to, sizeof(link_to)) != 0)
	{
		return luaL_error(lua, "%s", "Failed to resolve symbolic link");
	}

	lua_pushstring(lua, link_to);
	return 1;
}

/* Gets a MIME type. */
static int
VLUA_API(vifmentry_mimetype)(lua_State *lua)
{
	vifm_entry_t *vifm_entry = vlua_cmn_check_this(lua, lua_upvalueindex(1));

	const char *mimetype = get_mimetype(vifm_entry->full_path,
			/*resolve_symlinks=*/1);

	if(mimetype == NULL)
	{
		lua_pushnil(lua);
		return 1;
	}

	lua_pushstring(lua, mimetype);
	return 1;
}

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

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/vifm

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/vifm

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master