Carlos Une: 1 New module: +lua 5 files changed, 157 insertions(+), 4 deletions(-)
Copy & paste the following snippet into your terminal to import this patchset into git:
curl -s https://lists.sr.ht/~tomterl/public-inbox/patches/53952/mbox | git am -3Learn more about email & git
--- Makefile | 2 ++ README.org | 8 ++--- lua/lua.ha | 56 ++++++++++++++++++++++++++++++ man/thp.5.scd | 4 +++ mods/lua+lua.ha | 91 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 157 insertions(+), 4 deletions(-) create mode 100644 lua/lua.ha create mode 100644 mods/lua+lua.ha diff --git a/Makefile b/Makefile index a2bc2e9..626eb09 100644 --- a/Makefile +++ b/Makefile @@ -13,11 +13,13 @@ MANDIR := $(PREFIX)/share/man DESTDIR := GITLIBS = $(patsubst -pthread,,$(shell $(PKG_CONFIG) --libs libgit2 --static)) +LUALIBS = $(shell $(PKG_CONFIG) --libs lua5.4) HAREPATH := ./vendor:${HAREPATH} MODS ?= host path sigil $(EXTRA_MODS) THPD_LIBS = $(if $(filter git,$(MODS)),$(GITLIBS)) +THPD_LIBS+= $(if $(filter lua,$(MODS)),$(LUALIBS)) THPD_EXTRA_DEPS =$(if $(filter git,$(MODS)),git/*.ha) $(if $(filter timer,$(MODS)),timer/*.ha) all: thpd thp docs diff --git a/README.org b/README.org index 5dc7400..d303802 100644 --- a/README.org +++ b/README.org @@ -29,16 +29,16 @@ You need ~hare~, follow the instructions [[https://harelang.org/installation][at To build thp with all modules included, you need libgit2 and your platforms libgit2-dev equivalent installed, then issued #+BEGIN_SRC sh :exports code -make EXTRA_MODS="project git clock timer shind uptime moon sun star" -make EXTRA_MODS="project git clock timer shind uptime moon sun star" test +make EXTRA_MODS="project git clock timer shind uptime moon sun star lua" +make EXTRA_MODS="project git clock timer shind uptime moon sun star lua" test make PREFIX="${HOME}" install #+END_SRC To build with just the modules you use in your spec, use ~MODS~: #+BEGIN_SRC sh :exports code -make MODS="path host project timer uptime moon sun star" -make MODS="path host project timer uptime moon sun star" test +make MODS="path host project timer uptime moon sun star lua" +make MODS="path host project timer uptime moon sun star lua" test make PREFIX="${HOME}" install #+END_SRC diff --git a/lua/lua.ha b/lua/lua.ha new file mode 100644 index 0000000..190faba --- /dev/null +++ b/lua/lua.ha @@ -0,0 +1,56 @@ +// Author: Carlos Une <une@fastmail.fm> +// Maintainer: Carlos Une <une@fastmail.fm> +// +// SPDX-FileCopyrightText: 2024 Carlos Une <une@fastmail.fm> +// SPDX-License-Identifier: GPL-3.0-or-later +use types::c; + +export type KContext = c::ptrdiff; +export type KFunction = nullable *opaque; +export type State = opaque; +export type Integer = int; +export def MULTRET: int = -1; +export def OK: int = 0; + +export fn tostring(L: *State, i: int) *const c::char = { + return tolstring(L, i, null); +}; + +export fn pop(L: *State, n: int) void = settop(L, -(n)-1); + +export fn loadfile(L: *State, filename: *const c::char) int = { + return loadfilex(L, filename, null); +}; + +export fn pcall(L: *State, nargs: int, nresults: int, msgh: int) int = { + return pcallk(L, nargs, nresults, msgh, 0, null); +}; + +export fn dofile(L: *State, filename: *const c::char) int = { + let l = loadfilex(L, filename, null); + return if (l != 0) l else pcall(L, 0, MULTRET, 0); +}; + +export @symbol("luaL_newstate") fn newstate() *State; +export @symbol("luaL_openlibs") fn openlibs(L: *State) void; +export @symbol("luaL_loadstring") fn loadstring(L: *State, + s: *const c::char) int; +export @symbol("lua_pcallk") fn pcallk(L: *State, nargs: int, nresults: int, + msgh: int, ctx: KContext, k: KFunction) int; +export @symbol("lua_close") fn close(L: *State) void; +export @symbol("luaL_loadfilex") fn loadfilex(L: *State, + filename: nullable *const c::char, mode: nullable *const c::char) int; +export @symbol("lua_createtable") fn createtable(L: *State, narr: int, + nrec: int) void; +export @symbol("lua_pushstring") fn pushstring(L: *State, + s: *const c::char) *const c::char; +export @symbol("lua_pushboolean") fn pushboolean(L: *State, int) void; +export @symbol("lua_pushinteger") fn pushinteger(L: *State, n: Integer) void; +export @symbol("lua_setglobal") fn setglobal(L: *State, + name: *const c::char) void; +export @symbol("lua_settable") fn settable(L: *State, idx: int) void; +export @symbol("lua_isstring") fn isstring(L: *State, idx: int) int; +export @symbol("lua_gettop") fn gettop(L: *State) int; +export @symbol("lua_settop") fn settop(L: *State, n: int) void; +export @symbol("lua_tolstring") fn tolstring(L: *State, n: int, + sz: nullable *size) *const c::char; diff --git a/man/thp.5.scd b/man/thp.5.scd index 5b3450a..0a94375 100644 --- a/man/thp.5.scd +++ b/man/thp.5.scd @@ -123,6 +123,10 @@ the modules configuration settings. The location and time format can be configured. See thpd(5). - *star*++ displays the position of a star as seen by an observer on Earth. +- *lua*++ + Runs a Lua script —_XDG_DATA_HOME_/thp/thp.lua — and copies its return value + to the prompt string. The script has read-only access to thp's internal + _env::env_ struct through a Lua table named _thp.env_. # STYLES diff --git a/mods/lua+lua.ha b/mods/lua+lua.ha new file mode 100644 index 0000000..709bc38 --- /dev/null +++ b/mods/lua+lua.ha @@ -0,0 +1,91 @@ +// Author: Carlos Une <une@fastmail.fm> +// Maintainer: Carlos Une <une@fastmail.fm> +// +// SPDX-FileCopyrightText: 2024 Carlos Une <une@fastmail.fm> +// SPDX-License-Identifier: GPL-3.0-or-later +use env; +use dirs; +use strings; +use types::c; +use lua; + +@init fn register_lua() void = { + register("lua", &mod_lua); +}; + +fn mkfield(L: *lua::State, k: str, v: (str | bool | uint)) void = { + pushstring(L, k); + match (v) { + case let x: str => + pushstring(L, x); + case let x: bool => + lua::pushboolean(L, if (x) 1 else 0); + case let x: uint => + lua::pushinteger(L, x: int); + }; + lua::settable(L, -3); +}; + +fn pushstring(L: *lua::State, s: str) void = { + let string = c::fromstr(s); + defer free(string); + lua::pushstring(L, string); +}; + +export fn mod_lua(pe: *env::env) str = { + let L = lua::newstate(); + defer lua::close(L); + + lua::openlibs(L); + lua::createtable(L, 0, 0); + pushstring(L, "env"); + lua::createtable(L, 0, 0); + pushstring(L, "control"); + lua::createtable(L, 0, 0); + mkfield(L, "remote", pe.control.remote); + mkfield(L, "zsh", pe.control.zsh); + mkfield(L, "bash", pe.control.bash); + mkfield(L, "exit", pe.control.exit); + mkfield(L, "reload", pe.control.reload); + mkfield(L, "timer", pe.control.timer); + mkfield(L, "root", pe.control.root); + mkfield(L, "wtitle", pe.control.wtitle); + lua::settable(L, -3); + mkfield(L, "home", pe.home); + mkfield(L, "columns", pe.columns); + mkfield(L, "user", pe.user); + mkfield(L, "host", pe.host); + mkfield(L, "pwd", pe.pwd); + mkfield(L, "pd", pe.pd); + mkfield(L, "cid", pe.cid); + lua::settable(L, -3); + + let thp = c::fromstr("thp"); + defer free(thp); + lua::setglobal(L, thp); + + let script = strings::concat(dirs::data("thp"), "/thp.lua"); + defer free(script); + + let scriptz = c::fromstr(script); + defer free(scriptz); + + if (lua::dofile(L, scriptz) != lua::OK) { + let errormsg = lua::tostring(L, -1); + lua::pop(L, 1); + return strings::concat("mod_lua:", c::tostr(errormsg)!); + }; + + if (lua::gettop(L) != 1) { + return strings::dup("mod_lua:script must return a value."); + }; + + if (lua::isstring(L, -1) == 0) { + lua::pop(L, 1); + return strings::dup("mod_lua:script must return a string."); + }; + + let r = lua::tostring(L, -1); + lua::pop(L, 1); + return strings::dup(c::tostr(r)!); +}; -- 2.39.2