Created
October 27, 2010 10:53
-
-
Save jphalip/648828 to your computer and use it in GitHub Desktop.
AppleScript to manage dates in TaskPaper. Contains improvements made on top of http://www.hogbaysoftware.com/wiki/StartAndDueDates - Works well with http://gist.github.com/648841
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
property dueTag : "due" | |
property startTag : "start" | |
property repeatTag : "repeat" | |
property todayTag : "today" | |
property tomorrowTag : "tomorrow" | |
property pastDueTag : "overdue" | |
property upcomingTag : "upcoming" | |
property doneTag : "done" | |
property inProgressTag : "inprogress" | |
property errorTag : "error" | |
property mondayTag : "monday" | |
property tuesdayTag : "tuesday" | |
property wednesdayTag : "wednesday" | |
property thursdayTag : "thursday" | |
property fridayTag : "friday" | |
property saturdayTag : "saturday" | |
property sundayTag : "sunday" | |
property dayTags : {mondayTag, tuesdayTag, wednesdayTag, thursdayTag, fridayTag, saturdayTag, sundayTag} | |
property removeTags : {upcomingTag, tomorrowTag, todayTag, pastDueTag, inProgressTag} -- TODO: merge dayTags into removeTags (see also in code below) | |
property upcomingDays : 3 | |
property numberSet : {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"} | |
global vToday | |
set vToday to current date | |
set time of vToday to 0 | |
--Start by converting any due tags with a text description of the date | |
--to an actual date | |
my convertDate(dueTag) | |
my convertDate(startTag) | |
tell front document of application "TaskPaper" | |
--Next handle repeat tags. A due tag is not required on these. | |
repeat with tpRptTag in (every tag of (every entry) whose name is repeatTag) | |
tell entry of tpRptTag | |
set tagList to (every tag whose name is dueTag) | |
set needDue to false | |
if tagList is {} then | |
--no due tag, create one, and remember to fill in a date below. | |
--use today as the start date | |
set tpDueTag to make new tag with properties {name:dueTag} | |
copy vToday to vDate | |
set needDue to true | |
else | |
--have a due tag, use that as the start date | |
set tpDueTag to first item of tagList | |
set dateString to (get value of tpDueTag) | |
tell me to set vDate to getDateFromText(dateString) | |
end if | |
if not needDue then | |
set tagList to (every tag whose name is doneTag) | |
end if | |
--if there was no due tag, or the entry is marked done, | |
--the calculate and set the date of the due tag. | |
if needDue or tagList is not {} then | |
--Delete all extra tags | |
repeat with delTag in removeTags | |
delete (every tag whose name is delTag) | |
end repeat | |
repeat with delTag in dayTags -- TODO merge into removeTags for DRYness | |
delete (every tag whose name is delTag) | |
end repeat | |
--Create a date from the repeat value | |
set rInfo to (get value of tpRptTag) | |
if (vDate is not null) then | |
tell me to set vDate to getRepeatDate(rInfo, vDate) | |
end if | |
if vDate is not null then | |
--fill in the date, make sure it is not marked done | |
tell me to set vDateText to getTextFromDate(vDate) | |
set value of tpDueTag to vDateText | |
delete (every tag whose name is doneTag) | |
else | |
--flag unknown repeat value with an error tag | |
make new tag with properties {name:errorTag, value:"unknown repeat type"} | |
end if | |
end if | |
end tell | |
end repeat | |
--Add/update the extra tags based on the due date of items that are not done | |
repeat with tpDueTag in (every tag of (every entry) whose name is dueTag) | |
tell entry of tpDueTag | |
set tagList to (every tag whose name is doneTag) | |
set errTagList to (every tag whose name is errorTag) | |
if (tagList is {}) and (errTagList is {}) then | |
--Not marked done | |
set inFuture to false | |
set dateString to (get value of tpDueTag) | |
tell me to set vDate to getDateFromText(dateString) | |
set startTagList to (every tag whose name is startTag) | |
if (startTagList is not {}) then | |
set tpStartTag to first item of startTagList | |
set startDateString to (get value of tpStartTag) | |
tell me to set vStartDate to getDateFromText(startDateString) | |
set inFuture to ((vToday) - vStartDate < 0) | |
end if | |
if vDate is not null then | |
if inFuture then | |
delete (every tag whose name is tomorrowTag) | |
delete (every tag whose name is upcomingTag) | |
delete (every tag whose name is todayTag) | |
repeat with delTag in dayTags | |
delete (every tag whose name is delTag) | |
end repeat | |
else | |
set diffDays to (vDate - vToday) / days | |
if (diffDays < 0) then | |
-- The task is overdue | |
set tagList to (every tag whose name is pastDueTag) | |
if (tagList is {}) then | |
make new tag with properties {name:pastDueTag} | |
end if | |
delete (every tag whose name is upcomingTag) | |
delete (every tag whose name is tomorrowTag) | |
delete (every tag whose name is todayTag) | |
repeat with delTag in dayTags | |
delete (every tag whose name is delTag) | |
end repeat | |
else | |
delete (every tag whose name is pastDueTag) | |
if (diffDays = 0) then | |
-- The task is due today | |
set tagList to (every tag whose name is todayTag) | |
if (tagList is {}) then | |
make new tag with properties {name:todayTag} | |
end if | |
delete (every tag whose name is upcomingTag) | |
delete (every tag whose name is tomorrowTag) | |
repeat with delTag in dayTags | |
delete (every tag whose name is delTag) | |
end repeat | |
else if (diffDays = 1) then | |
-- The task is due tomorrow | |
set tagList to (every tag whose name is tomorrowTag) | |
if (tagList is {}) then | |
make new tag with properties {name:tomorrowTag} | |
end if | |
delete (every tag whose name is upcomingTag) | |
delete (every tag whose name is todayTag) | |
repeat with delTag in dayTags | |
delete (every tag whose name is delTag) | |
end repeat | |
else if (diffDays ≤ upcomingDays) then | |
-- The task is due soon after tomorrow | |
delete (every tag whose name is todayTag) | |
delete (every tag whose name is tomorrowTag) | |
-- Add the upcoming tag | |
set tagList to (every tag whose name is upcomingTag) | |
if (tagList is {}) then | |
make new tag with properties {name:upcomingTag} | |
end if | |
-- Add the day tag | |
set d to weekday of vDate as string | |
if (d is "Monday") then | |
set tagList to (every tag whose name is mondayTag) | |
if (tagList is {}) then | |
make new tag with properties {name:mondayTag} | |
end if | |
else | |
delete (every tag whose name is mondayTag) | |
end if | |
if (d is "Tuesday") then | |
set tagList to (every tag whose name is tuesdayTag) | |
if (tagList is {}) then | |
make new tag with properties {name:tuesdayTag} | |
end if | |
else | |
delete (every tag whose name is tuesdayTag) | |
end if | |
if (d is "Wednesday") then | |
set tagList to (every tag whose name is wednesdayTag) | |
if (tagList is {}) then | |
make new tag with properties {name:wednesdayTag} | |
end if | |
else | |
delete (every tag whose name is wednesdayTag) | |
end if | |
if (d is "Thursday") then | |
set tagList to (every tag whose name is thursdayTag) | |
if (tagList is {}) then | |
make new tag with properties {name:thursdayTag} | |
end if | |
else | |
delete (every tag whose name is thursdayTag) | |
end if | |
if (d is "Friday") then | |
set tagList to (every tag whose name is fridayTag) | |
if (tagList is {}) then | |
make new tag with properties {name:fridayTag} | |
end if | |
else | |
delete (every tag whose name is fridayTag) | |
end if | |
if (d is "Saturday") then | |
set tagList to (every tag whose name is saturdayTag) | |
if (tagList is {}) then | |
make new tag with properties {name:saturdayTag} | |
end if | |
else | |
delete (every tag whose name is saturdayTag) | |
end if | |
if (d is "Sunday") then | |
set tagList to (every tag whose name is sundayTag) | |
if (tagList is {}) then | |
make new tag with properties {name:sundayTag} | |
end if | |
else | |
delete (every tag whose name is sundayTag) | |
end if | |
else | |
delete (every tag whose name is upcomingTag) | |
delete (every tag whose name is tomorrowTag) | |
delete (every tag whose name is todayTag) | |
repeat with delTag in dayTags | |
delete (every tag whose name is delTag) | |
end repeat | |
end if | |
end if | |
end if | |
else | |
--invalid date format | |
make new tag with properties {name:"error", value:"invalid date format"} | |
end if | |
else | |
--Marked done, delete all extra tags | |
repeat with delTag in removeTags | |
delete (every tag whose name is delTag) | |
end repeat | |
repeat with delTag in dayTags -- TODO merge into removeTags for DRYness | |
delete (every tag whose name is delTag) | |
end repeat | |
end if | |
end tell | |
end repeat | |
end tell | |
on convertDate(tagLabel) | |
tell front document of application "TaskPaper" | |
repeat with myTag in (every tag of (every entry) whose name is tagLabel) | |
set vDueVal to (value of myTag) | |
if vDueVal is missing value then | |
set vDueVal to "today" | |
end if | |
if character 1 of vDueVal is not in numberSet then | |
set vDateString to null | |
tell me to set vDate to getDateForDueValue(vDueVal) | |
if vDate is not null then | |
tell me to set vDateString to getTextFromDate(vDate) | |
else | |
tell entry of myTag | |
make new tag with properties {name:errorTag, value:"Unknown value for " & tagLabel & " tag"} | |
end tell | |
end if | |
if vDateString is not null then | |
set value of myTag to vDateString | |
end if | |
end if | |
end repeat | |
end tell | |
end convertDate | |
on getDateFromText(dateText) | |
set vDate to null | |
set AppleScript's text item delimiters to {"-"} | |
if (count of text item of dateText) is 3 then | |
set vYear to text item 1 of dateText | |
set vMonth to text item 2 of dateText | |
set vDay to text item 3 of dateText | |
if (vYear > 1000) and (vMonth > 0 and vMonth < 13) and (vDay > 0 and vDay < 32) then | |
set vDate to current date | |
set year of vDate to (vYear as integer) | |
set month of vDate to vMonth as integer | |
set day of vDate to vDay as integer | |
set time of vDate to 0 | |
end if | |
end if | |
return vDate | |
end getDateFromText | |
on getTextFromDate(vDate) | |
set dText to ((year of vDate) as text) & "-" | |
set dayText to (month of vDate as number) as text | |
if length of dayText is 1 then | |
set dayText to "0" & dayText | |
end if | |
set dText to dText & dayText & "-" | |
set dayText to (day of vDate as number) as text | |
if length of dayText is 1 then | |
set dayText to "0" & dayText | |
end if | |
return dText & dayText | |
end getTextFromDate | |
on getDateForDueValue(dueValue) | |
set vDate to null | |
if character 1 of dueValue is in numberSet then | |
set vDate to getDateFromText(dueValue) | |
else | |
--Special cases for due date not handled in getRepeatDate | |
if "today" is dueValue then | |
copy vToday to vDate | |
else if "tomorrow" starts with dueValue then | |
copy vToday to vDate | |
set vDate to vDate + 1 * days | |
else | |
set vDate to getRepeatDate(dueValue, vToday) | |
end if | |
end if | |
return vDate | |
end getDateForDueValue | |
on getRepeatDate(repeatDesc, fromDate) | |
copy fromDate to vDate | |
set AppleScript's text item delimiters to {":"} | |
set repeatType to text item 1 of repeatDesc | |
if (count of text items in repeatDesc) > 1 then | |
set repeatCount to text item 2 of repeatDesc | |
else | |
set repeatCount to 1 | |
end if | |
if repeatType is "day" or repeatType is "week" then | |
if repeatType is "day" then | |
set vInterval to days | |
else | |
set vInterval to weeks | |
end if | |
set vDate to vDate + repeatCount * vInterval | |
repeat while vDate comes before vToday | |
set vDate to vDate + repeatCount * vInterval | |
end repeat | |
else if repeatType is "month" then | |
set month of vDate to (month of vDate) + repeatCount | |
repeat while vDate comes before vToday | |
set month of vDate to (month of vDate) + repeatCount | |
end repeat | |
else if repeatType is "year" then | |
set year of vDate to (year of vDate) + repeatCount | |
log "vDate is " & vDate | |
repeat while vDate comes before vToday | |
set year of vDate to (year of vDate) + repeatCount | |
end repeat | |
else | |
set rDay to 0 | |
if "sunday" starts with repeatType then | |
set rDay to Sunday | |
else if "monday" starts with repeatType then | |
set rDay to Monday | |
else if "tuesday" starts with repeatType then | |
set rDay to Tuesday | |
else if "wednesday" starts with repeatType then | |
set rDay to Wednesday | |
else if "thursday" starts with repeatType then | |
set rDay to Thursday | |
else if "friday" starts with repeatType then | |
set rDay to Friday | |
else if "saturday" starts with repeatType then | |
set rDay to Saturday | |
end if | |
if rDay > 0 then | |
--Handle case where vDate is not currect day of week. | |
set vOffset to rDay - (weekday of vDate) | |
if vOffset is not 0 then | |
set vDate to vDate + vOffset * days | |
if vOffset > 0 then | |
--If we move forward, count that as 1 | |
set repeatCount to repeatCount - 1 | |
end if | |
end if | |
--Find next date after vDate | |
set vOffset to 7 * repeatCount | |
set vDate to vDate + vOffset * days | |
repeat while vDate comes before vToday | |
set vDate to vDate + vOffset * days | |
end repeat | |
else | |
--Unknown type, return nothing | |
set vDate to null | |
end if | |
end if | |
return vDate | |
end getRepeatDate |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment