git.m455.casa

fa

clone url: git://git.m455.casa/fa


dists/fa.lua

1 #!/usr/bin/lua5.3
2 -- Authors:
3 -- - Jesse Laprade <jesselaprade@gmail.com>
4 -- - Will Sinatra <wpsinatra@gmail.com>
5 -- License: AGPLv3
6 local lume = nil
7 package.preload["lume"] = package.preload["lume"] or function(...)
8 --
9 -- lume
10 --
11 -- Copyright (c) 2020 rxi
12 --
13 -- Permission is hereby granted, free of charge, to any person obtaining a copy of
14 -- this software and associated documentation files (the "Software"), to deal in
15 -- the Software without restriction, including without limitation the rights to
16 -- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
17 -- of the Software, and to permit persons to whom the Software is furnished to do
18 -- so, subject to the following conditions:
19 --
20 -- The above copyright notice and this permission notice shall be included in all
21 -- copies or substantial portions of the Software.
22 --
23 -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 -- SOFTWARE.
30 --
31
32 local lume = { _version = "2.3.0" }
33
34 local pairs, ipairs = pairs, ipairs
35 local type, assert, unpack = type, assert, unpack or table.unpack
36 local tostring, tonumber = tostring, tonumber
37 local math_floor = math.floor
38 local math_ceil = math.ceil
39 local math_atan2 = math.atan2 or math.atan
40 local math_sqrt = math.sqrt
41 local math_abs = math.abs
42
43 local noop = function()
44 end
45
46 local identity = function(x)
47 return x
48 end
49
50 local patternescape = function(str)
51 return str:gsub("[%(%)%.%%%+%-%*%?%[%]%^%$]", "%%%1")
52 end
53
54 local absindex = function(len, i)
55 return i < 0 and (len + i + 1) or i
56 end
57
58 local iscallable = function(x)
59 if type(x) == "function" then return true end
60 local mt = getmetatable(x)
61 return mt and mt.__call ~= nil
62 end
63
64 local getiter = function(x)
65 if lume.isarray(x) then
66 return ipairs
67 elseif type(x) == "table" then
68 return pairs
69 end
70 error("expected table", 3)
71 end
72
73 local iteratee = function(x)
74 if x == nil then return identity end
75 if iscallable(x) then return x end
76 if type(x) == "table" then
77 return function(z)
78 for k, v in pairs(x) do
79 if z[k] ~= v then return false end
80 end
81 return true
82 end
83 end
84 return function(z) return z[x] end
85 end
86
87
88
89 function lume.clamp(x, min, max)
90 return x < min and min or (x > max and max or x)
91 end
92
93
94 function lume.round(x, increment)
95 if increment then return lume.round(x / increment) * increment end
96 return x >= 0 and math_floor(x + .5) or math_ceil(x - .5)
97 end
98
99
100 function lume.sign(x)
101 return x < 0 and -1 or 1
102 end
103
104
105 function lume.lerp(a, b, amount)
106 return a + (b - a) * lume.clamp(amount, 0, 1)
107 end
108
109
110 function lume.smooth(a, b, amount)
111 local t = lume.clamp(amount, 0, 1)
112 local m = t * t * (3 - 2 * t)
113 return a + (b - a) * m
114 end
115
116
117 function lume.pingpong(x)
118 return 1 - math_abs(1 - x % 2)
119 end
120
121
122 function lume.distance(x1, y1, x2, y2, squared)
123 local dx = x1 - x2
124 local dy = y1 - y2
125 local s = dx * dx + dy * dy
126 return squared and s or math_sqrt(s)
127 end
128
129
130 function lume.angle(x1, y1, x2, y2)
131 return math_atan2(y2 - y1, x2 - x1)
132 end
133
134
135 function lume.vector(angle, magnitude)
136 return math.cos(angle) * magnitude, math.sin(angle) * magnitude
137 end
138
139
140 function lume.random(a, b)
141 if not a then a, b = 0, 1 end
142 if not b then b = 0 end
143 return a + math.random() * (b - a)
144 end
145
146
147 function lume.randomchoice(t)
148 return t[math.random(#t)]
149 end
150
151
152 function lume.weightedchoice(t)
153 local sum = 0
154 for _, v in pairs(t) do
155 assert(v >= 0, "weight value less than zero")
156 sum = sum + v
157 end
158 assert(sum ~= 0, "all weights are zero")
159 local rnd = lume.random(sum)
160 for k, v in pairs(t) do
161 if rnd < v then return k end
162 rnd = rnd - v
163 end
164 end
165
166
167 function lume.isarray(x)
168 return type(x) == "table" and x[1] ~= nil
169 end
170
171
172 function lume.push(t, ...)
173 local n = select("#", ...)
174 for i = 1, n do
175 t[#t + 1] = select(i, ...)
176 end
177 return ...
178 end
179
180
181 function lume.remove(t, x)
182 local iter = getiter(t)
183 for i, v in iter(t) do
184 if v == x then
185 if lume.isarray(t) then
186 table.remove(t, i)
187 break
188 else
189 t[i] = nil
190 break
191 end
192 end
193 end
194 return x
195 end
196
197
198 function lume.clear(t)
199 local iter = getiter(t)
200 for k in iter(t) do
201 t[k] = nil
202 end
203 return t
204 end
205
206
207 function lume.extend(t, ...)
208 for i = 1, select("#", ...) do
209 local x = select(i, ...)
210 if x then
211 for k, v in pairs(x) do
212 t[k] = v
213 end
214 end
215 end
216 return t
217 end
218
219
220 function lume.shuffle(t)
221 local rtn = {}
222 for i = 1, #t do
223 local r = math.random(i)
224 if r ~= i then
225 rtn[i] = rtn[r]
226 end
227 rtn[r] = t[i]
228 end
229 return rtn
230 end
231
232
233 function lume.sort(t, comp)
234 local rtn = lume.clone(t)
235 if comp then
236 if type(comp) == "string" then
237 table.sort(rtn, function(a, b) return a[comp] < b[comp] end)
238 else
239 table.sort(rtn, comp)
240 end
241 else
242 table.sort(rtn)
243 end
244 return rtn
245 end
246
247
248 function lume.array(...)
249 local t = {}
250 for x in ... do t[#t + 1] = x end
251 return t
252 end
253
254
255 function lume.each(t, fn, ...)
256 local iter = getiter(t)
257 if type(fn) == "string" then
258 for _, v in iter(t) do v[fn](v, ...) end
259 else
260 for _, v in iter(t) do fn(v, ...) end
261 end
262 return t
263 end
264
265
266 function lume.map(t, fn)
267 fn = iteratee(fn)
268 local iter = getiter(t)
269 local rtn = {}
270 for k, v in iter(t) do rtn[k] = fn(v) end
271 return rtn
272 end
273
274
275 function lume.all(t, fn)
276 fn = iteratee(fn)
277 local iter = getiter(t)
278 for _, v in iter(t) do
279 if not fn(v) then return false end
280 end
281 return true
282 end
283
284
285 function lume.any(t, fn)
286 fn = iteratee(fn)
287 local iter = getiter(t)
288 for _, v in iter(t) do
289 if fn(v) then return true end
290 end
291 return false
292 end
293
294
295 function lume.reduce(t, fn, first)
296 local started = first ~= nil
297 local acc = first
298 local iter = getiter(t)
299 for _, v in iter(t) do
300 if started then
301 acc = fn(acc, v)
302 else
303 acc = v
304 started = true
305 end
306 end
307 assert(started, "reduce of an empty table with no first value")
308 return acc
309 end
310
311
312 function lume.unique(t)
313 local rtn = {}
314 for k in pairs(lume.invert(t)) do
315 rtn[#rtn + 1] = k
316 end
317 return rtn
318 end
319
320
321 function lume.filter(t, fn, retainkeys)
322 fn = iteratee(fn)
323 local iter = getiter(t)
324 local rtn = {}
325 if retainkeys then
326 for k, v in iter(t) do
327 if fn(v) then rtn[k] = v end
328 end
329 else
330 for _, v in iter(t) do
331 if fn(v) then rtn[#rtn + 1] = v end
332 end
333 end
334 return rtn
335 end
336
337
338 function lume.reject(t, fn, retainkeys)
339 fn = iteratee(fn)
340 local iter = getiter(t)
341 local rtn = {}
342 if retainkeys then
343 for k, v in iter(t) do
344 if not fn(v) then rtn[k] = v end
345 end
346 else
347 for _, v in iter(t) do
348 if not fn(v) then rtn[#rtn + 1] = v end
349 end
350 end
351 return rtn
352 end
353
354
355 function lume.merge(...)
356 local rtn = {}
357 for i = 1, select("#", ...) do
358 local t = select(i, ...)
359 local iter = getiter(t)
360 for k, v in iter(t) do
361 rtn[k] = v
362 end
363 end
364 return rtn
365 end
366
367
368 function lume.concat(...)
369 local rtn = {}
370 for i = 1, select("#", ...) do
371 local t = select(i, ...)
372 if t ~= nil then
373 local iter = getiter(t)
374 for _, v in iter(t) do
375 rtn[#rtn + 1] = v
376 end
377 end
378 end
379 return rtn
380 end
381
382
383 function lume.find(t, value)
384 local iter = getiter(t)
385 for k, v in iter(t) do
386 if v == value then return k end
387 end
388 return nil
389 end
390
391
392 function lume.match(t, fn)
393 fn = iteratee(fn)
394 local iter = getiter(t)
395 for k, v in iter(t) do
396 if fn(v) then return v, k end
397 end
398 return nil
399 end
400
401
402 function lume.count(t, fn)
403 local count = 0
404 local iter = getiter(t)
405 if fn then
406 fn = iteratee(fn)
407 for _, v in iter(t) do
408 if fn(v) then count = count + 1 end
409 end
410 else
411 if lume.isarray(t) then
412 return #t
413 end
414 for _ in iter(t) do count = count + 1 end
415 end
416 return count
417 end
418
419
420 function lume.slice(t, i, j)
421 i = i and absindex(#t, i) or 1
422 j = j and absindex(#t, j) or #t
423 local rtn = {}
424 for x = i < 1 and 1 or i, j > #t and #t or j do
425 rtn[#rtn + 1] = t[x]
426 end
427 return rtn
428 end
429
430
431 function lume.first(t, n)
432 if not n then return t[1] end
433 return lume.slice(t, 1, n)
434 end
435
436
437 function lume.last(t, n)
438 if not n then return t[#t] end
439 return lume.slice(t, -n, -1)
440 end
441
442
443 function lume.invert(t)
444 local rtn = {}
445 for k, v in pairs(t) do rtn[v] = k end
446 return rtn
447 end
448
449
450 function lume.pick(t, ...)
451 local rtn = {}
452 for i = 1, select("#", ...) do
453 local k = select(i, ...)
454 rtn[k] = t[k]
455 end
456 return rtn
457 end
458
459
460 function lume.keys(t)
461 local rtn = {}
462 local iter = getiter(t)
463 for k in iter(t) do rtn[#rtn + 1] = k end
464 return rtn
465 end
466
467
468 function lume.clone(t)
469 local rtn = {}
470 for k, v in pairs(t) do rtn[k] = v end
471 return rtn
472 end
473
474
475 function lume.fn(fn, ...)
476 assert(iscallable(fn), "expected a function as the first argument")
477 local args = { ... }
478 return function(...)
479 local a = lume.concat(args, { ... })
480 return fn(unpack(a))
481 end
482 end
483
484
485 function lume.once(fn, ...)
486 local f = lume.fn(fn, ...)
487 local done = false
488 return function(...)
489 if done then return end
490 done = true
491 return f(...)
492 end
493 end
494
495
496 local memoize_fnkey = {}
497 local memoize_nil = {}
498
499 function lume.memoize(fn)
500 local cache = {}
501 return function(...)
502 local c = cache
503 for i = 1, select("#", ...) do
504 local a = select(i, ...) or memoize_nil
505 c[a] = c[a] or {}
506 c = c[a]
507 end
508 c[memoize_fnkey] = c[memoize_fnkey] or {fn(...)}
509 return unpack(c[memoize_fnkey])
510 end
511 end
512
513
514 function lume.combine(...)
515 local n = select('#', ...)
516 if n == 0 then return noop end
517 if n == 1 then
518 local fn = select(1, ...)
519 if not fn then return noop end
520 assert(iscallable(fn), "expected a function or nil")
521 return fn
522 end
523 local funcs = {}
524 for i = 1, n do
525 local fn = select(i, ...)
526 if fn ~= nil then
527 assert(iscallable(fn), "expected a function or nil")
528 funcs[#funcs + 1] = fn
529 end
530 end
531 return function(...)
532 for _, f in ipairs(funcs) do f(...) end
533 end
534 end
535
536
537 function lume.call(fn, ...)
538 if fn then
539 return fn(...)
540 end
541 end
542
543
544 function lume.time(fn, ...)
545 local start = os.clock()
546 local rtn = {fn(...)}
547 return (os.clock() - start), unpack(rtn)
548 end
549
550
551 local lambda_cache = {}
552
553 function lume.lambda(str)
554 if not lambda_cache[str] then
555 local args, body = str:match([[^([%w,_ ]-)%->(.-)$]])
556 assert(args and body, "bad string lambda")
557 local s = "return function(" .. args .. ")\nreturn " .. body .. "\nend"
558 lambda_cache[str] = lume.dostring(s)
559 end
560 return lambda_cache[str]
561 end
562
563
564 local serialize
565
566 local serialize_map = {
567 [ "boolean" ] = tostring,
568 [ "nil" ] = tostring,
569 [ "string" ] = function(v) return string.format("%q", v) end,
570 [ "number" ] = function(v)
571 if v ~= v then return "0/0" -- nan
572 elseif v == 1 / 0 then return "1/0" -- inf
573 elseif v == -1 / 0 then return "-1/0" end -- -inf
574 return tostring(v)
575 end,
576 [ "table" ] = function(t, stk)
577 stk = stk or {}
578 if stk[t] then error("circular reference") end
579 local rtn = {}
580 stk[t] = true
581 for k, v in pairs(t) do
582 rtn[#rtn + 1] = "[" .. serialize(k, stk) .. "]=" .. serialize(v, stk)
583 end
584 stk[t] = nil
585 return "{" .. table.concat(rtn, ",") .. "}"
586 end
587 }
588
589 setmetatable(serialize_map, {
590 __index = function(_, k) error("unsupported serialize type: " .. k) end
591 })
592
593 serialize = function(x, stk)
594 return serialize_map[type(x)](x, stk)
595 end
596
597 function lume.serialize(x)
598 return serialize(x)
599 end
600
601
602 function lume.deserialize(str)
603 return lume.dostring("return " .. str)
604 end
605
606
607 function lume.split(str, sep)
608 if not sep then
609 return lume.array(str:gmatch("([%S]+)"))
610 else
611 assert(sep ~= "", "empty separator")
612 local psep = patternescape(sep)
613 return lume.array((str..sep):gmatch("(.-)("..psep..")"))
614 end
615 end
616
617
618 function lume.trim(str, chars)
619 if not chars then return str:match("^[%s]*(.-)[%s]*$") end
620 chars = patternescape(chars)
621 return str:match("^[" .. chars .. "]*(.-)[" .. chars .. "]*$")
622 end
623
624
625 function lume.wordwrap(str, limit)
626 limit = limit or 72
627 local check
628 if type(limit) == "number" then
629 check = function(s) return #s >= limit end
630 else
631 check = limit
632 end
633 local rtn = {}
634 local line = ""
635 for word, spaces in str:gmatch("(%S+)(%s*)") do
636 local s = line .. word
637 if check(s) then
638 table.insert(rtn, line .. "\n")
639 line = word
640 else
641 line = s
642 end
643 for c in spaces:gmatch(".") do
644 if c == "\n" then
645 table.insert(rtn, line .. "\n")
646 line = ""
647 else
648 line = line .. c
649 end
650 end
651 end
652 table.insert(rtn, line)
653 return table.concat(rtn)
654 end
655
656
657 function lume.format(str, vars)
658 if not vars then return str end
659 local f = function(x)
660 return tostring(vars[x] or vars[tonumber(x)] or "{" .. x .. "}")
661 end
662 return (str:gsub("{(.-)}", f))
663 end
664
665
666 function lume.trace(...)
667 local info = debug.getinfo(2, "Sl")
668 local t = { info.short_src .. ":" .. info.currentline .. ":" }
669 for i = 1, select("#", ...) do
670 local x = select(i, ...)
671 if type(x) == "number" then
672 x = string.format("%g", lume.round(x, .01))
673 end
674 t[#t + 1] = tostring(x)
675 end
676 print(table.concat(t, " "))
677 end
678
679
680 function lume.dostring(str)
681 return assert((loadstring or load)(str))()
682 end
683
684
685 function lume.uuid()
686 local fn = function(x)
687 local r = math.random(16) - 1
688 r = (x == "x") and (r + 1) or (r % 4) + 9
689 return ("0123456789abcdef"):sub(r, r)
690 end
691 return (("xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"):gsub("[xy]", fn))
692 end
693
694
695 function lume.hotswap(modname)
696 local oldglobal = lume.clone(_G)
697 local updated = {}
698 local function update(old, new)
699 if updated[old] then return end
700 updated[old] = true
701 local oldmt, newmt = getmetatable(old), getmetatable(new)
702 if oldmt and newmt then update(oldmt, newmt) end
703 for k, v in pairs(new) do
704 if type(v) == "table" then update(old[k], v) else old[k] = v end
705 end
706 end
707 local err = nil
708 local function onerror(e)
709 for k in pairs(_G) do _G[k] = oldglobal[k] end
710 err = lume.trim(e)
711 end
712 local ok, oldmod = pcall(require, modname)
713 oldmod = ok and oldmod or nil
714 xpcall(function()
715 package.loaded[modname] = nil
716 local newmod = require(modname)
717 if type(oldmod) == "table" then update(oldmod, newmod) end
718 for k, v in pairs(oldglobal) do
719 if v ~= _G[k] and type(v) == "table" then
720 update(v, _G[k])
721 _G[k] = v
722 end
723 end
724 end, onerror)
725 package.loaded[modname] = oldmod
726 if err then return nil, err end
727 return oldmod
728 end
729
730
731 local ripairs_iter = function(t, i)
732 i = i - 1
733 local v = t[i]
734 if v ~= nil then
735 return i, v
736 end
737 end
738
739 function lume.ripairs(t)
740 return ripairs_iter, t, (#t + 1)
741 end
742
743
744 function lume.color(str, mul)
745 mul = mul or 1
746 local r, g, b, a
747 r, g, b = str:match("#(%x%x)(%x%x)(%x%x)")
748 if r then
749 r = tonumber(r, 16) / 0xff
750 g = tonumber(g, 16) / 0xff
751 b = tonumber(b, 16) / 0xff
752 a = 1
753 elseif str:match("rgba?%s*%([%d%s%.,]+%)") then
754 local f = str:gmatch("[%d.]+")
755 r = (f() or 0) / 0xff
756 g = (f() or 0) / 0xff
757 b = (f() or 0) / 0xff
758 a = f() or 1
759 else
760 error(("bad color string '%s'"):format(str))
761 end
762 return r * mul, g * mul, b * mul, a * mul
763 end
764
765
766 local chain_mt = {}
767 chain_mt.__index = lume.map(lume.filter(lume, iscallable, true),
768 function(fn)
769 return function(self, ...)
770 self._value = fn(self._value, ...)
771 return self
772 end
773 end)
774 chain_mt.__index.result = function(x) return x._value end
775
776 function lume.chain(value)
777 return setmetatable({ _value = value }, chain_mt)
778 end
779
780 setmetatable(lume, {
781 __call = function(_, ...)
782 return lume.chain(...)
783 end
784 })
785
786
787 return lume
788 end
789 lume = require("lume")
790 local home = os.getenv("HOME")
791 local program_name = "fa"
792 local program_version = "0.5.0"
793 local program_file = (home .. "/." .. program_name)
794 local event_symbol = "!"
795 local keyword_today = "today"
796 local cmds_help = {human = "help", long = "--help", short = "-h"}
797 local cmds_version = {human = "version", long = "--version", short = "-v"}
798 local cmd_init = "init"
799 local cmd_add = "add"
800 local cmd_rm = "rm"
801 local cmd_ls = "ls"
802 local cmd_notify = "notify"
803 local newline = "\n"
804 local double_newline = "\n\n"
805 local space = " "
806 local indent_2 = " "
807 local messages = {["agenda-empty"] = "There is nothing in your agenda.", ["cancelling-date-creation"] = "Cancelling date creation", ["date-already-exists"] = ("The following event already exists in your agenda:" .. newline .. "%s %s" .. newline .. "Choose one of the options below:" .. newline .. "1. Replace the old event" .. newline .. "2. Add the event to the existing date" .. newline .. "3. Cancell even creation" .. newline .. "> "), ["date-format"] = ("Error: Date format must be mmdd" .. newline .. "Example: 1231 \"The last day of december\""), ["file-already-exists"] = string.format("A file or directory named '%s' already exists.", program_file), ["file-doesnt-exist"] = string.format("%s doesn't exist. Try running '%s %s' (without the quotation marks).", program_file, program_name, cmd_init), ["key-doesnt-exist"] = "The date '%s' wasn't found in your agenda.", ["not-an-option"] = "Error: '%s' is not an option.", ["program-version"] = string.format("AGPLv3 -- %s", program_version), ["sub-key-doesnt-exist"] = "The item '%s' on %s wasn't found in your agenda.", added = "Added '%s' to your agenda.", initialized = string.format("Successfully created %s", program_file), removed = "Removed '%s' from your agenda.", usage = string.format("For usage, type '%s %s'.", program_name, cmds_help.human)}
808 local function key_exists_3f(tbl, key)
809 if (type(tbl) == "table") then
810 local tbl_keys = lume.keys(tbl)
811 local function _0_(_241)
812 return (key == _241)
813 end
814 if lume.any(tbl_keys, _0_) then
815 return true
816 else
817 return false
818 end
819 else
820 return false
821 end
822 end
823 local function get_date()
824 return os.date("%m%d")
825 end
826 local function file_exists_3f(str)
827 local file_in = io.open(str, "r")
828 if file_in then
829 return file_in:close()
830 else
831 return false
832 end
833 end
834 local function file__3etable(str)
835 if file_exists_3f(str) then
836 local file_in = io.open(str, "r")
837 local function close_handlers_0_(ok_0_, ...)
838 file_in:close()
839 if ok_0_ then
840 return ...
841 else
842 return error(..., 0)
843 end
844 end
845 local function _0_()
846 return lume.deserialize(file_in:read("*all"))
847 end
848 return close_handlers_0_(xpcall(_0_, (package.loaded.fennel or debug).traceback))
849 else
850 return nil
851 end
852 end
853 local function table__3efile(str, tbl)
854 if file_exists_3f(str) then
855 local file_out = io.open(str, "w")
856 local function close_handlers_0_(ok_0_, ...)
857 file_out:close()
858 if ok_0_ then
859 return ...
860 else
861 return error(..., 0)
862 end
863 end
864 local function _0_()
865 return file_out:write(lume.serialize(tbl))
866 end
867 return close_handlers_0_(xpcall(_0_, (package.loaded.fennel or debug).traceback))
868 else
869 return nil
870 end
871 end
872 local function create_prefix(seq, key)
873 if (#seq > 1) then
874 return string.format("%s. ", key)
875 else
876 return ""
877 end
878 end
879 local function print_format(str, ...)
880 return print(string.format(str, ...))
881 end
882 local function init_2fcreate_file()
883 local file_out = io.open(program_file, "w")
884 local function close_handlers_0_(ok_0_, ...)
885 file_out:close()
886 if ok_0_ then
887 return ...
888 else
889 return error(..., 0)
890 end
891 end
892 local function _0_()
893 file_out:write(lume.serialize({}))
894 return print(messages.initialized)
895 end
896 return close_handlers_0_(xpcall(_0_, (package.loaded.fennel or debug).traceback))
897 end
898 local function init()
899 if file_exists_3f(program_file) then
900 return print(messages["file-already-exists"])
901 else
902 return init_2fcreate_file()
903 end
904 end
905 local function add_2fadd_event(date, event_str)
906 local tbl = file__3etable(program_file)
907 if key_exists_3f(tbl, date) then
908 tbl[date][(1 + #tbl[date])] = event_str
909 else
910 tbl[date] = {event_str}
911 end
912 table__3efile(program_file, tbl)
913 return print_format(messages.added, event_str)
914 end
915 local function add(date_str, event_str)
916 if file_exists_3f(program_file) then
917 local date = nil
918 if (date_str == keyword_today) then
919 date = get_date()
920 else
921 date = date_str
922 end
923 return add_2fadd_event(date, event_str)
924 else
925 return print(messages["file-doesnt-exist"])
926 end
927 end
928 local function rm(date_str, event_str)
929 if file_exists_3f(program_file) then
930 local tbl = file__3etable(program_file)
931 local date = nil
932 if (date_str == keyword_today) then
933 date = get_date()
934 else
935 date = date_str
936 end
937 local events_seq = tbl[date]
938 local events_seq_index = tonumber(event_str)
939 local date_exists_3f = key_exists_3f(tbl, date)
940 local event_exists_3f = key_exists_3f(events_seq, events_seq_index)
941 local _1_0 = {date_exists_3f, event_exists_3f, event_str}
942 if ((type(_1_0) == "table") and (_1_0[1] == true) and (_1_0[2] == false) and (_1_0[3] == nil)) then
943 tbl[date] = nil
944 table__3efile(program_file, tbl)
945 return print_format(messages.removed, date)
946 elseif ((type(_1_0) == "table") and (_1_0[1] == true) and (_1_0[2] == true)) then
947 local event = events_seq[events_seq_index]
948 table.remove(events_seq, events_seq_index)
949 if (#events_seq == 0) then
950 tbl[date] = nil
951 table__3efile(program_file, tbl)
952 return print_format(messages.removed, event)
953 else
954 tbl[date] = events_seq
955 table__3efile(program_file, tbl)
956 return print_format(messages.removed, event)
957 end
958 elseif ((type(_1_0) == "table") and (_1_0[1] == true) and (_1_0[2] == false)) then
959 return print_format(messages["sub-key-doesnt-exist"], event_str, date)
960 elseif ((type(_1_0) == "table") and (_1_0[1] == false)) then
961 return print_format(messages["key-doesnt-exist"], date)
962 end
963 else
964 return print(messages["file-doesnt-exist"])
965 end
966 end
967 local function notify()
968 if file_exists_3f(program_file) then
969 if key_exists_3f(file__3etable(program_file), get_date()) then
970 return io.write(event_symbol)
971 end
972 else
973 return print(messages["file-doesnt-exist"])
974 end
975 end
976 local function ls_2fprint_seq(events_seq)
977 local keys = lume.keys(events_seq)
978 for _, key in pairs(keys) do
979 local event = events_seq[key]
980 local event_prefix = create_prefix(events_seq, key)
981 print_format("%s%s", event_prefix, event)
982 end
983 return nil
984 end
985 local function ls_2fls_date(date_str)
986 if file_exists_3f(program_file) then
987 local tbl = file__3etable(program_file)
988 local date = nil
989 if (date_str == keyword_today) then
990 date = get_date()
991 else
992 date = date_str
993 end
994 if key_exists_3f(tbl, date) then
995 local events_seq = tbl[date]
996 return ls_2fprint_seq(events_seq)
997 end
998 else
999 return print(messages["file-doesnt-exist"])
1000 end
1001 end
1002 local function ls_2fprint_seq0(events_seq, date)
1003 local _0_ = events_seq
1004 local first_event = _0_[1]
1005 local _1_ = lume.keys(events_seq)
1006 local first_key = _1_[1]
1007 local rest_keys = {(table.unpack or unpack)(_1_, 2)}
1008 local first_event_prefix = create_prefix(events_seq, first_key)
1009 print_format("%s%s", first_event_prefix, first_event)
1010 for _, key in pairs(rest_keys) do
1011 local event = events_seq[key]
1012 local padding = string.rep(" ", (1 + #date))
1013 print_format("%s %s. %s", padding, key, event)
1014 end
1015 return nil
1016 end
1017 local function ls_2fsort_and_print_tbl(tbl, tbl_keys)
1018 table.sort(tbl_keys)
1019 for _, date in pairs(tbl_keys) do
1020 io.write(string.format("%s: ", date))
1021 local events_seq = tbl[date]
1022 ls_2fprint_seq0(events_seq, date)
1023 end
1024 return nil
1025 end
1026 local function ls(date_str)
1027 if file_exists_3f(program_file) then
1028 if date_str then
1029 return ls_2fls_date(date_str)
1030 else
1031 local tbl = file__3etable(program_file)
1032 local tbl_keys = lume.keys(tbl)
1033 local tbl_length = #tbl_keys
1034 if (tbl_length > 0) then
1035 return ls_2fsort_and_print_tbl(tbl, tbl_keys)
1036 else
1037 return print(messages["agenda-empty"])
1038 end
1039 end
1040 else
1041 return print(messages["file-doesnt-exist"])
1042 end
1043 end
1044 local function help()
1045 return print(("Usage:\n" .. " fa <command> [<arg>] [<arg>]\n" .. "\n" .. "Commands:\n" .. " init - Creates your agenda.\n" .. " add <mmdd|today> \"Quoted text\" - Adds an event to your agenda.\n" .. " rm <mmdd|today> - Removes a given date from your agenda.\n" .. " rm <mmdd|today> [<number>] - Removes an event from given date from your agenda.\n" .. " ls [<mmdd|today>] - Lists the events on the given date.\n" .. " ls - Lists all dates and their events.\n" .. " notify - Displays a \"!\" if an event exists today.\n" .. " version - Prints the current version of fa.\n" .. "\n" .. "Examples:\n" .. " fa init\n" .. " fa add 1231 \"Sherry's birthday\"\n" .. " fa add today \"Sherry's birthday\"\n" .. " fa rm 1231\n" .. " fa rm 1231 3 (See note below)\n" .. " fa rm today\n" .. " fa rm today 3 (See note below)\n" .. " fa ls today\n" .. " fa ls 1231\n" .. " fa ls\n" .. " fa notify\n" .. " fa version\n" .. "\n" .. "Note: You may need to run 'fa ls' to see which number correlates to which event.\n"))
1046 end
1047 local function process_args(arg_tbl)
1048 local _0_0, _1_0, _2_0 = arg_tbl
1049 if ((type(_0_0) == "table") and (_0_0[1] == cmd_add) and (nil ~= _0_0[2]) and (nil ~= _0_0[3]) and (_0_0[4] == nil)) then
1050 local date_str = _0_0[2]
1051 local event_str = _0_0[3]
1052 return add(date_str, event_str)
1053 elseif ((type(_0_0) == "table") and (_0_0[1] == cmd_rm) and (nil ~= _0_0[2]) and (nil ~= _0_0[3]) and (_0_0[4] == nil)) then
1054 local date_str = _0_0[2]
1055 local event_str = _0_0[3]
1056 return rm(date_str, event_str)
1057 elseif ((type(_0_0) == "table") and (_0_0[1] == cmd_rm) and (nil ~= _0_0[2]) and (_0_0[3] == nil)) then
1058 local date_str = _0_0[2]
1059 return rm(date_str)
1060 elseif ((type(_0_0) == "table") and (_0_0[1] == cmd_ls) and (nil ~= _0_0[2]) and (_0_0[3] == nil)) then
1061 local date_str = _0_0[2]
1062 return ls(date_str)
1063 elseif ((type(_0_0) == "table") and (_0_0[1] == cmd_ls) and (_0_0[2] == nil)) then
1064 return ls()
1065 else
1066 local _3_
1067 do
1068 local cmd = _0_0[1]
1069 _3_ = (((type(_0_0) == "table") and (nil ~= _0_0[1]) and (_0_0[2] == nil)) and ((cmd == cmds_help.human) or (cmd == cmds_help.long) or (cmd == cmds_help.short)))
1070 end
1071 if _3_ then
1072 local cmd = _0_0[1]
1073 return help()
1074 else
1075 local _4_
1076 do
1077 local cmd = _0_0[1]
1078 _4_ = (((type(_0_0) == "table") and (nil ~= _0_0[1]) and (_0_0[2] == nil)) and ((cmd == cmds_version.human) or (cmd == cmds_version.long) or (cmd == cmds_version.short)))
1079 end
1080 if _4_ then
1081 local cmd = _0_0[1]
1082 return print(messages["program-version"])
1083 elseif ((type(_0_0) == "table") and (_0_0[1] == cmd_init) and (_0_0[2] == nil)) then
1084 return init()
1085 elseif ((type(_0_0) == "table") and (_0_0[1] == cmd_notify) and (_0_0[2] == nil)) then
1086 return notify()
1087 else
1088 local _ = _0_0
1089 return print(messages.usage)
1090 end
1091 end
1092 end
1093 end
1094 local function main(arg_tbl)
1095 return process_args(arg_tbl)
1096 end
1097 return main(arg)