Files
typikon/examples/lua/typikon.lua
T

169 lines
6.1 KiB
Lua
Raw Normal View History

-- typikon, through LuaJIT's FFI.
--
-- Drop this beside your config and `local typikon = require("typikon")`. It
-- needs libtypikon.so on the loader's path, or TYPIKON_LIB set to it:
--
-- cargo build --release --features capi
-- TYPIKON_LIB=target/release/libtypikon.so luajit examples/lua/statusline.lua
--
-- Written for AwesomeWM, WezTerm and Neovim, which all embed LuaJIT and none
-- of which should be spawning a process on every redraw.
local ffi = require("ffi")
ffi.cdef [[
const char *typikon_version(void);
uint32_t typikon_abi_version(void);
const char *typikon_last_error(void);
int32_t typikon_jdn_from_ymd(int32_t year, uint32_t month, uint32_t day);
int typikon_ymd_from_jdn(int32_t jdn, int32_t *year, uint32_t *month, uint32_t *day);
int32_t typikon_today(void);
typedef struct typikon_day typikon_day;
typikon_day *typikon_describe(int32_t jdn, const char *jurisdiction);
typikon_day *typikon_describe_full(int32_t jdn, const char *jurisdiction,
const char *tradition, int discipline);
void typikon_day_free(typikon_day *day);
const char *typikon_day_json(const typikon_day *day);
const char *typikon_day_iso(const typikon_day *day);
const char *typikon_day_weekday(const typikon_day *day);
const char *typikon_day_jurisdiction(const typikon_day *day);
const char *typikon_day_calendar(const typikon_day *day);
const char *typikon_day_tradition(const typikon_day *day);
const char *typikon_day_church_date(const typikon_day *day);
const char *typikon_day_title(const typikon_day *day);
const char *typikon_day_fast(const typikon_day *day);
const char *typikon_day_fast_label(const typikon_day *day);
const char *typikon_day_emoji(const typikon_day *day);
const char *typikon_day_reason(const typikon_day *day);
const char *typikon_day_season(const typikon_day *day);
const char *typikon_day_cycle(const typikon_day *day);
const char *typikon_day_feast(const typikon_day *day);
const char *typikon_day_rank(const typikon_day *day);
const char *typikon_day_sign(const typikon_day *day);
const char *typikon_day_obligation(const typikon_day *day);
const char *typikon_day_binds(const typikon_day *day);
uint32_t typikon_day_commemoration_count(const typikon_day *day);
const char *typikon_day_commemoration(const typikon_day *day, uint32_t i);
int typikon_day_is_obligatory(const typikon_day *day);
int32_t typikon_day_days_to_pascha(const typikon_day *day);
int32_t typikon_day_pascha(const typikon_day *day);
int32_t typikon_day_julian_offset(const typikon_day *day);
int32_t typikon_pascha(int32_t year, const char *jurisdiction);
uint32_t typikon_jurisdiction_count(void);
const char *typikon_jurisdiction_key(uint32_t i);
const char *typikon_jurisdiction_name(uint32_t i);
const char *typikon_jurisdiction_note(uint32_t i);
]]
local C = ffi.load(os.getenv("TYPIKON_LIB") or "typikon")
local M = { ABI = 1 }
-- A string field, or nil where the library returned NULL. Every accessor may,
-- and NULL means "the day has no such thing" rather than an error.
local function str(p)
if p == nil then return nil end
return ffi.string(p)
end
local function err()
return str(C.typikon_last_error()) or "unknown error"
end
-- The fields worth reading without a JSON parser. Order matters only for the
-- table's own readability.
local FIELDS = {
"iso", "weekday", "jurisdiction", "calendar", "tradition", "church_date",
"title", "fast", "fast_label", "emoji", "reason",
"season", "cycle", "feast", "rank", "sign", "obligation", "binds",
}
-- Copy the day into a plain Lua table and free it. The C day owns its strings
-- and they die with it, so nothing here may hold on to a pointer.
local function harvest(d)
local t = {}
for _, f in ipairs(FIELDS) do
t[f] = str(C["typikon_day_" .. f](d))
end
t.is_obligatory = C.typikon_day_is_obligatory(d) ~= 0
t.days_to_pascha = C.typikon_day_days_to_pascha(d)
t.pascha_jdn = C.typikon_day_pascha(d)
t.julian_offset = C.typikon_day_julian_offset(d)
t.commemorations = {}
for i = 0, C.typikon_day_commemoration_count(d) - 1 do
t.commemorations[i + 1] = str(C.typikon_day_commemoration(d, i))
end
t.json = str(C.typikon_day_json(d))
C.typikon_day_free(d)
return t
end
--- One day, as a table. `opts` may carry `jurisdiction`, `tradition` and
--- `typikon` (true to show the day at the Typikon's full discipline, false for
--- only what particular law requires, nil for whatever was remembered).
--- Returns nil and a message on error.
function M.describe(jdn, opts)
opts = opts or {}
local discipline = -1
if opts.typikon == true then discipline = 1
elseif opts.typikon == false then discipline = 0 end
local d = C.typikon_describe_full(jdn, opts.jurisdiction, opts.tradition, discipline)
if d == nil then return nil, err() end
return harvest(d)
end
--- Today, by local time.
function M.today(opts)
return M.describe(C.typikon_today(), opts)
end
--- The Julian Day Number for a civil date, or nil and a message.
function M.jdn(year, month, day)
local n = C.typikon_jdn_from_ymd(year, month, day)
if n == 0 then return nil, err() end
return n
end
--- The civil year, month and day for a Julian Day Number.
function M.ymd(jdn)
local y = ffi.new("int32_t[1]")
local m = ffi.new("uint32_t[1]")
local d = ffi.new("uint32_t[1]")
if C.typikon_ymd_from_jdn(jdn, y, m, d) ~= 0 then return nil, err() end
return y[0], tonumber(m[0]), tonumber(d[0])
end
--- Pascha in a civil year, as a Julian Day Number.
function M.pascha(year, jurisdiction)
local n = C.typikon_pascha(year, jurisdiction)
if n == 0 then return nil, err() end
return n
end
--- Every jurisdiction the library knows: { key, name, note }.
function M.jurisdictions()
local out = {}
for i = 0, C.typikon_jurisdiction_count() - 1 do
out[i + 1] = {
key = str(C.typikon_jurisdiction_key(i)),
name = str(C.typikon_jurisdiction_name(i)),
note = str(C.typikon_jurisdiction_note(i)),
}
end
return out
end
M.version = str(C.typikon_version())
-- A library newer in a way that changed meaning, not one merely newer.
if C.typikon_abi_version() ~= M.ABI then
error(("typikon ABI %d, this binding wants %d")
:format(tonumber(C.typikon_abi_version()), M.ABI))
end
return M