|
|
@ -10,7 +10,7 @@ import org.joda.time.DateTime
|
|
|
|
|
|
|
|
|
|
|
|
public class GTDCLI {
|
|
|
|
public class GTDCLI {
|
|
|
|
|
|
|
|
|
|
|
|
public static final String VERSION = "0.6"
|
|
|
|
public static final String VERSION = "0.9"
|
|
|
|
private static String EOL = System.getProperty("line.separator")
|
|
|
|
private static String EOL = System.getProperty("line.separator")
|
|
|
|
private static GTDCLI nailgunInst
|
|
|
|
private static GTDCLI nailgunInst
|
|
|
|
|
|
|
|
|
|
|
@ -96,7 +96,8 @@ public class GTDCLI {
|
|
|
|
case ~/cal|calendar/: calendar(parsedArgs); break
|
|
|
|
case ~/cal|calendar/: calendar(parsedArgs); break
|
|
|
|
case ~/process/: process(parsedArgs); break
|
|
|
|
case ~/process/: process(parsedArgs); break
|
|
|
|
case ~/list-copies/: listCopies(parsedArgs); break
|
|
|
|
case ~/list-copies/: listCopies(parsedArgs); break
|
|
|
|
case ~/new/: newAction(parsedArgs);
|
|
|
|
case ~/new/: newAction(parsedArgs); break
|
|
|
|
|
|
|
|
case ~/tickler/: tickler(parsedArgs); break
|
|
|
|
default:
|
|
|
|
default:
|
|
|
|
println "Unrecognized command: ${command}"
|
|
|
|
println "Unrecognized command: ${command}"
|
|
|
|
break } } }
|
|
|
|
break } } }
|
|
|
@ -259,7 +260,7 @@ public class GTDCLI {
|
|
|
|
if (inPath(gtdDirs.projects, oldFile)) {
|
|
|
|
if (inPath(gtdDirs.projects, oldFile)) {
|
|
|
|
|
|
|
|
|
|
|
|
// Delete any copies of this item in the next actions folder.
|
|
|
|
// Delete any copies of this item in the next actions folder.
|
|
|
|
findAllCopies(oldFile, gtdDrs."next-actions").each { file ->
|
|
|
|
findAllCopies(oldFile, gtdDirs."next-actions").each { file ->
|
|
|
|
println "Deleting duplicate entry from the " +
|
|
|
|
println "Deleting duplicate entry from the " +
|
|
|
|
"${file.parentFile.name} context."
|
|
|
|
"${file.parentFile.name} context."
|
|
|
|
file.delete() }
|
|
|
|
file.delete() }
|
|
|
@ -338,8 +339,10 @@ public class GTDCLI {
|
|
|
|
|
|
|
|
|
|
|
|
protected void newAction(LinkedList args) {
|
|
|
|
protected void newAction(LinkedList args) {
|
|
|
|
|
|
|
|
|
|
|
|
def response = prompt("Next action?", "")
|
|
|
|
def response = prompt(["Next action?", ""])
|
|
|
|
def item = new Item(new File(workingDir, stringToFilename(response)))
|
|
|
|
def file = new File(workingDir, stringToFilename(response))
|
|
|
|
|
|
|
|
file.createNewFile()
|
|
|
|
|
|
|
|
def item = new Item(file)
|
|
|
|
|
|
|
|
|
|
|
|
item.action = response
|
|
|
|
item.action = response
|
|
|
|
|
|
|
|
|
|
|
@ -348,7 +351,7 @@ public class GTDCLI {
|
|
|
|
println "End with an empty line."
|
|
|
|
println "End with an empty line."
|
|
|
|
print "> "
|
|
|
|
print "> "
|
|
|
|
|
|
|
|
|
|
|
|
while (response = stdin.readLine().trim()) {
|
|
|
|
while (response = stdin.nextLine().trim()) {
|
|
|
|
if (!(response =~ /[:=]/)) continue
|
|
|
|
if (!(response =~ /[:=]/)) continue
|
|
|
|
def parts = response.split(/[:=]/)
|
|
|
|
def parts = response.split(/[:=]/)
|
|
|
|
item[parts[0].trim().toLowerCase()] =
|
|
|
|
item[parts[0].trim().toLowerCase()] =
|
|
|
@ -357,6 +360,23 @@ public class GTDCLI {
|
|
|
|
|
|
|
|
|
|
|
|
item.save() }
|
|
|
|
item.save() }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected void tickler(LinkedList args) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
gtdDirs.tickler.eachFileRecurse { file ->
|
|
|
|
|
|
|
|
def item = new Item(file)
|
|
|
|
|
|
|
|
def today = new DateMidnight()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// If the item is scheduled to be tickled today (or in the past)
|
|
|
|
|
|
|
|
// then move it into the next-actions folder
|
|
|
|
|
|
|
|
if ((item.tickle as DateMidnight) <= today) {
|
|
|
|
|
|
|
|
println "Moving '${item.action}' out of the tickler."
|
|
|
|
|
|
|
|
def oldFile = item.file
|
|
|
|
|
|
|
|
item.file = new File(gtdDirs."next-actions",
|
|
|
|
|
|
|
|
stringToFilename(item.action))
|
|
|
|
|
|
|
|
item.gtdProperties.remove("tickle")
|
|
|
|
|
|
|
|
item.save()
|
|
|
|
|
|
|
|
oldFile.delete() }}}
|
|
|
|
|
|
|
|
|
|
|
|
protected void printUsage(LinkedList args) {
|
|
|
|
protected void printUsage(LinkedList args) {
|
|
|
|
|
|
|
|
|
|
|
|
if (!args) {
|
|
|
|
if (!args) {
|
|
|
@ -383,7 +403,10 @@ top-level commands:
|
|
|
|
there the same item is filed (cross-reference
|
|
|
|
there the same item is filed (cross-reference
|
|
|
|
with a project folder, for example).
|
|
|
|
with a project folder, for example).
|
|
|
|
new Interactively create a new action item in the
|
|
|
|
new Interactively create a new action item in the
|
|
|
|
current folder."""
|
|
|
|
current folder.
|
|
|
|
|
|
|
|
tickler Search the tickler file for items that need to be
|
|
|
|
|
|
|
|
delivered and move them to the *next-actions*
|
|
|
|
|
|
|
|
folder."""
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
def command = args.poll()
|
|
|
|
def command = args.poll()
|
|
|
|
|
|
|
|
|
|
|
@ -466,6 +489,14 @@ future?). It prompts the user for the next action and any extended properties
|
|
|
|
that should be associated with it, then creates the action file in the current
|
|
|
|
that should be associated with it, then creates the action file in the current
|
|
|
|
directory."""
|
|
|
|
directory."""
|
|
|
|
break
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case ~/tickler/: println """\
|
|
|
|
|
|
|
|
usage: gtd tickler
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
This command should be scheduled for execution once a day. It checks the tickler
|
|
|
|
|
|
|
|
file for any items that should become active (based on their <tickle> property)
|
|
|
|
|
|
|
|
and moves them out of the tickler file and into the next-actions file."""
|
|
|
|
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -530,7 +561,7 @@ directory."""
|
|
|
|
|
|
|
|
|
|
|
|
return [:] }
|
|
|
|
return [:] }
|
|
|
|
|
|
|
|
|
|
|
|
protected String prompt(String message) {
|
|
|
|
protected String prompt(def msg) {
|
|
|
|
if (msg instanceof List) msg = msg.join(EOL)
|
|
|
|
if (msg instanceof List) msg = msg.join(EOL)
|
|
|
|
msg += "> "
|
|
|
|
msg += "> "
|
|
|
|
print msg
|
|
|
|
print msg
|
|
|
|