mirror of
https://git.pumpin.online/funkpower/typikon.git
synced 2026-10-22 18:57:13 +00:00
Nine Sundays went unnamed in every jurisdiction. Three were missing from the movable cycle outright: the Paralytic, the Samaritan Woman and the Blind Man, so the fourth, fifth and sixth Sundays of Pascha reported only the saint of the fixed date. Six more are reckoned from a fixed feast rather than from Pascha — before and after the Exaltation, the Forefathers, before and after the Nativity, before and after the Theophany — and were not modelled at all. The three Pentecostarion Sundays rank with Thomas Sunday and the Myrrh-bearing Women, so a vigil-rank saint still keeps the day and the Sunday is commemorated on it. The six fixed-cycle ones never name a day: they are found in ecclesiastical space, so the old calendar and the new get them on the right morning, and they join the commemorations. Where a short window holds no Sunday the Typikon says what to do and this follows it; where the books disagree, the day goes unmarked rather than carrying an answer this calendar cannot defend. `week` says where a day falls in the count from Pentecost, which is how the books head the long ordinary stretch. It runs on across the new year and stops at the Triodion, whose Sundays have names instead of numbers. `--every-day` gives ics an event for every day, ferias included. The default still thins the calendar, which is right for a subscription and wrong for a reader who wants the saint of each morning; and the description now leads with the commemorations rather than burying them under the church date. Checked against 1.1.2 over every jurisdiction from 2015 to 2035: rank, feast and title move on the three new Sundays and nowhere else. No fast, obligation, binding or season changes on any day.
170 lines
6.2 KiB
Lua
170 lines
6.2 KiB
Lua
-- 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_week(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", "week", "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
|