Last active
June 27, 2016 06:24
-
-
Save macias/f6cddf39e457f0e0c350fef11113c936 to your computer and use it in GitHub Desktop.
quick&dirty reminder script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%% first "real" program converted to Skila | |
%% read more at: https://aboutskila.wordpress.com/2016/04/25/x-fullmoon-the-first-successful-conversion/ | |
using System._; | |
var current_year Int = Date.now.year; | |
var current_month Int = Date.now.month; | |
var current_day Int = Date.now.day; | |
def main() | |
if Environment.arguments.count==1 then | |
let parts = Environment.arguments[0].split("-"); | |
if not (current_year,current_month,current_day) ?= * parts.map(p => p to ?Int) then | |
throw !Exception("Argument error."); | |
end | |
end | |
processing(); | |
end | |
def print_tasks(title String,tasks ~String) String | |
var res = !""; | |
if not tasks.empty() then | |
res ++= "${title}:\n"; | |
for s in tasks do | |
res ++= "* ${s}\n"; | |
end | |
end | |
return res; | |
end | |
def days_in_month(var yyyy Int,var mm Int) Int | |
mm++; | |
if mm==13 then | |
mm = 1; | |
++yyyy; | |
end | |
let d = Date(yyyy,mm,1).addDays(-1); | |
return d.day; | |
end | |
def add_delta_YM(var year Int,var month Int,var day Int,dy Int,dm Int) (Int*3) | |
assert(dm>=0,"Only positive values"); | |
year += dy; | |
month += dm; | |
year += (month-1).div(12); | |
month = (month-1).mod(12) + 1; | |
if day>days_in_month(year,month) then | |
day = days_in_month(year,month); | |
end | |
return (year,month,day); | |
end | |
def process_date(var yyyy Int,var mm Int,var dd Int,var day_of_week Int) (Int*4) | |
%% input: Monday -- 1, Sunday -- 7 | |
if day_of_week>0 then %% given day of the week is required | |
day_of_week = (day_of_week==7?0:day_of_week); %% internal conversion -- 0 is Sunday, 6 is Saturday | |
var dw = Date(yyyy,mm,dd).dayOfWeek.ordinal; | |
if dw>day_of_week then | |
dw -= 7; | |
end | |
let t = Date(yyyy,mm,dd).addDays(day_of_week-dw); | |
(yyyy,mm,dd) = (t.year, t.month, t.day); | |
end | |
let days = days_in_month(yyyy,mm); %% correction because of the length of the month | |
if dd>days then | |
dd = days; | |
end | |
var distance = (Date(yyyy,mm,dd)-Date(current_year,current_month,current_day)).totalDays; | |
return (yyyy,mm,dd,distance); | |
end | |
def processing() | |
let current_tasks = ![String](); | |
let upcoming_tasks = ![String](); | |
let executables_ask = ![String](); | |
let executables_run = ![String](); | |
let dates_filename = Io.Path.combine(Io.Path.getDirectoryName(Environment.executablePath),"fullmoon.dates"); | |
assert(Io.File.exists(dates_filename),"Dates file does not exist."); | |
for s in Io.File.readLines(dates_filename) | |
.map(s => s.replace(/#.*/,"").replace(/^\s+/,"").replace(/\s+$/,"")) | |
.filter(s => not s.empty) | |
do | |
let (date, cycle_str, task_desc, advance_str, day_of_week_str) | |
= * do | |
let parts = s.split(";"); | |
parts ++ "".copy((5-parts.count())); | |
end | |
let cycle = cycle_str to ?Int ?? 0; | |
let day_of_week = day_of_week_str to ?Int ?? 0; | |
%% yyyy -- given year, mm -- month, dd -- day | |
var (yyyy,mm,dd) | |
= * do | |
let date_parts = /^(?:(\d{4})-)?(?:(\d{1,2})-)?(\d{1,2})$/.match(date) | |
.at(0).captures | |
.map(m => date.slice(m.index,m.count) to ?Int ?? throw !Exception("Ill-formed date.")); | |
%% optional parts start from year, thus we have to prepend zeros, not append them | |
0.copy((3-date_parts.count())) ++ date_parts; | |
end | |
var cycle_mode = 0; | |
if yyyy==0 then | |
yyyy = current_year; | |
cycle_mode = 2; | |
end | |
if mm==0 then | |
mm = current_month; | |
cycle_mode = 1; | |
end | |
(yyyy,mm,dd,var distance) = *process_date(yyyy,mm,dd,day_of_week); | |
%% yyyy,mm,dd are corrected now | |
%% distance -- distance (in days) from today to given date (yyyy,mm,dd) | |
if cycle>0 then | |
if distance<0 then | |
distance = (-distance).mod(cycle); | |
if distance>0 then | |
distance = cycle-distance; | |
end | |
else | |
%% if there is a cyclic event, computed distance to the nearest date, not to given one | |
%% thus -- compute modulo | |
distance = distance.abs().mod(cycle); | |
end | |
else if distance<0 then %% given event passed | |
if cycle_mode==1 then %% monthly event | |
(yyyy,mm,dd) = *add_delta_YM(yyyy,mm,dd,0,1); | |
else if cycle_mode==2 then %% annual event | |
(yyyy,mm,dd) = *add_delta_YM(yyyy,mm,dd,1,0); | |
end | |
(yyyy,mm,dd,distance) = *process_date(yyyy,mm,dd,day_of_week); | |
end | |
if advance_str=="?" then | |
if distance==0 then | |
executables_ask!append(task_desc); | |
end | |
else if advance_str=="!" then | |
if distance==0 then | |
executables_run!append(task_desc); | |
end | |
else if distance==0 then | |
current_tasks!append(task_desc); | |
else if advance_str != "" and distance>0 | |
and (let advance ?= advance_str to ?Int) and distance<=advance then | |
upcoming_tasks!append("+${distance}: ${task_desc}"); | |
end | |
end-for | |
let msg = print_tasks("Upcoming tasks",upcoming_tasks) | |
++ | |
print_tasks("Current tasks",current_tasks); | |
if not msg.empty or (not executables_ask.empty) then | |
let proc = Process.call("kdialog","--title \"X-FullMoon\" --"++(executables_ask.empty ? "msgbox":"yesno")++" \""++msg++"\""); | |
if proc.exitCode==0 then | |
for exe in executables_ask do | |
Process.start(exe); | |
end | |
end | |
end | |
for exe in executables_run do | |
Process.start(exe); | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment