From mboxrd@z Thu Jan 1 00:00:00 1970 From: John Wiegley Subject: Added support for "habit tracking" Date: Mon, 19 Oct 2009 04:26:02 -0400 Message-ID: Mime-Version: 1.0 (Apple Message framework v1075.2) Content-Type: multipart/mixed; boundary=Apple-Mail-10-608171745 Return-path: Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1MznZG-0006M3-56 for emacs-orgmode@gnu.org; Mon, 19 Oct 2009 04:26:14 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1MznZB-0006LP-97 for emacs-orgmode@gnu.org; Mon, 19 Oct 2009 04:26:13 -0400 Received: from [199.232.76.173] (port=42360 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1MznZB-0006LF-3I for emacs-orgmode@gnu.org; Mon, 19 Oct 2009 04:26:09 -0400 Received: from mail-qy0-f183.google.com ([209.85.221.183]:65492) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1MznZ8-000209-2o for emacs-orgmode@gnu.org; Mon, 19 Oct 2009 04:26:07 -0400 Received: by qyk13 with SMTP id 13so1040206qyk.27 for ; Mon, 19 Oct 2009 01:26:05 -0700 (PDT) List-Id: "General discussions about Org-mode." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: emacs-orgmode-bounces+geo-emacs-orgmode=m.gmane.org@gnu.org Errors-To: emacs-orgmode-bounces+geo-emacs-orgmode=m.gmane.org@gnu.org To: Org-mode Mode --Apple-Mail-10-608171745 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=us-ascii; format=flowed; delsp=yes There are really two kinds of TODOs on people's lists: 1. Those whose importance is that they get done. 2. Those whose importance is that they are done consistently. I think most married people will know what I mean. If you wash the dishes once after not having done it all month, you're not likely to win much applause. But if you mow the lawn every month like clockwork, it's the regularity that does it. Tracking habits isn't suited to a regular task manager, however. You can see that the task needs to be done in your agenda, but you don't know if it's a task that sorely needs attention because you've been neglecting it, or if you've really been on the ball and don't _have_ to do it today. In the commercial world there is an app to address this kind of task called Sciral Consistency (http://sciral.com/consistency/). I've been using it for about a year, and it's fantastic for making sure I keep up on my everyday duties, both at work and at home. Well, I've implemented the functionality of Sciral for Org. It works just as described on the Sciral webpage, complete with colorful graphs that appear to the right of the task name in the agenda buffer. The graph even follows the same coloring algorithm as Sciral. To test out this new feature, apply the attached patches and read the new manual section on "Tracking your habits". John --Apple-Mail-10-608171745 Content-Disposition: attachment; filename=0001-Improvement-to-org-repeat-re.patch Content-Type: application/octet-stream; name="0001-Improvement-to-org-repeat-re.patch" Content-Transfer-Encoding: quoted-printable =46rom=2049cbd5355a8d76fe64cbad8785807f1166097096=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20John=20Wiegley=20=0A= Date:=20Mon,=2019=20Oct=202009=2003:58:45=20-0400=0ASubject:=20[PATCH=20= 1/5]=20Improvement=20to=20`org-repeat-re'=0A=0A(org-repeat-re):=20= Improved=20regexp=20to=20include=20.+=20and=20++=20leaders=20for=20= repeat=0Astrings.=0A---=0A=20lisp/ChangeLog=20|=20=20=20=205=20+++++=0A=20= lisp/org.el=20=20=20=20|=20=20=20=202=20+-=0A=202=20files=20changed,=206=20= insertions(+),=201=20deletions(-)=0A=0Adiff=20--git=20a/lisp/ChangeLog=20= b/lisp/ChangeLog=0Aindex=20c437305..efb6466=20100755=0A---=20= a/lisp/ChangeLog=0A+++=20b/lisp/ChangeLog=0A@@=20-1,5=20+1,10=20@@=0A=20= 2009-10-19=20=20John=20Wiegley=20=20=0A=20=0A+=09= *=20org.el=20(org-repeat-re):=20Improved=20regexp=20to=20include=20.+=20= and=20++=0A+=09leaders=20for=20repeat=20strings.=0A+=0A+2009-10-19=20=20= John=20Wiegley=20=20=0A+=0A=20=09*=20= org-agenda.el=20(org-agenda-auto-exclude-function):=20New=0A=20=09= customization=20variable=20for=20allowing=20the=20user=20to=20create=20= an=20"auto=0A=20=09exclusion"=20filter=20for=20doing=20context-aware=20= auto=20tag=20filtering.=0Adiff=20--git=20a/lisp/org.el=20b/lisp/org.el=0A= index=205b254d1..182234e=20100644=0A---=20a/lisp/org.el=0A+++=20= b/lisp/org.el=0A@@=20-474,7=20+474,7=20@@=20An=20entry=20can=20be=20= toggled=20between=20QUOTE=20and=20normal=20with=0A=20=20=20:type=20= 'string)=0A=20=0A=20(defconst=20org-repeat-re=0A-=20=20= "<[0-9]\\{4\\}-[0-9][0-9]-[0-9][0-9]=20= [^>\n]*\\([.+]?\\+[0-9]+[dwmy]\\)"=0A+=20=20= "<[0-9]\\{4\\}-[0-9][0-9]-[0-9][0-9]=20= [^>\n]*\\([.+]+?\\+[0-9]+[dwmy]\\)"=0A=20=20=20"Regular=20expression=20= for=20specifying=20repeated=20events.=0A=20After=20a=20match,=20group=20= 1=20contains=20the=20repeat=20expression.")=0A=20=0A--=20=0A1.6.5=0A=0A= --Apple-Mail-10-608171745 Content-Disposition: attachment; filename=0002-Added-tagline-parameter-to-org-get-repeat.patch Content-Type: application/octet-stream; name="0002-Added-tagline-parameter-to-org-get-repeat.patch" Content-Transfer-Encoding: quoted-printable =46rom=20f604a7ecec7295cfbe4dd38519d38e16b51d9080=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20John=20Wiegley=20=0A= Date:=20Mon,=2019=20Oct=202009=2003:59:42=20-0400=0ASubject:=20[PATCH=20= 2/5]=20Added=20tagline=20parameter=20to=20`org-get-repeat'=0A=0A= (org-get-repeat):=20Now=20takes=20a=20string=20parameter=20`tagline',=20= so=20the=20caller=0Acan=20obtain=20the=20SCHEDULED=20repeat,=20or=20the=20= DEADLINE=20repeat.=0A---=0A=20lisp/ChangeLog=20|=20=20=20=202=20++=0A=20= lisp/org.el=20=20=20=20|=20=20=2010=20++++++----=0A=202=20files=20= changed,=208=20insertions(+),=204=20deletions(-)=0A=0Adiff=20--git=20= a/lisp/ChangeLog=20b/lisp/ChangeLog=0Aindex=20efb6466..a5f8b7f=20100755=0A= ---=20a/lisp/ChangeLog=0A+++=20b/lisp/ChangeLog=0A@@=20-2,6=20+2,8=20@@=0A= =20=0A=20=09*=20org.el=20(org-repeat-re):=20Improved=20regexp=20to=20= include=20.+=20and=20++=0A=20=09leaders=20for=20repeat=20strings.=0A+=09= (org-get-repeat):=20Now=20takes=20a=20string=20parameter=20`tagline',=20= so=20the=0A+=09caller=20can=20obtain=20the=20SCHEDULED=20repeat,=20or=20= the=20DEADLINE=20repeat.=0A=20=0A=202009-10-19=20=20John=20Wiegley=20=20= =0A=20=0Adiff=20--git=20a/lisp/org.el=20= b/lisp/org.el=0Aindex=20182234e..2b202d8=20100644=0A---=20a/lisp/org.el=0A= +++=20b/lisp/org.el=0A@@=20-10047,14=20+10047,16=20@@=20Returns=20the=20= new=20TODO=20keyword,=20or=20nil=20if=20no=20state=20change=20should=20= occur."=0A=20=09=20=20=20=20=20(throw=20'exit=20t)))=0A=20=20=20=20=20=20= =20nil)))=0A=20=0A-(defun=20org-get-repeat=20()=0A+(defun=20= org-get-repeat=20(&optional=20tagline)=0A=20=20=20"Check=20if=20there=20= is=20a=20deadline/schedule=20with=20repeater=20in=20this=20entry."=0A=20=20= =20(save-match-data=0A=20=20=20=20=20(save-excursion=0A=20=20=20=20=20=20= =20(org-back-to-heading=20t)=0A-=20=20=20=20=20=20(if=20= (re-search-forward=0A-=09=20=20=20org-repeat-re=20(save-excursion=20= (outline-next-heading)=20(point))=20t)=0A-=09=20=20(match-string=20= 1)))))=0A+=20=20=20=20=20=20(and=20(re-search-forward=20(if=20tagline=0A= +=09=09=09=09=20=20(concat=20tagline=20":[^:]+"=20org-repeat-re)=0A+=09=09= =09=09org-repeat-re)=0A+=09=09=09=20=20=20=20=20=20= (org-entry-end-position)=20t)=0A+=09=20=20=20(match-string-no-properties=20= 1)))))=0A=20=0A=20(defvar=20org-last-changed-timestamp)=0A=20(defvar=20= org-last-inserted-timestamp)=0A--=20=0A1.6.5=0A=0A= --Apple-Mail-10-608171745 Content-Disposition: attachment; filename=0003-Set-day-of-week-in-result-from-org-parse-time-string.patch Content-Type: application/octet-stream; name="0003-Set-day-of-week-in-result-from-org-parse-time-string.patch" Content-Transfer-Encoding: quoted-printable =46rom=20be58bd294b741a50474c276e8d719f731973257b=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20John=20Wiegley=20=0A= Date:=20Mon,=2019=20Oct=202009=2004:00:35=20-0400=0ASubject:=20[PATCH=20= 3/5]=20Set=20day-of-week=20in=20result=20from=20`org-parse-time-string'=0A= =0A(org-parse-time-string):=20Set=20the=20day-of-week=20field=20after=20= parsing=20a=20time,=0Asince=20this=20information=20is=20always=20in=20= the=20time=20string.=0A---=0A=20lisp/ChangeLog=20|=20=20=20=202=20++=0A=20= lisp/org.el=20=20=20=20|=20=20=20=209=20++++++++-=0A=202=20files=20= changed,=2010=20insertions(+),=201=20deletions(-)=0A=0Adiff=20--git=20= a/lisp/ChangeLog=20b/lisp/ChangeLog=0Aindex=20a5f8b7f..6810f7e=20100755=0A= ---=20a/lisp/ChangeLog=0A+++=20b/lisp/ChangeLog=0A@@=20-4,6=20+4,8=20@@=0A= =20=09leaders=20for=20repeat=20strings.=0A=20=09(org-get-repeat):=20Now=20= takes=20a=20string=20parameter=20`tagline',=20so=20the=0A=20=09caller=20= can=20obtain=20the=20SCHEDULED=20repeat,=20or=20the=20DEADLINE=20repeat.=0A= +=09(org-parse-time-string):=20Set=20the=20day-of-week=20field=20after=20= parsing=20a=0A+=09time,=20since=20this=20information=20is=20always=20in=20= the=20time=20string.=0A=20=0A=202009-10-19=20=20John=20Wiegley=20=20= =0A=20=0Adiff=20--git=20a/lisp/org.el=20= b/lisp/org.el=0Aindex=202b202d8..eb45eea=20100644=0A---=20a/lisp/org.el=0A= +++=20b/lisp/org.el=0A@@=20-13457,7=20+13457,14=20@@=20hour=20and=20= minute=20fields=20will=20be=20nil=20if=20not=20given."=0A=20=09=20=20=20=20= (string-to-number=20(match-string=204=20s))=0A=20=09=20=20=20=20= (string-to-number=20(match-string=203=20s))=0A=20=09=20=20=20=20= (string-to-number=20(match-string=202=20s))=0A-=09=20=20=20=20nil=20nil=20= nil)=0A+=09=20=20=20=20(let=20((dow=20(match-string=205=20s)))=0A+=09=20=20= =20=20=20=20(cond=20((string=3D=20dow=20"Sun")=200)=0A+=09=09=20=20=20=20= ((string=3D=20dow=20"Mon")=201)=0A+=09=09=20=20=20=20((string=3D=20dow=20= "Tue")=202)=0A+=09=09=20=20=20=20((string=3D=20dow=20"Wed")=203)=0A+=09=09= =20=20=20=20((string=3D=20dow=20"Thu")=204)=0A+=09=09=20=20=20=20= ((string=3D=20dow=20"Fri")=205)=0A+=09=09=20=20=20=20((string=3D=20dow=20= "Sat")=206)))=20nil=20nil)=0A=20=20=20=20=20(error=20"Not=20a=20standard=20= Org-mode=20time=20string:=20%s"=20s)))=0A=20=0A=20(defun=20= org-timestamp-up=20(&optional=20arg)=0A--=20=0A1.6.5=0A=0A= --Apple-Mail-10-608171745 Content-Disposition: attachment; filename=0004-Added-some-missing-text-to-the-manual.patch Content-Type: application/octet-stream; name="0004-Added-some-missing-text-to-the-manual.patch" Content-Transfer-Encoding: quoted-printable =46rom=203c0dfce39f4467b6fda19e1d3dfb9b675b214c37=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20John=20Wiegley=20=0A= Date:=20Mon,=2019=20Oct=202009=2004:04:07=20-0400=0ASubject:=20[PATCH=20= 4/5]=20Added=20some=20missing=20text=20to=20the=20manual=0A=0A---=0A=20= doc/org.texi=20|=20=20=20=202=20+-=0A=201=20files=20changed,=201=20= insertions(+),=201=20deletions(-)=0A=0Adiff=20--git=20a/doc/org.texi=20= b/doc/org.texi=0Aindex=205ae6575..b8e4eed=20100644=0A---=20= a/doc/org.texi=0A+++=20b/doc/org.texi=0A@@=20-231,7=20+231,7=20@@=20= Dates=20and=20Times=0A=20*=20Creating=20timestamps::=20=20=20=20=20=20=20= =20=20Commands=20which=20insert=20timestamps=0A=20*=20Deadlines=20and=20= scheduling::=20=20=20=20Planning=20your=20work=0A=20*=20Clocking=20work=20= time::=20=20=20=20=20=20=20=20=20=20Tracking=20how=20long=20you=20spend=20= on=20a=20task=0A-*=20Resolving=20idle=20time::=20=20=20=20=20=20=20=20=20= =0A+*=20Resolving=20idle=20time::=20=20=20=20=20=20=20=20=20Resolving=20= time=20if=20you've=20been=20idle=0A=20*=20Effort=20estimates::=20=20=20=20= =20=20=20=20=20=20=20=20Planning=20work=20effort=20in=20advance=0A=20*=20= Relative=20timer::=20=20=20=20=20=20=20=20=20=20=20=20=20=20Notes=20with=20= a=20running=20timer=0A=20=0A--=20=0A1.6.5=0A=0A= --Apple-Mail-10-608171745 Content-Disposition: attachment; filename=0005-Added-support-for-habit-consistency-tracking.patch Content-Type: application/octet-stream; name="0005-Added-support-for-habit-consistency-tracking.patch" Content-Transfer-Encoding: quoted-printable =46rom=20617ccd1c2afe267f464a8b692db41c23329b6326=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20John=20Wiegley=20=0A= Date:=20Mon,=2019=20Oct=202009=2004:17:49=20-0400=0ASubject:=20[PATCH=20= 5/5]=20Added=20support=20for=20habit=20consistency=20tracking=0A=0A= org-habit.el:=20New=20file,=20which=20implements=20code=20to=20build=20a=20= "habit=0Aconsistency=20graph".=0A=0Aorg-agenda.el=20= (org-agenda-get-deadlines)=0A(org-agenda-get-scheduled):=20Display=20= consistency=20graphs=20when=20outputting=0Ahabits=20into=20the=20agenda.=20= =20The=20graphs=20are=20always=20relative=20to=20the=20current=0Atime.=0A= =0A(org-format-agenda-item):=20Added=20new=20parameter=20`habitp',=20= which=20indicates=0Awhether=20we=20are=20formatting=20a=20habit=20or=20= not.=20=20Do=20not=20display=20"extra"=0Aleading=20information=20if=20= habitp=20is=20true.=0A---=0A=20doc/ChangeLog=20=20=20=20=20=20|=20=20=20=20= 5=20+=0A=20doc/org.texi=20=20=20=20=20=20=20|=20=20=2075=20= +++++++++++++++++-=0A=20lisp/ChangeLog=20=20=20=20=20|=20=20=2011=20+++=0A= =20lisp/org-agenda.el=20|=20=20=2056=20+++++++++++---=0A=20= lisp/org-habit.el=20=20|=20=20223=20= ++++++++++++++++++++++++++++++++++++++++++++++++++++=0A=205=20files=20= changed,=20358=20insertions(+),=2012=20deletions(-)=0A=20create=20mode=20= 100644=20lisp/org-habit.el=0A=0Adiff=20--git=20a/doc/ChangeLog=20= b/doc/ChangeLog=0Aindex=204ae3099..76fbd32=20100644=0A---=20= a/doc/ChangeLog=0A+++=20b/doc/ChangeLog=0A@@=20-1,3=20+1,8=20@@=0A= +2009-10-19=20=20John=20Wiegley=20=20=0A+=0A+=09*=20= org.texi=20(Tracking=20your=20habits):=20Added=20a=20new=20section=20in=20= the=0A+=09manual=20about=20how=20to=20track=20habits.=0A+=0A=20= 2009-10-18=20=20Carsten=20Dominik=20=20=0A=20=0A= =20=09*=20org.texi=20(Pushing=20to=20MobileOrg):=20Mention=20that=20= `org-directory'=0Adiff=20--git=20a/doc/org.texi=20b/doc/org.texi=0Aindex=20= b8e4eed..79606dc=20100644=0A---=20a/doc/org.texi=0A+++=20b/doc/org.texi=0A= @@=20-198,6=20+198,7=20@@=20Progress=20logging=0A=20=0A=20*=20Closing=20= items::=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20When=20was=20this=20= entry=20marked=20DONE?=0A=20*=20Tracking=20TODO=20state=20changes::=20=20= When=20did=20the=20status=20change?=0A+*=20Tracking=20your=20habits::=20=20= =20=20=20=20=20=20How=20consistent=20have=20you=20been?=0A=20=0A=20Tags=0A= =20=0A@@=20-231,7=20+232,7=20@@=20Dates=20and=20Times=0A=20*=20Creating=20= timestamps::=20=20=20=20=20=20=20=20=20Commands=20which=20insert=20= timestamps=0A=20*=20Deadlines=20and=20scheduling::=20=20=20=20Planning=20= your=20work=0A=20*=20Clocking=20work=20time::=20=20=20=20=20=20=20=20=20=20= Tracking=20how=20long=20you=20spend=20on=20a=20task=0A-*=20Resolving=20= idle=20time::=20=20=20=20=20=20=20=20=20Resolving=20time=20if=20you've=20= been=20idle=0A+*=20Resolving=20idle=20time::=20=20=20=20=20=20=20=20=20=0A= =20*=20Effort=20estimates::=20=20=20=20=20=20=20=20=20=20=20=20Planning=20= work=20effort=20in=20advance=0A=20*=20Relative=20timer::=20=20=20=20=20=20= =20=20=20=20=20=20=20=20Notes=20with=20a=20running=20timer=0A=20=0A@@=20= -3524,6=20+3525,7=20@@=20work=20time}.=0A=20@menu=0A=20*=20Closing=20= items::=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20When=20was=20this=20= entry=20marked=20DONE?=0A=20*=20Tracking=20TODO=20state=20changes::=20=20= When=20did=20the=20status=20change?=0A+*=20Tracking=20your=20habits::=20=20= =20=20=20=20=20=20=0A=20@end=20menu=0A=20=0A=20@node=20Closing=20items,=20= Tracking=20TODO=20state=20changes,=20Progress=20logging,=20Progress=20= logging=0A@@=20-3558,7=20+3560,7=20@@=20In=20the=20timeline=20= (@pxref{Timeline})=20and=20in=20the=20agenda=0A=20display=20the=20TODO=20= items=20with=20a=20@samp{CLOSED}=20timestamp=20on=20each=20day,=0A=20= giving=20you=20an=20overview=20of=20what=20has=20been=20done.=0A=20=0A= -@node=20Tracking=20TODO=20state=20changes,=20=20,=20Closing=20items,=20= Progress=20logging=0A+@node=20Tracking=20TODO=20state=20changes,=20= Tracking=20your=20habits,=20Closing=20items,=20Progress=20logging=0A=20= @subsection=20Tracking=20TODO=20state=20changes=0A=20@cindex=20drawer,=20= for=20state=20change=20recording=0A=20=0A@@=20-3635,6=20+3637,75=20@@=20= settings=20like=20@code{TODO(!)}.=20=20For=20example=0A=20=20=20:END:=0A=20= @end=20example=0A=20=0A+@node=20Tracking=20your=20habits,=20=20,=20= Tracking=20TODO=20state=20changes,=20Progress=20logging=0A+@subsection=20= Tracking=20your=20habits=0A+@cindex=20habits=0A+=0A+Org=20has=20the=20= ability=20to=20track=20the=20consistency=20of=20a=20special=20category=20= of=20TODOs,=0A+which=20are=20called=20``habits''.=20=20A=20habit=20has=20= the=20followed=20properties:=0A+=0A+@enumerate=0A+@item=0A+The=20= property=20@code{STYLE}=20is=20set=20to=20the=20value=20@code{habit}.=0A= +@item=0A+The=20TODO=20has=20a=20scheduled=20date,=20with=20a=20= @code{.+}=20style=20repeat=20interval.=0A+@item=0A+It=20may=20also=20= have=20a=20deadline=20set,=20as=20long=20as=20it=20also=20has=20a=20= @code{.+}=20style=0A+repeat=20interval,=20and=20it=20starts=20a=20number=20= of=20days=20after=20the=20scheduled=20date=0A+equal=20to=20the=20= difference=20between=20the=20repeat=20intervals.=20=20If=20you=20get=20= this=20wrong,=0A+Org=20will=20alert=20you=20to=20what=20you've=20set=20= incorrectly=20in=20your=20habit.=0A+@item=0A+You=20must=20also=20have=20= state=20logging=20on=20the=20@code{DONE}=20enabled,=20in=20order=20for=0A= +historical=20data=20to=20be=20represented=20in=20the=20consistency=20= graph.=0A+@end=20enumerate=0A+=0A+To=20give=20you=20an=20idea=20of=20= what=20the=20above=20rules=20look=20like,=20here=20is=20an=20actual=0A= +habit,=20with=20some=20history:=0A+=0A+@example=0A+**=20TODO=20Shave=0A= +=20=20=20SCHEDULED:=20<2009-10-17=20Sat=20.+2d>=20DEADLINE:=20= <2009-10-19=20Mon=20.+4d>=0A+=20=20=20-=20State=20"DONE"=20=20=20=20=20=20= =20from=20"TODO"=20=20=20=20=20=20=20[2009-10-15=20Thu]=0A+=20=20=20-=20= State=20"DONE"=20=20=20=20=20=20=20from=20"TODO"=20=20=20=20=20=20=20= [2009-10-12=20Mon]=0A+=20=20=20-=20State=20"DONE"=20=20=20=20=20=20=20= from=20"TODO"=20=20=20=20=20=20=20[2009-10-10=20Sat]=0A+=20=20=20-=20= State=20"DONE"=20=20=20=20=20=20=20from=20"TODO"=20=20=20=20=20=20=20= [2009-10-04=20Sun]=0A+=20=20=20-=20State=20"DONE"=20=20=20=20=20=20=20= from=20"TODO"=20=20=20=20=20=20=20[2009-10-02=20Fri]=0A+=20=20=20-=20= State=20"DONE"=20=20=20=20=20=20=20from=20"TODO"=20=20=20=20=20=20=20= [2009-09-29=20Tue]=0A+=20=20=20-=20State=20"DONE"=20=20=20=20=20=20=20= from=20"TODO"=20=20=20=20=20=20=20[2009-09-25=20Fri]=0A+=20=20=20-=20= State=20"DONE"=20=20=20=20=20=20=20from=20"TODO"=20=20=20=20=20=20=20= [2009-09-19=20Sat]=0A+=20=20=20-=20State=20"DONE"=20=20=20=20=20=20=20= from=20"TODO"=20=20=20=20=20=20=20[2009-09-16=20Wed]=0A+=20=20=20-=20= State=20"DONE"=20=20=20=20=20=20=20from=20"TODO"=20=20=20=20=20=20=20= [2009-09-12=20Sat]=0A+=20=20=20:PROPERTIES:=0A+=20=20=20:STYLE:=20=20=20=20= habit=0A+=20=20=20:LAST_REPEAT:=20[2009-10-19=20Mon=2000:36]=0A+=20=20=20= :END:=0A+@end=20example=0A+=0A+What=20this=20habit=20says=20is:=20I=20= want=20to=20shave=20at=20least=20every=204=20days,=20and=20at=20most=0A= +every=202=20days.=20=20Imagine=20today=20is=20the=2015th,=20for=20the=20= purposes=20of=20this=20example.=0A+This=20means=20the=20habit=20will=20= first=20appear=20in=20the=20agenda=20on=20Oct=2017,=20after=20the=0A= +minimum=20of=202=20days=20has=20elapsed,=20and=20will=20appear=20= overdue=20on=20Oct=2019,=20after=20four=0A+days=20have=20elapsed.=20=20= But=20what's=20really=20useful=20about=20habits=20is=20they=20are=0A= +displayed=20along=20with=20a=20conistency=20graph,=20which=20shows=20= how=20consistent=20you've=0A+been=20at=20getting=20task=20done=20in=20= the=20past.=20=20The=20graph=20shows=20every=20day=20that=20the=0A+task=20= was=20done=20over=20the=20past=20five=20weeks,=20with=20colors=20for=20= each=20day.=20=20The=20colors=0A+used=20are:=0A+=0A+@table=20@code=0A= +@item=20Blue=0A+If=20the=20task=20wasn't=20to=20be=20done=20yet=20on=20= that=20day.=0A+@item=20Green=0A+If=20the=20task=20could=20have=20been=20= done=20on=20that=20day.=0A+@item=20Yellow=0A+If=20the=20task=20was=20= going=20to=20be=20overdue=20on=20the=20next=20day.=0A+@item=20Red=0A+If=20= the=20task=20was=20overdue=20on=20that=20day.=0A+@end=20table=0A+=0A+In=20= addition=20to=20coloring=20each=20day,=20the=20day=20is=20also=20marked=20= with=20an=20asterix=20if=0A+the=20task=20was=20actually=20done=20that=20= day,=20and=20an=20exclamation=20mark=20to=20show=20where=0A+the=20= current=20day=20falls=20in=20the=20graph.=0A+=0A=20@node=20Priorities,=20= Breaking=20down=20tasks,=20Progress=20logging,=20TODO=20Items=0A=20= @section=20Priorities=0A=20@cindex=20priorities=0Adiff=20--git=20= a/lisp/ChangeLog=20b/lisp/ChangeLog=0Aindex=206810f7e..23bb298=20100755=0A= ---=20a/lisp/ChangeLog=0A+++=20b/lisp/ChangeLog=0A@@=20-1,5=20+1,16=20@@=0A= =202009-10-19=20=20John=20Wiegley=20=20=0A=20=0A+=09= *=20org-habit.el:=20New=20file,=20which=20implements=20code=20to=20build=20= a=20"habit=0A+=09consistency=20graph".=0A+=0A+=09*=20org-agenda.el=20= (org-agenda-get-deadlines)=0A+=09(org-agenda-get-scheduled):=20Display=20= consistency=20graphs=20when=0A+=09outputting=20habits=20into=20the=20= agenda.=20=20The=20graphs=20are=20always=20relative=0A+=09to=20the=20= current=20time.=0A+=09(org-format-agenda-item):=20Added=20new=20= parameter=20`habitp',=20which=0A+=09indicates=20whether=20we=20are=20= formatting=20a=20habit=20or=20not.=20=20Do=20not=0A+=09display=20"extra"=20= leading=20information=20if=20habitp=20is=20true.=0A+=0A=20=09*=20org.el=20= (org-repeat-re):=20Improved=20regexp=20to=20include=20.+=20and=20++=0A=20= =09leaders=20for=20repeat=20strings.=0A=20=09(org-get-repeat):=20Now=20= takes=20a=20string=20parameter=20`tagline',=20so=20the=0Adiff=20--git=20= a/lisp/org-agenda.el=20b/lisp/org-agenda.el=0Aindex=20730250b..71353df=20= 100644=0A---=20a/lisp/org-agenda.el=0A+++=20b/lisp/org-agenda.el=0A@@=20= -4215,7=20+4215,7=20@@=20the=20documentation=20of=20`org-diary'."=0A=20=09= =20(todayp=20(org-agenda-todayp=20date))=20;=20DATE=20bound=20by=20= calendar=0A=20=09=20(d1=20(calendar-absolute-from-gregorian=20date))=20=20= ;=20DATE=20bound=20by=20calendar=0A=20=09=20d2=20diff=20dfrac=20wdays=20= pos=20pos1=20category=20tags=0A-=09=20ee=20txt=20head=20face=20s=20= todo-state=20upcomingp=20donep=20timestr)=0A+=09=20ee=20txt=20head=20= face=20s=20todo-state=20upcomingp=20donep=20timestr=20habitp)=0A=20=20=20= =20=20(goto-char=20(point-min))=0A=20=20=20=20=20(while=20= (re-search-forward=20regexp=20nil=20t)=0A=20=20=20=20=20=20=20(catch=20= :skip=0A@@=20-4239,6=20+4239,7=20@@=20the=20documentation=20of=20= `org-diary'."=0A=20=09=20=20=20=20(save-excursion=0A=20=09=20=20=20=20=20= =20(setq=20todo-state=20(org-get-todo-state))=0A=20=09=20=20=20=20=20=20= (setq=20donep=20(member=20todo-state=20org-done-keywords))=0A+=09=20=20=20= =20=20=20(setq=20habitp=20(org-is-habit-p))=0A=20=09=20=20=20=20=20=20= (if=20(and=20donep=0A=20=09=09=20=20=20=20=20=20=20(or=20= org-agenda-skip-deadline-if-done=0A=20=09=09=09=20=20=20(not=20(=3D=20= diff=200))))=0A@@=20-4267,8=20+4268,14=20@@=20the=20documentation=20of=20= `org-diary'."=0A=20=09=09=09=09=20=20=20=20diff=20date)=0A=20=09=09=09=09= =20(format=20(nth=201=20org-agenda-deadline-leaders)=0A=20=09=09=09=09=09= =20diff)))=0A-=09=09=09=20=20=20=20=20head=20category=20tags=0A-=09=09=09= =20=20=20=20=20(if=20(not=20(=3D=20diff=200))=20nil=20timestr)))))=0A+=09= =09=09=20=20=20=20=20(if=20habitp=0A+=09=09=09=09=20(if=20(>=20(length=20= head)=2020)=0A+=09=09=09=09=20=20=20=20=20(substring=20head=200=2020)=0A= +=09=09=09=09=20=20=20(format=20"%-20s"=20head))=0A+=09=09=09=20=20=20=20= =20=20=20head)=0A+=09=09=09=20=20=20=20=20category=20tags=0A+=09=09=09=20= =20=20=20=20(if=20(not=20(=3D=20diff=200))=20nil=20timestr)=0A+=09=09=09=20= =20=20=20=20nil=20nil=20habitp))))=0A=20=09=20=20=20=20=20=20(when=20txt=0A= =20=09=09(setq=20face=20(org-agenda-deadline-face=20dfrac=20wdays))=0A=20= =09=09(org-add-props=20txt=20props=0A@@=20-4282,6=20+4289,17=20@@=20the=20= documentation=20of=20`org-diary'."=0A=20=09=09=20=20'date=20(if=20= upcomingp=20date=20d2)=0A=20=09=09=20=20'face=20(if=20donep=20= 'org-agenda-done=20face)=0A=20=09=09=20=20'undone-face=20face=20= 'done-face=20'org-agenda-done)=0A+=09=09;;=20If=20this=20TODO=20is=20a=20= habit,=20append=20the=20consistency=20graph=20to=0A+=09=09;;=20the=20= todo=20line.=0A+=09=09(when=20habitp=0A+=09=09=20=20(setq=20txt=20= (concat=20txt=20"=20=20"=0A+=09=09=09=09=20=20=20=20= (org-habit-build-graph=0A+=09=09=09=09=20=20=20=20=20= (org-habit-parse-todo)=0A+=09=09=09=09=20=20=20=20=20(time-subtract=20= (current-time)=0A+=09=09=09=09=09=09=20=20=20=20(days-to-time=20(*=205=20= 7)))=0A+=09=09=09=09=20=20=20=20=20(current-time)=0A+=09=09=09=09=20=20=20= =20=20(time-add=20(current-time)=0A+=09=09=09=09=09=20=20=20=20=20=20=20= (days-to-time=207))))))=0A=20=09=09(push=20txt=20ee))))))=0A=20=20=20=20=20= (nreverse=20ee)))=0A=20=0A@@=20-4311,11=20+4329,11=20@@=20FRACTION=20is=20= what=20fraction=20of=20the=20head-warning=20time=20has=20passed."=0A=20=09= =20mm=0A=20=09=20(deadline-position-alist=0A=20=09=20=20(mapcar=20= (lambda=20(a)=20(and=20(setq=20mm=20(get-text-property=0A-=09=09=09=09=09= =20=20=20=20=200=20'org-hd-marker=20a))=0A-=09=09=09=09=20=20=20(cons=20= (marker-position=20mm)=20a)))=0A+=09=09=09=09=090=20'org-hd-marker=20a))=0A= +=09=09=09=20=20=20=20=20=20(cons=20(marker-position=20mm)=20a)))=0A=20=09= =09=20=20deadline-results))=0A=20=09=20d2=20diff=20pos=20pos1=20category=20= tags=20donep=0A-=09=20ee=20txt=20head=20pastschedp=20todo-state=20face=20= timestr=20s)=0A+=09=20ee=20txt=20head=20pastschedp=20todo-state=20face=20= timestr=20s=20habitp)=0A=20=20=20=20=20(goto-char=20(point-min))=0A=20=20= =20=20=20(while=20(re-search-forward=20regexp=20nil=20t)=0A=20=20=20=20=20= =20=20(catch=20:skip=0A@@=20-4337,6=20+4355,7=20@@=20FRACTION=20is=20= what=20fraction=20of=20the=20head-warning=20time=20has=20passed."=0A=20=09= =20=20=20=20(save-excursion=0A=20=09=20=20=20=20=20=20(setq=20todo-state=20= (org-get-todo-state))=0A=20=09=20=20=20=20=20=20(setq=20donep=20(member=20= todo-state=20org-done-keywords))=0A+=09=20=20=20=20=20=20(setq=20habitp=20= (org-is-habit-p))=0A=20=09=20=20=20=20=20=20(if=20(and=20donep=0A=20=09=09= =20=20=20=20=20=20=20(or=20org-agenda-skip-scheduled-if-done=0A=20=09=09=09= =20=20=20(not=20(=3D=20diff=200))))=0A@@=20-4365,8=20+4384,14=20@@=20= FRACTION=20is=20what=20fraction=20of=20the=20head-warning=20time=20has=20= passed."=0A=20=09=09=09=09=20(car=20org-agenda-scheduled-leaders)=0A=20=09= =09=09=20=20=20=20=20=20=20(format=20(nth=201=20= org-agenda-scheduled-leaders)=0A=20=09=09=09=09=20=20=20=20=20=20=20(-=20= 1=20diff)))=0A-=09=09=09=20=20=20=20=20head=20category=20tags=0A-=09=09=09= =20=20=20=20=20(if=20(not=20(=3D=20diff=200))=20nil=20timestr)))))=0A+=09= =09=09=20=20=20=20=20(if=20habitp=0A+=09=09=09=09=20(if=20(>=20(length=20= head)=2020)=0A+=09=09=09=09=20=20=20=20=20(substring=20head=200=2020)=0A= +=09=09=09=09=20=20=20(format=20"%-20s"=20head))=0A+=09=09=09=20=20=20=20= =20=20=20head)=0A+=09=09=09=20=20=20=20=20category=20tags=0A+=09=09=09=20= =20=20=20=20(if=20(not=20(=3D=20diff=200))=20nil=20timestr)=0A+=09=09=09=20= =20=20=20=20nil=20nil=20habitp))))=0A=20=09=20=20=20=20=20=20(when=20txt=0A= =20=09=09(setq=20face=0A=20=09=09=20=20=20=20=20=20(cond=0A@@=20-4383,6=20= +4408,17=20@@=20FRACTION=20is=20what=20fraction=20of=20the=20= head-warning=20time=20has=20passed."=0A=20=09=09=20=20'priority=20(+=20= 94=20(-=205=20diff)=20(org-get-priority=20txt))=0A=20=09=09=20=20= 'org-category=20category=0A=20=09=09=20=20'todo-state=20todo-state)=0A+=09= =09;;=20If=20this=20TODO=20is=20a=20habit,=20append=20the=20consistency=20= graph=20to=0A+=09=09;;=20the=20todo=20line.=0A+=09=09(when=20habitp=0A+=09= =09=20=20(setq=20txt=20(concat=20txt=20"=20=20"=0A+=09=09=09=09=20=20=20=20= (org-habit-build-graph=0A+=09=09=09=09=20=20=20=20=20= (org-habit-parse-todo)=0A+=09=09=09=09=20=20=20=20=20(time-subtract=20= (current-time)=0A+=09=09=09=09=09=09=20=20=20=20(days-to-time=20(*=205=20= 7)))=0A+=09=09=09=09=20=20=20=20=20(current-time)=0A+=09=09=09=09=20=20=20= =20=20(time-add=20(current-time)=0A+=09=09=09=09=09=20=20=20=20=20=20=20= (days-to-time=207))))))=0A=20=09=09(push=20txt=20ee))))))=0A=20=20=20=20=20= (nreverse=20ee)))=0A=20=0A@@=20-4462,7=20+4498,7=20@@=20The=20flag=20is=20= set=20if=20the=20currently=20compiled=20format=20contains=20a=20`%e'.")=0A= =20=20=20"Used=20by=20`org-compile-prefix-format'=20to=20remember=20the=20= category=20field=20widh.")=0A=20=0A=20(defun=20org-format-agenda-item=20= (extra=20txt=20&optional=20category=20tags=20dotime=0A-=09=09=09=09=20=20= =20=20=20noprefix=20remove-re)=0A+=09=09=09=09=20=20=20=20=20noprefix=20= remove-re=20habitp)=0A=20=20=20"Format=20TXT=20to=20be=20inserted=20into=20= the=20agenda=20buffer.=0A=20In=20particular,=20it=20adds=20the=20prefix=20= and=20corresponding=20text=20properties.=20=20EXTRA=0A=20must=20be=20a=20= string=20and=20replaces=20the=20`%s'=20specifier=20in=20the=20prefix=20= format.=0A@@=20-4575,7=20+4611,7=20@@=20Any=20match=20of=20REMOVE-RE=20= will=20be=20removed=20from=20TXT."=0A=20=09(setq=20time=20(cond=20(s2=20= (concat=20s1=20"-"=20s2))=0A=20=09=09=09=20(s1=20(concat=20s1=20= "......"))=0A=20=09=09=09=20(t=20""))=0A-=09=20=20=20=20=20=20extra=20= (or=20extra=20"")=0A+=09=20=20=20=20=20=20extra=20(or=20(and=20(not=20= habitp)=20extra)=20"")=0A=20=09=20=20=20=20=20=20category=20(if=20= (symbolp=20category)=20(symbol-name=20category)=20category)=0A=20=09=20=20= =20=20=20=20thecategory=20(copy-sequence=20category))=0A=20=09(if=20= (string-match=20org-bracket-link-regexp=20category)=0Adiff=20--git=20= a/lisp/org-habit.el=20b/lisp/org-habit.el=0Anew=20file=20mode=20100644=0A= index=200000000..a3face5=0A---=20/dev/null=0A+++=20b/lisp/org-habit.el=0A= @@=20-0,0=20+1,223=20@@=0A+;;;=20org-habit.el=20---=20The=20habit=20= tracking=20code=20for=20Org-mode=0A+=0A+;;=20Copyright=20(C)=202009=0A= +;;=20=20=20Free=20Software=20Foundation,=20Inc.=0A+=0A+;;=20Author:=20= John=20Wiegley=20=0A+;;=20Keywords:=20= outlines,=20hypermedia,=20calendar,=20wp=0A+;;=20Homepage:=20= http://orgmode.org=0A+;;=20Version:=206.31trans=0A+;;=0A+;;=20This=20= file=20is=20part=20of=20GNU=20Emacs.=0A+;;=0A+;;=20GNU=20Emacs=20is=20= free=20software:=20you=20can=20redistribute=20it=20and/or=20modify=0A+;;=20= it=20under=20the=20terms=20of=20the=20GNU=20General=20Public=20License=20= as=20published=20by=0A+;;=20the=20Free=20Software=20Foundation,=20either=20= version=203=20of=20the=20License,=20or=0A+;;=20(at=20your=20option)=20= any=20later=20version.=0A+=0A+;;=20GNU=20Emacs=20is=20distributed=20in=20= the=20hope=20that=20it=20will=20be=20useful,=0A+;;=20but=20WITHOUT=20ANY=20= WARRANTY;=20without=20even=20the=20implied=20warranty=20of=0A+;;=20= MERCHANTABILITY=20or=20FITNESS=20FOR=20A=20PARTICULAR=20PURPOSE.=20=20= See=20the=0A+;;=20GNU=20General=20Public=20License=20for=20more=20= details.=0A+=0A+;;=20You=20should=20have=20received=20a=20copy=20of=20= the=20GNU=20General=20Public=20License=0A+;;=20along=20with=20GNU=20= Emacs.=20=20If=20not,=20see=20.=0A= +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;= ;;;;=0A+;;=0A+;;;=20Commentary:=0A+=0A+;;=20This=20file=20contains=20the=20= habit=20tracking=20code=20for=20Org-mode=0A+=0A+(require=20'org)=0A= +(eval-when-compile=0A+=20=20(require=20'cl)=0A+=20=20(require=20= 'calendar))=0A+=0A+(defgroup=20org-habit=20nil=0A+=20=20"Options=20= concerning=20habit=20tracking=20in=20Org-mode."=0A+=20=20:tag=20"Org=20= Habit"=0A+=20=20:group=20'org-progress)=0A+=0A+(defvar=20= org-habit-clear-color=20"slateblue")=0A+(defvar=20= org-habit-clear-future-color=20"powderblue")=0A+=0A+(defvar=20= org-habit-ready-color=20"green")=0A+(defvar=20= org-habit-ready-future-color=20"palegreen")=0A+=0A+(defvar=20= org-habit-warning-color=20"yellow")=0A+(defvar=20= org-habit-warning-future-color=20"palegoldenrod")=0A+=0A+(defvar=20= org-habit-alert-color=20"yellow")=0A+(defvar=20= org-habit-alert-future-color=20"palegoldenrod")=0A+=0A+(defvar=20= org-habit-overdue-color=20"red")=0A+(defvar=20= org-habit-overdue-future-color=20"mistyrose")=0A+=0A+(defun=20= org-habit-duration-to-days=20(ts)=0A+=20=20(if=20(string-match=20= "\\([0-9]+\\)\\([dwmy]\\)\\'"=20ts)=0A+=20=20=20=20=20=20;;=20lead=20= time=20is=20specified.=0A+=20=20=20=20=20=20(floor=20(*=20= (string-to-number=20(match-string=201=20ts))=0A+=09=09(cdr=20(assoc=20= (match-string=202=20ts)=0A+=09=09=09=20=20=20=20'(("d"=20.=201)=20=20=20=20= ("w"=20.=207)=0A+=09=09=09=20=20=20=20=20=20("m"=20.=2030.4)=20("y"=20.=20= 365.25))))))=0A+=20=20=20=20(error=20"Invalid=20duration=20string:=20%s"=20= ts)))=0A+=0A+(defun=20org-is-habit-p=20(&optional=20pom)=0A+=20=20= (string=3D=20"habit"=20(org-entry-get=20(or=20pom=20(point))=20= "STYLE")))=0A+=0A+(defun=20org-habit-parse-todo=20(&optional=20pom)=0A+=20= =20"Parse=20the=20TODO=20surrounding=20point=20for=20its=20habit-related=20= data.=0A+Returns=20a=20list=20with=20the=20following=20elements:=0A+=0A+=20= =200:=20Scheduled=20date=20for=20the=20habit=20(may=20be=20in=20the=20= past)=0A+=20=201:=20\".+\"-style=20repeater=20for=20the=20schedule,=20in=20= days=0A+=20=202:=20Optional=20deadline=20(nil=20if=20not=20present)=0A+=20= =203:=20If=20deadline,=20the=20repeater=20for=20the=20deadline,=20= otherwise=20nil=0A+=20=204:=20A=20list=20of=20all=20the=20past=20dates=20= this=20todo=20was=20mark=20closed=0A+=0A+This=20list=20represents=20a=20= \"habit\"=20for=20the=20rest=20of=20this=20module."=0A+=20=20= (save-excursion=0A+=20=20=20=20(if=20pom=20(goto-char=20pom))=0A+=20=20=20= =20(assert=20(org-is-habit-p=20(point)))=0A+=20=20=20=20(let=20= ((scheduled=20(org-get-scheduled-time=20(point)))=0A+=09=20=20= (scheduled-repeat=20(org-get-repeat=20"SCHEDULED"))=0A+=09=20=20= (deadline=20(org-get-deadline-time=20(point)))=0A+=09=20=20= (deadline-repeat=20(org-get-repeat=20"DEADLINE")))=0A+=20=20=20=20=20=20= (unless=20scheduled=0A+=09(error=20"Habit=20has=20no=20scheduled=20= date"))=0A+=20=20=20=20=20=20(unless=20scheduled-repeat=0A+=09(error=20= "Habit=20has=20no=20scheduled=20repeat=20period"))=0A+=20=20=20=20=20=20= (unless=20(string-match=20"\\`\\.\\+[0-9]+"=20scheduled-repeat)=0A+=09= (error=20"Habit's=20scheduled=20repeat=20period=20does=20not=20match=20= `.+[0-9]*'"))=0A+=20=20=20=20=20=20(if=20(and=20deadline=20(not=20= deadline-repeat))=0A+=09=20=20(error=20"Habit=20has=20a=20deadline,=20= but=20no=20deadline=20repeat=20period"))=0A+=20=20=20=20=20=20(if=20(and=20= deadline=0A+=09=20=20=20=20=20=20=20(not=20(string-match=20= "\\`\\.\\+[0-9]+"=20scheduled-repeat)))=20=0A+=09=20=20(error=20"Habit's=20= deadline=20repeat=20period=20does=20not=20match=20`.+[0-9]*'"))=0A+=20=20= =20=20=20=20(let=20((sr-days=20(org-habit-duration-to-days=20= scheduled-repeat))=0A+=09=20=20=20=20(dr-days=20= (org-habit-duration-to-days=20deadline-repeat)))=0A+=09(when=20(and=20= scheduled=20deadline)=0A+=09=20=20(cond=0A+=09=20=20=20((time-less-p=20= deadline=20scheduled)=0A+=09=20=20=20=20(error=20"Habit's=20deadline=20= date=20is=20before=20the=20scheduled=20date"))=0A+=09=20=20=20((<=20= dr-days=20sr-days)=0A+=09=20=20=20=20(error=20"Habit's=20deadline=20= repeat=20period=20is=20less=20than=20scheduled"))=0A+=09=20=20=20((/=3D=20= (-=20(time-to-days=20deadline)=0A+=09=09=20=20=20(time-to-days=20= scheduled))=0A+=09=09(-=20dr-days=20sr-days))=0A+=09=20=20=20=20(error=20= "Habit's=20deadline=20and=20scheduled=20period=20lengths=20are=20= off"))))=0A+=09(let=20((end=20(org-entry-end-position))=0A+=09=20=20=20=20= =20=20closed-dates)=0A+=09=20=20(org-back-to-heading=20t)=0A+=09=20=20= (while=20(re-search-forward=20"-=20State=20\"DONE\".*\\[\\([^]]+\\)\\]"=20= end=20t)=0A+=09=20=20=20=20(push=20(org-time-string-to-time=20= (match-string-no-properties=201))=0A+=09=09=20=20closed-dates))=0A+=09=20= =20(list=20scheduled=20sr-days=20deadline=20dr-days=20closed-dates))))))=0A= +=0A+(defsubst=20org-habit-scheduled=20(habit)=0A+=20=20(nth=200=20= habit))=0A+(defsubst=20org-habit-scheduled-repeat=20(habit)=0A+=20=20= (nth=201=20habit))=0A+(defsubst=20org-habit-deadline=20(habit)=0A+=20=20= (nth=202=20habit))=0A+(defsubst=20org-habit-deadline-repeat=20(habit)=0A= +=20=20(nth=203=20habit))=0A+(defsubst=20org-habit-done-dates=20(habit)=0A= +=20=20(nth=204=20habit))=0A+=0A+(defun=20org-habit-get-colors=20(habit=20= &optional=20moment=20scheduled-time)=0A+=20=20"Return=20faces=20for=20= HABIT=20relative=20to=20MOMENT=20and=20SCHEDULED-TIME.=0A+MOMENT=20= defaults=20to=20the=20current=20time=20if=20it=20is=20nil.=0A= +SCHEDULED-TIME=20defaults=20to=20the=20habit's=20actual=20scheduled=20= time=20if=20nil.=0A+=0A+Habits=20are=20assigned=20colors=20on=20the=20= following=20basis:=0A+=20=20Blue=20=20=20=20=20=20Task=20is=20before=20= the=20scheduled=20date.=0A+=20=20Green=20=20=20=20=20Task=20is=20on=20or=20= after=20scheduled=20date,=20but=20before=20the=0A+=20=20=20=20=20=20=20=20= =20=20=20=20end=20of=20the=20schedule's=20repeat=20period.=0A+=20=20= Yellow=20=20=20=20If=20the=20task=20has=20a=20deadline,=20then=20it=20is=20= after=20schedule's=0A+=20=20=20=20=20=20=20=20=20=20=20=20repeat=20= period,=20but=20before=20the=20deadline.=0A+=20=20Orange=20=20=20=20The=20= task=20has=20reached=20the=20deadline=20day,=20or=20if=20there=20is=0A+=20= =20=20=20=20=20=20=20=20=20=20=20no=20deadline,=20the=20end=20of=20the=20= schedule's=20repeat=20period.=0A+=20=20Red=20=20=20=20=20=20=20The=20= task=20has=20gone=20beyond=20the=20deadline=20day=20or=20the=0A+=20=20=20= =20=20=20=20=20=20=20=20=20schedule's=20repeat=20period."=0A+=20=20= (unless=20moment=20(setq=20moment=20(current-time)))=0A+=20=20(let*=20= ((scheduled=20(or=20scheduled-time=20(org-habit-scheduled=20habit)))=0A+=09= =20(s-repeat=20(org-habit-scheduled-repeat=20habit))=0A+=09=20= (scheduled-end=20(time-add=20scheduled=20(days-to-time=20s-repeat)))=0A+=09= =20(d-repeat=20(org-habit-deadline-repeat=20habit))=0A+=09=20(deadline=20= (if=20scheduled-time=0A+=09=09=20=20=20=20=20=20=20(time-add=20= scheduled-time=0A+=09=09=09=09=20(days-to-time=20(-=20d-repeat=20= s-repeat)))=0A+=09=09=20=20=20=20=20(org-habit-deadline=20habit))))=0A+=20= =20=20=20(cond=0A+=20=20=20=20=20((time-less-p=20moment=20scheduled)=0A+=20= =20=20=20=20=20(cons=20org-habit-clear-color=20= org-habit-clear-future-color))=0A+=20=20=20=20=20((time-less-p=20moment=20= scheduled-end)=0A+=20=20=20=20=20=20(cons=20org-habit-ready-color=20= org-habit-ready-future-color))=0A+=20=20=20=20=20((and=20deadline=0A+=09=20= =20=20(time-less-p=20moment=20deadline))=0A+=20=20=20=20=20=20(cons=20= org-habit-warning-color=20org-habit-warning-future-color))=0A+=20=20=20=20= =20((=3D=20(time-to-days=20moment)=0A+=09=20(if=20deadline=0A+=09=20=20=20= =20=20(time-to-days=20deadline)=0A+=09=20=20=20(time-to-days=20= scheduled-end)))=0A+=20=20=20=20=20=20(cons=20org-habit-alert-color=20= org-habit-alert-future-color))=0A+=20=20=20=20=20(t=0A+=20=20=20=20=20=20= (cons=20org-habit-overdue-color=20org-habit-overdue-future-color)))))=0A= +=0A+(defun=20org-habit-build-graph=20(habit=20&optional=20starting=20= current=20ending)=0A+=20=20"Build=20a=20color=20graph=20for=20the=20= given=20HABIT,=20from=20STARTING=20to=20ENDING."=0A+=20=20(message=20= "Build=20graph=20starting:=20%s"=20(format-time-string=20"%c"=20= starting))=0A+=20=20(message=20"Build=20graph=20current:=20=20%s"=20= (format-time-string=20"%c"=20current))=0A+=20=20(message=20"Build=20= graph=20ending:=20=20=20%s"=20(format-time-string=20"%c"=20ending))=0A+=20= =20(let=20((done-dates=20(sort=20(org-habit-done-dates=20habit)=20= 'time-less-p))=0A+=09(s-repeat=20(org-habit-scheduled-repeat=20habit))=0A= +=09(day=20starting)=0A+=09(current-days=20(time-to-days=20current))=0A+=09= last-done-date=0A+=09(graph=20(make-string=20(1+=20(-=20(time-to-days=20= ending)=0A+=09=09=09=09=20=20=20(time-to-days=20starting)))=20?\=20))=0A= +=09(index=200))=0A+=20=20=20=20(if=20done-dates=0A+=09(while=20= (time-less-p=20(car=20done-dates)=20starting)=0A+=09=20=20(setq=20= done-dates=20(cdr=20done-dates))))=0A+=20=20=20=20(while=20(time-less-p=20= day=20ending)=0A+=20=20=20=20=20=20(let*=20((now-days=20(time-to-days=20= day))=0A+=09=20=20=20=20=20(in-the-past-p=20(<=20now-days=20= current-days))=0A+=09=20=20=20=20=20(today-p=20(=3D=20now-days=20= current-days))=0A+=09=20=20=20=20=20(colors=20(if=20(and=20in-the-past-p=20= (not=20last-done-date))=0A+=09=09=09=20(cons=20org-habit-clear-color=0A+=09= =09=09=20=20=20=20=20=20=20org-habit-clear-future-color)=0A+=09=09=20=20=20= =20=20=20=20(org-habit-get-colors=0A+=09=09=09habit=20day=0A+=09=09=09= (and=20in-the-past-p=0A+=09=09=09=20=20=20=20=20(time-add=20= last-done-date=0A+=09=09=09=09=20=20=20=20=20=20=20(days-to-time=20= s-repeat))))))=0A+=09=20=20=20=20=20markedp=20color)=0A+=09(if=20today-p=0A= +=09=20=20=20=20(aset=20graph=20index=20?!)=0A+=09=20=20(when=20(and=20= done-dates=0A+=09=09=20=20=20=20=20(=3D=20now-days=20(time-to-days=20= (car=20done-dates))))=0A+=09=20=20=20=20(aset=20graph=20index=20?*)=0A+=09= =20=20=20=20(setq=20last-done-date=20(car=20done-dates)=0A+=09=09=20=20= done-dates=20(cdr=20done-dates)=0A+=09=09=20=20markedp=20t)))=0A+=09= (setq=20color=20(if=20(or=20in-the-past-p=0A+=09=09=09=20=20=20=20= today-p)=0A+=09=09=09(car=20colors)=0A+=09=09=20=20=20=20=20=20(cdr=20= colors)))=0A+=09(if=20(and=20in-the-past-p=0A+=09=09=20(not=20(string=3D=20= color=20org-habit-overdue-color))=0A+=09=09=20(not=20markedp))=0A+=09=20=20= =20=20(setq=20color=20(cdr=20colors)))=0A+=09(put-text-property=20index=20= (1+=20index)=0A+=09=09=09=20=20=20'face=20(list=20:background=20color)=20= graph))=0A+=20=20=20=20=20=20(setq=20day=20(time-add=20day=20= (days-to-time=201))=0A+=09=20=20=20=20index=20(1+=20index)))=0A+=20=20=20= =20graph))=0A+=0A+(provide=20'org-habit)=0A+=0A+;;=20arch-tag:=20=0A+=0A= +;;;=20org-habit.el=20ends=20here=0A--=20=0A1.6.5=0A=0A= --Apple-Mail-10-608171745 Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ Emacs-orgmode mailing list Remember: use `Reply All' to send replies to the list. Emacs-orgmode@gnu.org http://lists.gnu.org/mailman/listinfo/emacs-orgmode --Apple-Mail-10-608171745--