diff --git a/bin/todo.rb b/bin/todo.rb index 7e7eb35..290cd3f 100644 --- a/bin/todo.rb +++ b/bin/todo.rb @@ -29,7 +29,6 @@ require 'date' class Todo - COLOR_CODES = { black: 30, red: 31, @@ -177,7 +176,6 @@ def setup next_7_days = (0..6).map do |day| @today + day end @due_date_days = next_7_days.map do |day| day.strftime('%A').downcase end due_dates_for_queries = next_7_days.map do |day| day.strftime(DATE_FORMAT) end - @queries = { ':active' => lambda do |task| /(new|started|blocked)/.match(task[:state]) end, ':done' => lambda do |task| 'done' == task[:state] end, @@ -380,7 +378,7 @@ def filter_tasks(tasks, patterns) end items[num] = task if match end - return items + items end def colorize(text, color) @@ -388,16 +386,11 @@ def colorize(text, color) end def convert_due_date(date) - due = nil day_index = @due_date_days.index(date.to_s.downcase) || DUE_DATE_DAYS_SIMPLE.index(date.to_s.downcase) || @due_date_days.map do |day| day[0..2] end.index(date.to_s.downcase) - if day_index - due = (@today + day_index).strftime(DATE_FORMAT) - else - due = date.nil? || date.empty? ? nil : Date.strptime(date, DATE_FORMAT).strftime(DATE_FORMAT) - end - return due + return (@today + day_index).strftime(DATE_FORMAT) if day_index + date.nil? || date.empty? ? nil : Date.strptime(date, DATE_FORMAT).strftime(DATE_FORMAT) end end diff --git a/node/package.json b/node/package.json index ce18526..8cecb2d 100644 --- a/node/package.json +++ b/node/package.json @@ -1,6 +1,6 @@ { "name": "todo-jsonl", - "version": "0.1.32", + "version": "0.1.33", "description": "todo list manager on the command-line inspired by todo.txt using the jsonl format", "main": "todo.js", "bin": { diff --git a/node/todo.js b/node/todo.js index ebbba44..7628c28 100644 --- a/node/todo.js +++ b/node/todo.js @@ -714,14 +714,14 @@ xa=function(W,za){var Da=xa.$$p,Va=Da||z,ib,db,bb=z;bb=bb=z;Da&&(xa.$$p=null);Da Ta=function(){return this.$wday()["$=="](3)},Ta.$$arity=0);a.def(u,"$year",Ia=function(){return this.date.getFullYear()},Ia.$$arity=0);a.def(u,"$cwday",kb=function(){return this.date.getDay()||7},kb.$$arity=0);a.def(u,"$cweek",Ra=function(){var W=new Date(this.date);W.setHours(0,0,0);W.setDate(W.getDate()+4-(W.getDay()||7));return Math.ceil(((W-new Date(W.getFullYear(),0,1))/864E5+1)/7)},Ra.$$arity=0)}(w[0],null,w)}; (function(a){function y(I,e){return"number"===typeof I&&"number"===typeof e?I+e:I["$+"](e)}function J(I,e){return"number"===typeof I&&"number"===typeof e?I>e:I["$>"](e)}function t(I,e){return"number"===typeof I&&"number"===typeof e?I $length $change_state $to_i $list $< $set_priority $due_date $append $rename $!= $delete $add_note $delete_note $show $puts $usage $start_repl $cleanup $colorize $private $keys $map $select $parse $strftime $today $downcase $lambda $match $== $! $each $split $strip $chomp $[]= $- $has_key? $sort $generate $gsub $convert_due_date $postprocess_tags $load_tasks $call $write_tasks $update_task $push $max $size $to_s $& $sort_by $filter_tasks $start_with? $abs $rjust $kind_of? $execute $to_a $each_key $all? $uniq $index $new".split(" ")); z.$require("json");z.$require("date");(function(I,$super,n){I=k(I,$super,"Todo");var L=[I].concat(n),D,R,ia,da,ma,b,h,f,q,A,E,G,M,ba,ua,Oa,wa,Ba,La,na,S,sa,ya;I.$$prototype.queries=I.$$prototype.today=I.$$prototype.due_date_days=d;a.const_set(L[0],"COLOR_CODES",m("black red green yellow blue magenta cyan white".split(" "),{black:30,red:31,green:32,yellow:33,blue:34,magenta:35,cyan:36,white:37}));a.const_set(L[0],"STATES",m(["new","done","started","blocked","default"],{"new":"[ ]",done:"[x]",started:"[>]", -blocked:"[!]","default":"[?]"}));a.const_set(L[0],"ORDER",m(["new","done","started","blocked","default"],{"new":3,done:4,started:2,blocked:1,"default":100}));a.const_set(L[0],"COLORS",m(["new","done","started","blocked","default"],{"new":"white",done:"blue",started:"green",blocked:"yellow","default":"magenta"}));a.const_set(L[0],"DATE_FORMAT","%Y-%m-%d");a.const_set(L[0],"DUE_DATE_DAYS_SIMPLE",["today","tomorrow"]);a.const_set(L[0],"DUE_DATE_TAG_PATTERN",/(^| )due:([a-zA-Z0-9-]+)/);a.const_set(L[0], -"CONTEXT_TAG_PATTERN",/(^| )[@+][\w-]+/);a.const_set(L[0],"PRIORITY_FLAG","*");a.const_set(L[0],"TODO_FILE",require("path").join(require("os").homedir(),"todo.jsonl"));a.def(I,"$execute",D=function(pa){var ha=d,F=d,V=d,ka=d,va=d,ja=d,xa=d,Fa=d,Ea=d,Qa=d,Ta=d,Ia=d;try{this.$setup(),ha=pa.$first(),F=u(V=pa["$[]"](c(1,-1,!1)))?V:[],ka=ha,"add"["$==="](ka)?(u(u(va=F["$nil?"]())?va:F["$empty?"]())&&this.$raise(y(ha," command requires at least one parameter")),this.$add(F.$join(" "))):"start"["$==="](ka)? -u(J(F.$length(),0))?this.$change_state(F.$first().$to_i(),"started",(u(ja=F["$[]"](c(1,-1,!1)))?ja:[]).$join(" ")):this.$list(d,[":started"]):"done"["$==="](ka)?u(J(F.$length(),0))?this.$change_state(F.$first().$to_i(),"done",(u(xa=F["$[]"](c(1,-1,!1)))?xa:[]).$join(" ")):this.$list(d,[":done"]):"block"["$==="](ka)?u(J(F.$length(),0))?this.$change_state(F.$first().$to_i(),"blocked",(u(Fa=F["$[]"](c(1,-1,!1)))?Fa:[]).$join(" ")):this.$list(d,[":blocked"]):"reset"["$==="](ka)?u(J(F.$length(),0))?this.$change_state(F.$first().$to_i(), -"new",(u(Ea=F["$[]"](c(1,-1,!1)))?Ea:[]).$join(" ")):this.$list(d,[":new"]):"prio"["$==="](ka)?(u(t(F.$length(),1))&&this.$raise(y(ha," command requires at least one parameter")),this.$set_priority(F.$first().$to_i(),(u(Qa=F["$[]"](c(1,-1,!1)))?Qa:[]).$join(" "))):"due"["$==="](ka)?(u(t(F.$length(),1))&&this.$raise(y(ha," command requires at least one parameter")),this.$due_date(F.$first().$to_i(),(u(Ta=F["$[]"](c(1,-1,!1)))?Ta:[]).$join(" "))):"append"["$==="](ka)?(u(t(F.$length(),2))&&this.$raise(y(ha, -" command requires at least two parameters")),this.$append(F.$first().$to_i(),F["$[]"](c(1,-1,!1)).$join(" "))):"rename"["$==="](ka)?(u(t(F.$length(),2))&&this.$raise(y(ha," command requires at least two parameters")),this.$rename(F.$first().$to_i(),F["$[]"](c(1,-1,!1)).$join(" "))):"del"["$==="](ka)?(u(F.$length()["$!="](1))&&this.$raise(y(ha," command requires exactly one parameter")),this.$delete(F.$first().$to_i())):"note"["$==="](ka)?(u(t(F.$length(),2))&&this.$raise(y(ha," command requires at least two parameters")), -this.$add_note(F.$first().$to_i(),F["$[]"](c(1,-1,!1)).$join(" "))):"delnote"["$==="](ka)?(u(F.$length()["$!="](1))&&this.$raise(y(ha," command requires exactly one parameter")),this.$delete_note(F.$first().$to_i())):"list"["$==="](ka)?this.$list(d,F):"show"["$==="](ka)?(u(F.$length()["$!="](1))&&this.$raise(y(ha," command requires exactly one parameter")),this.$show(F.$first().$to_i())):"help"["$==="](ka)?(u(J(F.$length(),0))&&this.$raise(y(ha," command has no parameters")),this.$puts(this.$usage())): -"repl"["$==="](ka)?(u(J(F.$length(),0))&&this.$raise(y(ha," command has no parameters")),this.$start_repl()):"cleanup"["$==="](ka)?(u(u(Ia=F["$nil?"]())?Ia:F["$empty?"]())&&this.$raise(y(ha," command requires at least one parameter")),this.$cleanup(F)):this.$list(d,pa)}catch(kb){if(a.rescue(kb,[H(x(L,"JS"),"Error"),x(L,"RuntimeError")])){pa=kb;try{this.$puts(""+this.$colorize("ERROR:","red")+" "+pa)}finally{a.pop_exception()}}else throw kb;}return this},D.$$arity=1);I.$private();a.def(I,"$usage", -R=function(){var pa,ha;return"Usage: todo \n\nCommands:\n* add add new task\n* start [text] mark task as started, with optional note\n* done [text] mark task as completed, with optional note\n* block [text] mark task as blocked, with optional note\n* reset [text] reset task to new state, with optional note\n* prio [text] toggle high priority flag, with optional note\n* due [date] set/unset due date (in YYYY-MM-DD format)\n\n* append append text to task title\n* rename rename task\n* del delete task\n* note add note to task\n* delnote delete all notes from task\n\n* list [regex...] list tasks (only active tasks by default)\n* show show all task details\n* repl enter read-eval-print loop mode\n* cleanup [regex...] cleanup completed tasks by regex\n* help this help screen\n\nWith list command the following pre-defined regex patterns can be also used:\n"+ +blocked:"[!]","default":"[?]"}));a.const_set(L[0],"ORDER",m(["new","done","started","blocked","default"],{"new":3,done:4,started:2,blocked:1,"default":100}));a.const_set(L[0],"COLORS",m(["new","done","started","blocked","default"],{"new":"white",done:"blue",started:"green",blocked:"yellow","default":"magenta"}));a.const_set(L[0],"DATE_FORMAT","%Y-%m-%d");a.const_set(L[0],"DATE_PATTERN",/^[1-9]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/);a.const_set(L[0],"DUE_DATE_DAYS_SIMPLE",["today","tomorrow"]); +a.const_set(L[0],"DUE_DATE_TAG_PATTERN",/(^| )due:([a-zA-Z0-9-]+)/);a.const_set(L[0],"CONTEXT_TAG_PATTERN",/(^| )[@+][\w-]+/);a.const_set(L[0],"PRIORITY_FLAG","*");a.const_set(L[0],"TODO_FILE",require("path").join(require("os").homedir(),"todo.jsonl"));a.def(I,"$execute",D=function(pa){var ha=d,F=d,V=d,ka=d,va=d,ja=d,xa=d,Fa=d,Ea=d,Qa=d,Ta=d,Ia=d;try{this.$setup(),ha=pa.$first(),F=u(V=pa["$[]"](c(1,-1,!1)))?V:[],ka=ha,"add"["$==="](ka)?(u(u(va=F["$nil?"]())?va:F["$empty?"]())&&this.$raise(y(ha," command requires at least one parameter")), +this.$add(F.$join(" "))):"start"["$==="](ka)?u(J(F.$length(),0))?this.$change_state(F.$first().$to_i(),"started",(u(ja=F["$[]"](c(1,-1,!1)))?ja:[]).$join(" ")):this.$list(d,[":started"]):"done"["$==="](ka)?u(J(F.$length(),0))?this.$change_state(F.$first().$to_i(),"done",(u(xa=F["$[]"](c(1,-1,!1)))?xa:[]).$join(" ")):this.$list(d,[":done"]):"block"["$==="](ka)?u(J(F.$length(),0))?this.$change_state(F.$first().$to_i(),"blocked",(u(Fa=F["$[]"](c(1,-1,!1)))?Fa:[]).$join(" ")):this.$list(d,[":blocked"]): +"reset"["$==="](ka)?u(J(F.$length(),0))?this.$change_state(F.$first().$to_i(),"new",(u(Ea=F["$[]"](c(1,-1,!1)))?Ea:[]).$join(" ")):this.$list(d,[":new"]):"prio"["$==="](ka)?(u(t(F.$length(),1))&&this.$raise(y(ha," command requires at least one parameter")),this.$set_priority(F.$first().$to_i(),(u(Qa=F["$[]"](c(1,-1,!1)))?Qa:[]).$join(" "))):"due"["$==="](ka)?(u(t(F.$length(),1))&&this.$raise(y(ha," command requires at least one parameter")),this.$due_date(F.$first().$to_i(),(u(Ta=F["$[]"](c(1,-1, +!1)))?Ta:[]).$join(" "))):"append"["$==="](ka)?(u(t(F.$length(),2))&&this.$raise(y(ha," command requires at least two parameters")),this.$append(F.$first().$to_i(),F["$[]"](c(1,-1,!1)).$join(" "))):"rename"["$==="](ka)?(u(t(F.$length(),2))&&this.$raise(y(ha," command requires at least two parameters")),this.$rename(F.$first().$to_i(),F["$[]"](c(1,-1,!1)).$join(" "))):"del"["$==="](ka)?(u(F.$length()["$!="](1))&&this.$raise(y(ha," command requires exactly one parameter")),this.$delete(F.$first().$to_i())): +"note"["$==="](ka)?(u(t(F.$length(),2))&&this.$raise(y(ha," command requires at least two parameters")),this.$add_note(F.$first().$to_i(),F["$[]"](c(1,-1,!1)).$join(" "))):"delnote"["$==="](ka)?(u(F.$length()["$!="](1))&&this.$raise(y(ha," command requires exactly one parameter")),this.$delete_note(F.$first().$to_i())):"list"["$==="](ka)?this.$list(d,F):"show"["$==="](ka)?(u(F.$length()["$!="](1))&&this.$raise(y(ha," command requires exactly one parameter")),this.$show(F.$first().$to_i())):"help"["$==="](ka)? +(u(J(F.$length(),0))&&this.$raise(y(ha," command has no parameters")),this.$puts(this.$usage())):"repl"["$==="](ka)?(u(J(F.$length(),0))&&this.$raise(y(ha," command has no parameters")),this.$start_repl()):"cleanup"["$==="](ka)?(u(u(Ia=F["$nil?"]())?Ia:F["$empty?"]())&&this.$raise(y(ha," command requires at least one parameter")),this.$cleanup(F)):this.$list(d,pa)}catch(kb){if(a.rescue(kb,[H(x(L,"JS"),"Error"),x(L,"RuntimeError")])){pa=kb;try{this.$puts(""+this.$colorize("ERROR:","red")+" "+pa)}finally{a.pop_exception()}}else throw kb; +}return this},D.$$arity=1);I.$private();a.def(I,"$usage",R=function(){var pa,ha;return"Usage: todo \n\nCommands:\n* add add new task\n* start [text] mark task as started, with optional note\n* done [text] mark task as completed, with optional note\n* block [text] mark task as blocked, with optional note\n* reset [text] reset task to new state, with optional note\n* prio [text] toggle high priority flag, with optional note\n* due [date] set/unset due date (in YYYY-MM-DD format)\n\n* append append text to task title\n* rename rename task\n* del delete task\n* note add note to task\n* delnote delete all notes from task\n\n* list [regex...] list tasks (only active tasks by default)\n* show show all task details\n* repl enter read-eval-print loop mode\n* cleanup [regex...] cleanup completed tasks by regex\n* help this help screen\n\nWith list command the following pre-defined regex patterns can be also used:\n"+ this.queries.$keys().$join(", ")+'\n\nDue dates can be also added via tags in task title: "due:YYYY-MM-DD"\n\nLegend:\n'+l(l(x(L,"STATES"),"select",[],(pa=function(F){null==F&&(F=d);return F["$!="]("default")},pa.$$s=this,pa.$$arity=2,pa)),"map",[],(ha=function(F,V){null==F&&(F=d);null==V&&(V=d);return""+F+" "+V},ha.$$s=this,ha.$$arity=2,ha)).$join(", ")+", priority "+x(L,"PRIORITY_FLAG")+"\n\nTodo file: "+x(L,"TODO_FILE")+"\n"},R.$$arity=0);a.def(I,"$setup",ia=function(){var pa,ha,F,V,ka,va,ja,xa, Fa,Ea,Qa,Ta,Ia=d,kb=d;this.today=x(L,"Date").$parse(x(L,"Date").$today().$strftime(x(L,"DATE_FORMAT")));Ia=l(c(0,6,!1),"map",[],(pa=function(Ra){var W=null==pa.$$s?this:pa.$$s;null==W.today&&(W.today=d);null==Ra&&(Ra=d);return y(W.today,Ra)},pa.$$s=this,pa.$$arity=1,pa));this.due_date_days=l(Ia,"map",[],(ha=function(Ra){null==Ra&&(Ra=d);return Ra.$strftime("%A").$downcase()},ha.$$s=this,ha.$$arity=1,ha));kb=l(Ia,"map",[],(F=function(Ra){null==Ra&&(Ra=d);return Ra.$strftime(x(L,"DATE_FORMAT"))},F.$$s= this,F.$$arity=1,F));return this.queries=m(":active :done :blocked :started :new :all :today :tomorrow :next7days".split(" "),{":active":l(this,"lambda",[],(V=function(Ra){null==Ra&&(Ra=d);return/(new|started|blocked)/.$match(Ra["$[]"]("state"))},V.$$s=this,V.$$arity=1,V)),":done":l(this,"lambda",[],(ka=function(Ra){null==Ra&&(Ra=d);return"done"["$=="](Ra["$[]"]("state"))},ka.$$s=this,ka.$$arity=1,ka)),":blocked":l(this,"lambda",[],(va=function(Ra){null==Ra&&(Ra=d);return"blocked"["$=="](Ra["$[]"]("state"))}, @@ -743,5 +743,5 @@ ha.$$s=this,ha.$$arity=1,ha)))},wa.$$arity=1);a.def(I,"$show",Ba=function(pa,ha) function(ka){try{ka=ka.trim(),["exit","quit"].includes(ka)?V.close():(["clear","cls"].includes(ka)?process.stdout.write("\u001b[H\u001b[2J"):F(ka),pa())}catch(va){throw V.close(),va;}})}var ha,F=d;F=l(this,"lambda",[],(ha=function(ka){var va=null==ha.$$s?this:ha.$$s;null==ka&&(ka=d);return va.$execute(ka["$=="]("repl")?[]:ka.$split(/\s+/))},ha.$$s=this,ha.$$arity=1,ha));var V=require("readline").createInterface({input:process.stdin,output:process.stdout});F("");pa()},La.$$arity=0);a.def(I,"$cleanup", na=function(pa){var ha,F=d,V=d;F=this.$load_tasks();pa=y([":done"],pa.$to_a());V=this.$filter_tasks(F,pa);l(V,"each_key",[],(ha=function(ka){null==ka&&(ka=d);return F.$delete(ka)},ha.$$s=this,ha.$$arity=1,ha));this.$write_tasks(F);return this.$puts("Deleted "+V.$size()+" todo(s)")},na.$$arity=1);a.def(I,"$filter_tasks",S=function(pa,ha){var F,V=d;V=m([],{});l(pa,"each",[],(F=function(ka,va){var ja=null==F.$$s?this:F.$$s,xa,Fa=d;Fa=d;null==ka&&(ka=d);null==va&&(va=d);Fa=l(ha.$uniq(),"all?",[],(xa= function(Ea){var Qa=null==xa.$$s?this:xa.$$s;null==Qa.queries&&(Qa.queries=d);null==Ea&&(Ea=d);return u(Qa.queries["$[]"](Ea))?Qa.queries["$[]"](Ea).$call(va):a.regexp([Ea],"i").$match(va["$[]"]("title"))},xa.$$s=ja,xa.$$arity=1,xa));return u(Fa)?(Fa=[ka,va],l(V,"[]=",a.to_a(Fa)),Fa[w(Fa.length,1)]):d},F.$$s=this,F.$$arity=2,F));return V},S.$$arity=2);a.def(I,"$colorize",sa=function(pa,ha){var F=d;return"\u001b["+(u(F=x(L,"COLOR_CODES")["$[]"](ha))?F:37)+"m"+pa+"\u001b[0m"},sa.$$arity=2);return(a.def(I, -"$convert_due_date",ya=function(pa){var ha,F=this,V=d,ka=V=d,va=d,ja=d;V=d;V=function(){return u(ka=u(va=F.due_date_days.$index(pa.$to_s().$downcase()))?va:x(L,"DUE_DATE_DAYS_SIMPLE").$index(pa.$to_s().$downcase()))?ka:l(F.due_date_days,"map",[],(ha=function(xa){null==xa&&(xa=d);return xa["$[]"](c(0,2,!1))},ha.$$s=F,ha.$$arity=1,ha)).$index(pa.$to_s().$downcase())}();return V=u(V)?y(F.today,V).$strftime(x(L,"DATE_FORMAT")):u(u(ja=pa["$nil?"]())?ja:pa["$empty?"]())?d:x(L,"Date").$parse(/^\d{4}-\d{2}-\d{2}$/.$match(pa).$to_s()).$strftime(x(L, +"$convert_due_date",ya=function(pa){var ha,F=this,V=d,ka=d,va=d,ja=d;V=function(){return u(ka=u(va=F.due_date_days.$index(pa.$to_s().$downcase()))?va:x(L,"DUE_DATE_DAYS_SIMPLE").$index(pa.$to_s().$downcase()))?ka:l(F.due_date_days,"map",[],(ha=function(xa){null==xa&&(xa=d);return xa["$[]"](c(0,2,!1))},ha.$$s=F,ha.$$arity=1,ha)).$index(pa.$to_s().$downcase())}();return u(V)?y(F.today,V).$strftime(x(L,"DATE_FORMAT")):u(u(ja=pa["$nil?"]())?ja:pa["$empty?"]())?d:x(L,"Date").$parse(x(L,"DATE_PATTERN").$match(pa).$to_s()).$strftime(x(L, "DATE_FORMAT"))},ya.$$arity=1),d)&&"convert_due_date"})(p[0],null,p);return x(p,"Todo").$new().$execute(process.argv.slice(2))})(Opal);var Qb=Opal.$$;Opal.add_stubs(["$exit"]);Qb([],"Kernel").$exit();}).call(this); diff --git a/node/todo.js.rb b/node/todo.js.rb index 62bf38c..a4c8540 100644 --- a/node/todo.js.rb +++ b/node/todo.js.rb @@ -29,7 +29,6 @@ require 'date' class Todo - COLOR_CODES = { black: 30, red: 31, @@ -66,6 +65,7 @@ class Todo } DATE_FORMAT = '%Y-%m-%d' + DATE_PATTERN = /^[1-9]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/ DUE_DATE_DAYS_SIMPLE = ['today', 'tomorrow'] DUE_DATE_TAG_PATTERN = /(^| )due:([a-zA-Z0-9-]+)/ CONTEXT_TAG_PATTERN = /(^| )[@+][\w-]+/ @@ -177,7 +177,6 @@ def setup next_7_days = (0..6).map do |day| @today + day end @due_date_days = next_7_days.map do |day| day.strftime('%A').downcase end due_dates_for_queries = next_7_days.map do |day| day.strftime(DATE_FORMAT) end - @queries = { ':active' => lambda do |task| /(new|started|blocked)/.match(task[:state]) end, ':done' => lambda do |task| 'done' == task[:state] end, @@ -395,7 +394,7 @@ def filter_tasks(tasks, patterns) end items[num] = task if match end - return items + items end def colorize(text, color) @@ -403,16 +402,11 @@ def colorize(text, color) end def convert_due_date(date) - due = nil day_index = @due_date_days.index(date.to_s.downcase) || DUE_DATE_DAYS_SIMPLE.index(date.to_s.downcase) || @due_date_days.map do |day| day[0..2] end.index(date.to_s.downcase) - if day_index - due = (@today + day_index).strftime(DATE_FORMAT) - else - due = date.nil? || date.empty? ? nil : Date.parse(/^\d{4}-\d{2}-\d{2}$/.match(date).to_s).strftime(DATE_FORMAT) - end - return due + return (@today + day_index).strftime(DATE_FORMAT) if day_index + date.nil? || date.empty? ? nil : Date.parse(DATE_PATTERN.match(date).to_s).strftime(DATE_FORMAT) end end diff --git a/todo.gemspec b/todo.gemspec index 2dacae2..8a7dd38 100644 --- a/todo.gemspec +++ b/todo.gemspec @@ -1,7 +1,7 @@ Gem::Specification.new do |s| s.name = 'todo-jsonl' - s.version = '0.1.32' - s.date = '2021-03-17' + s.version = '0.1.33' + s.date = '2021-03-18' s.summary = 'todo list manager on the command-line inspired by todo.txt using the jsonl format' s.authors = ['Gabor Bata'] s.homepage = 'https://github.com/gaborbata/todo' diff --git a/web/app.js b/web/app.js index 8cfd964..7ac64d3 100644 --- a/web/app.js +++ b/web/app.js @@ -723,14 +723,14 @@ ua=function(S,ya){var Ca=ua.$$p,Va=Ca||y,cb,db,ab=y;ab=ab=y;Ca&&(ua.$$p=null);Ca Pa=function(){return this.$wday()["$=="](3)},Pa.$$arity=0);a.def(v,"$year",Ja=function(){return this.date.getFullYear()},Ja.$$arity=0);a.def(v,"$cwday",fb=function(){return this.date.getDay()||7},fb.$$arity=0);a.def(v,"$cweek",kb=function(){var S=new Date(this.date);S.setHours(0,0,0);S.setDate(S.getDate()+4-(S.getDay()||7));return Math.ceil(((S-new Date(S.getFullYear(),0,1))/864E5+1)/7)},kb.$$arity=0)}(t[0],null,t)}; Opal.modules.todo=function(a){function w(H,e){return"number"===typeof H&&"number"===typeof e?H+e:H["$+"](e)}function F(H,e){return"number"===typeof H&&"number"===typeof e?H>e:H["$>"](e)}function p(H,e){return"number"===typeof H&&"number"===typeof e?H $length $change_state $to_i $list $< $set_priority $due_date $append $rename $!= $delete $add_note $delete_note $show $push $strip $usage $cleanup $colorize $gsub $to_s $private $keys $map $select $parse $strftime $today $downcase $lambda $match $== $! $each $split $chomp $[]= $- $has_key? $sort $generate $convert_due_date $postprocess_tags $load_tasks $call $write_tasks $update_task $max $size $& $sort_by $filter_tasks $start_with? $abs $rjust $kind_of? $to_a $each_key $all? $uniq $index".split(" ")); y.$require("json");y.$require("date");return function(H,$super,n){H=f(H,$super,"Todo");var J=[H].concat(n),D,T,ia,da,ma,b,m,g,r,A,E,I,L,ba,va,Oa,wa,Aa,La,na,U,ra,xa,Ia;H.$$prototype.text_buffer=H.$$prototype.queries=H.$$prototype.today=H.$$prototype.due_date_days=d;a.const_set(J[0],"COLOR_CODES",h("black red green yellow blue magenta cyan white".split(" "),{black:30,red:31,green:32,yellow:33,blue:34,magenta:35,cyan:36,white:37}));a.const_set(J[0],"STATES",h(["new","done","started","blocked","default"], -{"new":"[ ]",done:"[x]",started:"[>]",blocked:"[!]","default":"[?]"}));a.const_set(J[0],"ORDER",h(["new","done","started","blocked","default"],{"new":3,done:4,started:2,blocked:1,"default":100}));a.const_set(J[0],"COLORS",h(["new","done","started","blocked","default"],{"new":"white",done:"blue",started:"green",blocked:"yellow","default":"magenta"}));a.const_set(J[0],"DATE_FORMAT","%Y-%m-%d");a.const_set(J[0],"DUE_DATE_DAYS_SIMPLE",["today","tomorrow"]);a.const_set(J[0],"DUE_DATE_TAG_PATTERN",/(^| )due:([a-zA-Z0-9-]+)/); -a.const_set(J[0],"CONTEXT_TAG_PATTERN",/(^| )[@+][\w-]+/);a.const_set(J[0],"PRIORITY_FLAG","*");a.const_set(J[0],"TODO_FILE","todo.jsonl");a.def(H,"$execute",D=function(ka){var N=d,M=d,ja=d,sa=d,ea=d,ua=d,Fa=d,Ga=d,Ra=d,Pa=d,Ja=d,fb=d;this.text_buffer=[];try{this.$setup(),N=ka.$first(),M=v(ja=ka["$[]"](c(1,-1,!1)))?ja:[],sa=N,"add"["$==="](sa)?(v(v(ea=M["$nil?"]())?ea:M["$empty?"]())&&this.$raise(w(N," command requires at least one parameter")),this.$add(M.$join(" "))):"start"["$==="](sa)?v(F(M.$length(), -0))?this.$change_state(M.$first().$to_i(),"started",(v(ua=M["$[]"](c(1,-1,!1)))?ua:[]).$join(" ")):this.$list(d,[":started"]):"done"["$==="](sa)?v(F(M.$length(),0))?this.$change_state(M.$first().$to_i(),"done",(v(Fa=M["$[]"](c(1,-1,!1)))?Fa:[]).$join(" ")):this.$list(d,[":done"]):"block"["$==="](sa)?v(F(M.$length(),0))?this.$change_state(M.$first().$to_i(),"blocked",(v(Ga=M["$[]"](c(1,-1,!1)))?Ga:[]).$join(" ")):this.$list(d,[":blocked"]):"reset"["$==="](sa)?v(F(M.$length(),0))?this.$change_state(M.$first().$to_i(), -"new",(v(Ra=M["$[]"](c(1,-1,!1)))?Ra:[]).$join(" ")):this.$list(d,[":new"]):"prio"["$==="](sa)?(v(p(M.$length(),1))&&this.$raise(w(N," command requires at least one parameter")),this.$set_priority(M.$first().$to_i(),(v(Pa=M["$[]"](c(1,-1,!1)))?Pa:[]).$join(" "))):"due"["$==="](sa)?(v(p(M.$length(),1))&&this.$raise(w(N," command requires at least one parameter")),this.$due_date(M.$first().$to_i(),(v(Ja=M["$[]"](c(1,-1,!1)))?Ja:[]).$join(" "))):"append"["$==="](sa)?(v(p(M.$length(),2))&&this.$raise(w(N, -" command requires at least two parameters")),this.$append(M.$first().$to_i(),M["$[]"](c(1,-1,!1)).$join(" "))):"rename"["$==="](sa)?(v(p(M.$length(),2))&&this.$raise(w(N," command requires at least two parameters")),this.$rename(M.$first().$to_i(),M["$[]"](c(1,-1,!1)).$join(" "))):"del"["$==="](sa)?(v(M.$length()["$!="](1))&&this.$raise(w(N," command requires exactly one parameter")),this.$delete(M.$first().$to_i())):"note"["$==="](sa)?(v(p(M.$length(),2))&&this.$raise(w(N," command requires at least two parameters")), -this.$add_note(M.$first().$to_i(),M["$[]"](c(1,-1,!1)).$join(" "))):"delnote"["$==="](sa)?(v(M.$length()["$!="](1))&&this.$raise(w(N," command requires exactly one parameter")),this.$delete_note(M.$first().$to_i())):"list"["$==="](sa)?this.$list(d,M):"show"["$==="](sa)?(v(M.$length()["$!="](1))&&this.$raise(w(N," command requires exactly one parameter")),this.$show(M.$first().$to_i())):"help"["$==="](sa)?(v(F(M.$length(),0))&&this.$raise(w(N," command has no parameters")),this.text_buffer.$push(this.$usage().$strip())): -"cleanup"["$==="](sa)?(v(v(fb=M["$nil?"]())?fb:M["$empty?"]())&&this.$raise(w(N," command requires at least one parameter")),this.$cleanup(M)):this.$list(d,ka)}catch(kb){if(a.rescue(kb,[G(z(J,"JS"),"Error"),z(J,"RuntimeError")])){ka=kb;try{this.text_buffer.$push(""+this.$colorize("ERROR:","red")+" "+ka)}finally{a.pop_exception()}}else throw kb;}return this},D.$$arity=1);a.def(H,"$to_s",T=function(){var ka=d;return w((v(ka=this.text_buffer)?ka:[]).$join("\n"),"\n")},T.$$arity=0);a.def(H,"$to_html", -ia=function(){return w(w('',this.$to_s().$gsub("&","&").$gsub("<","<").$gsub(">",">").$gsub(" "," ").$gsub("\n","
").$gsub(/e\[0m/,"
").$gsub(/e\[(\d+)m/,'')),"")},ia.$$arity=0);H.$private();a.def(H,"$usage",da=function(){var ka,N;return"Usage: todo \n\nCommands:\n* add add new task\n* start [text] mark task as started, with optional note\n* done [text] mark task as completed, with optional note\n* block [text] mark task as blocked, with optional note\n* reset [text] reset task to new state, with optional note\n* prio [text] toggle high priority flag, with optional note\n* due [date] set/unset due date (in YYYY-MM-DD format)\n\n* append append text to task title\n* rename rename task\n* del delete task\n* note add note to task\n* delnote delete all notes from task\n\n* list [regex...] list tasks (only active tasks by default)\n* show show all task details\n* cleanup [regex...] cleanup completed tasks by regex\n* help this help screen\n\nWith list command the following pre-defined regex patterns can be also used:\n"+ +{"new":"[ ]",done:"[x]",started:"[>]",blocked:"[!]","default":"[?]"}));a.const_set(J[0],"ORDER",h(["new","done","started","blocked","default"],{"new":3,done:4,started:2,blocked:1,"default":100}));a.const_set(J[0],"COLORS",h(["new","done","started","blocked","default"],{"new":"white",done:"blue",started:"green",blocked:"yellow","default":"magenta"}));a.const_set(J[0],"DATE_FORMAT","%Y-%m-%d");a.const_set(J[0],"DATE_PATTERN",/^[1-9]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/);a.const_set(J[0],"DUE_DATE_DAYS_SIMPLE", +["today","tomorrow"]);a.const_set(J[0],"DUE_DATE_TAG_PATTERN",/(^| )due:([a-zA-Z0-9-]+)/);a.const_set(J[0],"CONTEXT_TAG_PATTERN",/(^| )[@+][\w-]+/);a.const_set(J[0],"PRIORITY_FLAG","*");a.const_set(J[0],"TODO_FILE","todo.jsonl");a.def(H,"$execute",D=function(ka){var N=d,M=d,ja=d,sa=d,ea=d,ua=d,Fa=d,Ga=d,Ra=d,Pa=d,Ja=d,fb=d;this.text_buffer=[];try{this.$setup(),N=ka.$first(),M=v(ja=ka["$[]"](c(1,-1,!1)))?ja:[],sa=N,"add"["$==="](sa)?(v(v(ea=M["$nil?"]())?ea:M["$empty?"]())&&this.$raise(w(N," command requires at least one parameter")), +this.$add(M.$join(" "))):"start"["$==="](sa)?v(F(M.$length(),0))?this.$change_state(M.$first().$to_i(),"started",(v(ua=M["$[]"](c(1,-1,!1)))?ua:[]).$join(" ")):this.$list(d,[":started"]):"done"["$==="](sa)?v(F(M.$length(),0))?this.$change_state(M.$first().$to_i(),"done",(v(Fa=M["$[]"](c(1,-1,!1)))?Fa:[]).$join(" ")):this.$list(d,[":done"]):"block"["$==="](sa)?v(F(M.$length(),0))?this.$change_state(M.$first().$to_i(),"blocked",(v(Ga=M["$[]"](c(1,-1,!1)))?Ga:[]).$join(" ")):this.$list(d,[":blocked"]): +"reset"["$==="](sa)?v(F(M.$length(),0))?this.$change_state(M.$first().$to_i(),"new",(v(Ra=M["$[]"](c(1,-1,!1)))?Ra:[]).$join(" ")):this.$list(d,[":new"]):"prio"["$==="](sa)?(v(p(M.$length(),1))&&this.$raise(w(N," command requires at least one parameter")),this.$set_priority(M.$first().$to_i(),(v(Pa=M["$[]"](c(1,-1,!1)))?Pa:[]).$join(" "))):"due"["$==="](sa)?(v(p(M.$length(),1))&&this.$raise(w(N," command requires at least one parameter")),this.$due_date(M.$first().$to_i(),(v(Ja=M["$[]"](c(1,-1,!1)))? +Ja:[]).$join(" "))):"append"["$==="](sa)?(v(p(M.$length(),2))&&this.$raise(w(N," command requires at least two parameters")),this.$append(M.$first().$to_i(),M["$[]"](c(1,-1,!1)).$join(" "))):"rename"["$==="](sa)?(v(p(M.$length(),2))&&this.$raise(w(N," command requires at least two parameters")),this.$rename(M.$first().$to_i(),M["$[]"](c(1,-1,!1)).$join(" "))):"del"["$==="](sa)?(v(M.$length()["$!="](1))&&this.$raise(w(N," command requires exactly one parameter")),this.$delete(M.$first().$to_i())): +"note"["$==="](sa)?(v(p(M.$length(),2))&&this.$raise(w(N," command requires at least two parameters")),this.$add_note(M.$first().$to_i(),M["$[]"](c(1,-1,!1)).$join(" "))):"delnote"["$==="](sa)?(v(M.$length()["$!="](1))&&this.$raise(w(N," command requires exactly one parameter")),this.$delete_note(M.$first().$to_i())):"list"["$==="](sa)?this.$list(d,M):"show"["$==="](sa)?(v(M.$length()["$!="](1))&&this.$raise(w(N," command requires exactly one parameter")),this.$show(M.$first().$to_i())):"help"["$==="](sa)? +(v(F(M.$length(),0))&&this.$raise(w(N," command has no parameters")),this.text_buffer.$push(this.$usage().$strip())):"cleanup"["$==="](sa)?(v(v(fb=M["$nil?"]())?fb:M["$empty?"]())&&this.$raise(w(N," command requires at least one parameter")),this.$cleanup(M)):this.$list(d,ka)}catch(kb){if(a.rescue(kb,[G(z(J,"JS"),"Error"),z(J,"RuntimeError")])){ka=kb;try{this.text_buffer.$push(""+this.$colorize("ERROR:","red")+" "+ka)}finally{a.pop_exception()}}else throw kb;}return this},D.$$arity=1);a.def(H,"$to_s", +T=function(){var ka=d;return w((v(ka=this.text_buffer)?ka:[]).$join("\n"),"\n")},T.$$arity=0);a.def(H,"$to_html",ia=function(){return w(w('',this.$to_s().$gsub("&","&").$gsub("<","<").$gsub(">",">").$gsub(" "," ").$gsub("\n","
").$gsub(/e\[0m/,"
").$gsub(/e\[(\d+)m/,'')),"")},ia.$$arity=0);H.$private();a.def(H,"$usage",da=function(){var ka,N;return"Usage: todo \n\nCommands:\n* add add new task\n* start [text] mark task as started, with optional note\n* done [text] mark task as completed, with optional note\n* block [text] mark task as blocked, with optional note\n* reset [text] reset task to new state, with optional note\n* prio [text] toggle high priority flag, with optional note\n* due [date] set/unset due date (in YYYY-MM-DD format)\n\n* append append text to task title\n* rename rename task\n* del delete task\n* note add note to task\n* delnote delete all notes from task\n\n* list [regex...] list tasks (only active tasks by default)\n* show show all task details\n* cleanup [regex...] cleanup completed tasks by regex\n* help this help screen\n\nWith list command the following pre-defined regex patterns can be also used:\n"+ this.queries.$keys().$join(", ")+'\n\nDue dates can be also added via tags in task title: "due:YYYY-MM-DD"\n\nLegend:\n'+l(l(z(J,"STATES"),"select",[],(ka=function(M){null==M&&(M=d);return M["$!="]("default")},ka.$$s=this,ka.$$arity=2,ka)),"map",[],(N=function(M,ja){null==M&&(M=d);null==ja&&(ja=d);return""+M+" "+ja},N.$$s=this,N.$$arity=2,N)).$join(", ")+", priority "+z(J,"PRIORITY_FLAG")+"\n\nLocal storage: "+z(J,"TODO_FILE")+"\n"},da.$$arity=0);a.def(H,"$setup",ma=function(){var ka,N,M,ja,sa,ea, ua,Fa,Ga,Ra,Pa,Ja,fb=d,kb=d;this.today=z(J,"Date").$parse(z(J,"Date").$today().$strftime(z(J,"DATE_FORMAT")));fb=l(c(0,6,!1),"map",[],(ka=function(S){var ya=null==ka.$$s?this:ka.$$s;null==ya.today&&(ya.today=d);null==S&&(S=d);return w(ya.today,S)},ka.$$s=this,ka.$$arity=1,ka));this.due_date_days=l(fb,"map",[],(N=function(S){null==S&&(S=d);return S.$strftime("%A").$downcase()},N.$$s=this,N.$$arity=1,N));kb=l(fb,"map",[],(M=function(S){null==S&&(S=d);return S.$strftime(z(J,"DATE_FORMAT"))},M.$$s=this, M.$$arity=1,M));return this.queries=h(":active :done :blocked :started :new :all :today :tomorrow :next7days".split(" "),{":active":l(this,"lambda",[],(ja=function(S){null==S&&(S=d);return/(new|started|blocked)/.$match(S["$[]"]("state"))},ja.$$s=this,ja.$$arity=1,ja)),":done":l(this,"lambda",[],(sa=function(S){null==S&&(S=d);return"done"["$=="](S["$[]"]("state"))},sa.$$s=this,sa.$$arity=1,sa)),":blocked":l(this,"lambda",[],(ea=function(S){null==S&&(S=d);return"blocked"["$=="](S["$[]"]("state"))}, @@ -751,8 +751,8 @@ ya+cb)},ja.$$s=this,ja.$$arity=2,ja));return v(Fa["$empty?"]())?this.text_buffer l(this,"lambda",[],(N=function(M){null==M&&(M=d);return M.$delete("note")},N.$$s=this,N.$$arity=1,N)))},La.$$arity=1);a.def(H,"$show",na=function(ka,N){var M,ja=d;null==N&&(N=d);N=v(ja=N)?ja:this.$load_tasks(ka);return l(N["$[]"](ka),"each",[],(M=function(sa,ea){var ua=null==M.$$s?this:M.$$s;null==ua.text_buffer&&(ua.text_buffer=d);null==sa&&(sa=d);null==ea&&(ea=d);ea=v(ea["$kind_of?"](z(J,"Array")))?w("\n",ea.$join("\n")):ea;return ua.text_buffer.$push(""+ua.$colorize(w(sa.$to_s().$rjust(10," "), ":"),"cyan")+" "+ea)},M.$$s=this,M.$$arity=2,M))},na.$$arity=-2);a.def(H,"$cleanup",U=function(ka){var N,M=d,ja=d;M=this.$load_tasks();ka=w([":done"],ka.$to_a());ja=this.$filter_tasks(M,ka);l(ja,"each_key",[],(N=function(sa){null==sa&&(sa=d);return M.$delete(sa)},N.$$s=this,N.$$arity=1,N));this.$write_tasks(M);return this.text_buffer.$push("Deleted "+ja.$size()+" todo(s)")},U.$$arity=1);a.def(H,"$filter_tasks",ra=function(ka,N){var M,ja=d;ja=h([],{});l(ka,"each",[],(M=function(sa,ea){var ua=null== M.$$s?this:M.$$s,Fa,Ga=d;Ga=d;null==sa&&(sa=d);null==ea&&(ea=d);Ga=l(N.$uniq(),"all?",[],(Fa=function(Ra){var Pa=null==Fa.$$s?this:Fa.$$s;null==Pa.queries&&(Pa.queries=d);null==Ra&&(Ra=d);return v(Pa.queries["$[]"](Ra))?Pa.queries["$[]"](Ra).$call(ea):a.regexp([Ra],"i").$match(ea["$[]"]("title"))},Fa.$$s=ua,Fa.$$arity=1,Fa));return v(Ga)?(Ga=[sa,ea],l(ja,"[]=",a.to_a(Ga)),Ga[t(Ga.length,1)]):d},M.$$s=this,M.$$arity=2,M));return ja},ra.$$arity=2);a.def(H,"$colorize",xa=function(ka,N){var M=d;return"e["+ -(v(M=z(J,"COLOR_CODES")["$[]"](N))?M:37)+"m"+ka+"e[0m"},xa.$$arity=2);return(a.def(H,"$convert_due_date",Ia=function(ka){var N,M=this,ja=d,sa=ja=d,ea=d,ua=d;ja=d;ja=function(){return v(sa=v(ea=M.due_date_days.$index(ka.$to_s().$downcase()))?ea:z(J,"DUE_DATE_DAYS_SIMPLE").$index(ka.$to_s().$downcase()))?sa:l(M.due_date_days,"map",[],(N=function(Fa){null==Fa&&(Fa=d);return Fa["$[]"](c(0,2,!1))},N.$$s=M,N.$$arity=1,N)).$index(ka.$to_s().$downcase())}();return ja=v(ja)?w(M.today,ja).$strftime(z(J,"DATE_FORMAT")): -v(v(ua=ka["$nil?"]())?ua:ka["$empty?"]())?d:z(J,"Date").$parse(/^\d{4}-\d{2}-\d{2}$/.$match(ka).$to_s()).$strftime(z(J,"DATE_FORMAT"))},Ia.$$arity=1),d)&&"convert_due_date"}(q[0],null,q)}; -(function(a){var w,F=a.top,p=[],t=a.nil,y=a.$$$,q=a.$$,d=a.send,G=t,z=t;a.add_stubs("$require $new $lambda $to_html $execute $+".split(" "));F.$require("./todo.js.rb");G=q(p,"Todo").$new();z=d(F,"lambda",[],(w=function(f,h,v){null==f&&(f=t);null==h&&(h=t);null==v&&(v=t);var c=f.output,l=G,H=l.$execute;h=[h];v="number"===typeof h&&"number"===typeof v?h+v:h["$+"](v);return c.call(f,H.call(l,v).$to_html())},w.$$s=F,w.$$arity=3,w));(new VanillaTerminal({welcome:'todo list manager REPL v0.1.32
Type "help" or "copyright" for more information.

', +(v(M=z(J,"COLOR_CODES")["$[]"](N))?M:37)+"m"+ka+"e[0m"},xa.$$arity=2);return(a.def(H,"$convert_due_date",Ia=function(ka){var N,M=this,ja=d,sa=d,ea=d,ua=d;ja=function(){return v(sa=v(ea=M.due_date_days.$index(ka.$to_s().$downcase()))?ea:z(J,"DUE_DATE_DAYS_SIMPLE").$index(ka.$to_s().$downcase()))?sa:l(M.due_date_days,"map",[],(N=function(Fa){null==Fa&&(Fa=d);return Fa["$[]"](c(0,2,!1))},N.$$s=M,N.$$arity=1,N)).$index(ka.$to_s().$downcase())}();return v(ja)?w(M.today,ja).$strftime(z(J,"DATE_FORMAT")): +v(v(ua=ka["$nil?"]())?ua:ka["$empty?"]())?d:z(J,"Date").$parse(z(J,"DATE_PATTERN").$match(ka).$to_s()).$strftime(z(J,"DATE_FORMAT"))},Ia.$$arity=1),d)&&"convert_due_date"}(q[0],null,q)}; +(function(a){var w,F=a.top,p=[],t=a.nil,y=a.$$$,q=a.$$,d=a.send,G=t,z=t;a.add_stubs("$require $new $lambda $to_html $execute $+".split(" "));F.$require("./todo.js.rb");G=q(p,"Todo").$new();z=d(F,"lambda",[],(w=function(f,h,v){null==f&&(f=t);null==h&&(h=t);null==v&&(v=t);var c=f.output,l=G,H=l.$execute;h=[h];v="number"===typeof h&&"number"===typeof v?h+v:h["$+"](v);return c.call(f,H.call(l,v).$to_html())},w.$$s=F,w.$$arity=3,w));(new VanillaTerminal({welcome:'todo list manager REPL v0.1.33
Type "help" or "copyright" for more information.

', defaultCallback:z,prompt:"todo",commands:{cls:function(f){f.clear()},copyright:function(f){f.output('todo-jsonl - Copyright (c) 2020-2021 Gabor Bata
opal - Copyright (c) 2013-2021 Adam Beynon and the Opal contributors
vanilla-terminal - Copyright (c) 2018 Javier Jimenez Villar
')},wipe:function(f){f.prompt("Are you sure remove all your todo data? y/n",function(h){"Y"===h.trim().toUpperCase()&&(localStorage.removeItem(y(q(p,"Todo"),"TODO_FILE")),f.history=[],f.historyCursor= 0,f.output("todo data wiped"))})}}})).output(G.$execute(["list"]).$to_html())})(Opal);var Qb=Opal.$$;Opal.add_stubs(["$exit"]);Qb([],"Kernel").$exit();}).call(this); diff --git a/web/app.js.rb b/web/app.js.rb index d8af61a..c069bc0 100644 --- a/web/app.js.rb +++ b/web/app.js.rb @@ -8,7 +8,7 @@ ` var term = new VanillaTerminal({ - 'welcome': 'todo list manager REPL v0.1.32
Type "help" or "copyright" for more information.

', + 'welcome': 'todo list manager REPL v0.1.33
Type "help" or "copyright" for more information.

', 'defaultCallback': default_callback, 'prompt': 'todo', 'commands': { diff --git a/web/todo.js.rb b/web/todo.js.rb index 782d428..8cadab3 100644 --- a/web/todo.js.rb +++ b/web/todo.js.rb @@ -29,7 +29,6 @@ require 'date' class Todo - COLOR_CODES = { black: 30, red: 31, @@ -66,11 +65,12 @@ class Todo } DATE_FORMAT = '%Y-%m-%d' + DATE_PATTERN = /^[1-9]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/ DUE_DATE_DAYS_SIMPLE = ['today', 'tomorrow'] DUE_DATE_TAG_PATTERN = /(^| )due:([a-zA-Z0-9-]+)/ CONTEXT_TAG_PATTERN = /(^| )[@+][\w-]+/ PRIORITY_FLAG = '*' - TODO_FILE = "todo.jsonl" + TODO_FILE = 'todo.jsonl' def execute(arguments) @text_buffer = [] @@ -189,7 +189,6 @@ def setup next_7_days = (0..6).map do |day| @today + day end @due_date_days = next_7_days.map do |day| day.strftime('%A').downcase end due_dates_for_queries = next_7_days.map do |day| day.strftime(DATE_FORMAT) end - @queries = { ':active' => lambda do |task| /(new|started|blocked)/.match(task[:state]) end, ':done' => lambda do |task| 'done' == task[:state] end, @@ -206,7 +205,6 @@ def setup def load_tasks(item_to_check = nil) count = 0 tasks = {} - todo_jsonl = `window.localStorage.getItem(#{TODO_FILE}) || ''` if !todo_jsonl.empty? todo_jsonl.split("\n").each do |line| @@ -376,7 +374,7 @@ def filter_tasks(tasks, patterns) end items[num] = task if match end - return items + items end def colorize(text, color) @@ -384,15 +382,10 @@ def colorize(text, color) end def convert_due_date(date) - due = nil day_index = @due_date_days.index(date.to_s.downcase) || DUE_DATE_DAYS_SIMPLE.index(date.to_s.downcase) || @due_date_days.map do |day| day[0..2] end.index(date.to_s.downcase) - if day_index - due = (@today + day_index).strftime(DATE_FORMAT) - else - due = date.nil? || date.empty? ? nil : Date.parse(/^\d{4}-\d{2}-\d{2}$/.match(date).to_s).strftime(DATE_FORMAT) - end - return due + return (@today + day_index).strftime(DATE_FORMAT) if day_index + date.nil? || date.empty? ? nil : Date.parse(DATE_PATTERN.match(date).to_s).strftime(DATE_FORMAT) end end