- Removed all obsolete hooks, except from commands.cpp, which is being
  worked on in parallel.
- Implemented new on-launch and on-exit unit tests.
This commit is contained in:
Paul Beckingham 2011-04-17 21:09:58 -04:00
parent 2f4efb28d6
commit 48eb4757f8
15 changed files with 2816 additions and 3246 deletions

View file

@ -124,7 +124,7 @@ void Context::initialize (int argc, char** argv)
// Hook system init, plus post-start event occurring at the first possible // Hook system init, plus post-start event occurring at the first possible
// moment after hook initialization. // moment after hook initialization.
hooks.initialize (); hooks.initialize ();
hooks.trigger ("post-start"); hooks.trigger ("on-launch");
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -189,41 +189,33 @@ int Context::run ()
} }
// Dump all debug messages. // Dump all debug messages.
hooks.trigger ("pre-debug");
if (config.getBoolean ("debug")) if (config.getBoolean ("debug"))
foreach (d, debugMessages) foreach (d, debugMessages)
if (config.getBoolean ("color") || config.getBoolean ("_forcecolor")) if (config.getBoolean ("color") || config.getBoolean ("_forcecolor"))
std::cout << colorizeDebug (*d) << "\n"; std::cout << colorizeDebug (*d) << "\n";
else else
std::cout << *d << "\n"; std::cout << *d << "\n";
hooks.trigger ("post-debug");
// Dump all headers. // Dump all headers.
hooks.trigger ("pre-header");
if (config.getBoolean ("verbose")) if (config.getBoolean ("verbose"))
foreach (h, headers) foreach (h, headers)
if (config.getBoolean ("color") || config.getBoolean ("_forcecolor")) if (config.getBoolean ("color") || config.getBoolean ("_forcecolor"))
std::cout << colorizeHeader (*h) << "\n"; std::cout << colorizeHeader (*h) << "\n";
else else
std::cout << *h << "\n"; std::cout << *h << "\n";
hooks.trigger ("post-header");
// Dump the report output. // Dump the report output.
hooks.trigger ("pre-output");
std::cout << output; std::cout << output;
hooks.trigger ("post-output");
// Dump all footnotes. // Dump all footnotes.
hooks.trigger ("pre-footnote");
if (config.getBoolean ("verbose")) if (config.getBoolean ("verbose"))
foreach (f, footnotes) foreach (f, footnotes)
if (config.getBoolean ("color") || config.getBoolean ("_forcecolor")) if (config.getBoolean ("color") || config.getBoolean ("_forcecolor"))
std::cout << colorizeFootnote (*f) << "\n"; std::cout << colorizeFootnote (*f) << "\n";
else else
std::cout << *f << "\n"; std::cout << *f << "\n";
hooks.trigger ("post-footnote");
hooks.trigger ("pre-exit"); hooks.trigger ("on-exit");
return rc; return rc;
} }
@ -234,8 +226,6 @@ int Context::dispatch (std::string &out)
Timer t ("Context::dispatch"); Timer t ("Context::dispatch");
hooks.trigger ("pre-dispatch");
// For read-only commands, optionally update the xterm window title. // For read-only commands, optionally update the xterm window title.
// Why just the read-only commands? Because this capability is to answer the // Why just the read-only commands? Because this capability is to answer the
// question of 'what did I just do to generate this outout?'. // question of 'what did I just do to generate this outout?'.
@ -310,15 +300,12 @@ int Context::dispatch (std::string &out)
rc = handleCustomReport (cmd.command, out); } rc = handleCustomReport (cmd.command, out); }
// If the command is not recognized, display usage. // If the command is not recognized, display usage.
else { hooks.trigger ("pre-usage-command"); else { rc = shortUsage (out); }
rc = shortUsage (out);
hooks.trigger ("post-usage-command"); }
// Only update the shadow file if such an update was not suppressed (shadow), // Only update the shadow file if such an update was not suppressed (shadow),
if (cmd.isWriteCommand () && !inShadow) if (cmd.isWriteCommand () && !inShadow)
shadow (); shadow ();
hooks.trigger ("post-dispatch");
return rc; return rc;
} }

View file

@ -73,208 +73,19 @@ Hook& Hook::operator= (const Hook& other)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
Hooks::Hooks () Hooks::Hooks ()
{ {
/*
// New 2.x hooks. // New 2.x hooks.
validTaskEvents.push_back ("on-task-add"); validTaskEvents.push_back ("on-task-add"); // Unimplemented
validTaskEvents.push_back ("on-task-modify"); validTaskEvents.push_back ("on-task-modify"); // Unimplemented
validTaskEvents.push_back ("on-task-complete"); validTaskEvents.push_back ("on-task-complete"); // Unimplemented
validTaskEvents.push_back ("on-task-delete"); validTaskEvents.push_back ("on-task-delete"); // Unimplemented
validProgramEvents.push_back ("on-launch"); validProgramEvents.push_back ("on-launch");
validProgramEvents.push_back ("on-exit"); validProgramEvents.push_back ("on-exit");
validProgramEvents.push_back ("on-file-read"); validProgramEvents.push_back ("on-file-read"); // Unimplemented
validProgramEvents.push_back ("on-file-write"); validProgramEvents.push_back ("on-file-write"); // Unimplemented
validProgramEvents.push_back ("on-synch"); validProgramEvents.push_back ("on-synch"); // Unimplemented
validProgramEvents.push_back ("on-gc"); validProgramEvents.push_back ("on-merge"); // Unimplemented
*/ validProgramEvents.push_back ("on-gc"); // Unimplemented
// Obsolete 1.x hooks.
validProgramEvents.push_back ("post-start");
validProgramEvents.push_back ("pre-exit");
validProgramEvents.push_back ("pre-file-read");
validProgramEvents.push_back ("post-file-read");
validProgramEvents.push_back ("pre-file-write");
validProgramEvents.push_back ("post-file-write");
validProgramEvents.push_back ("pre-gc");
validProgramEvents.push_back ("post-gc");
validProgramEvents.push_back ("post-commit");
validProgramEvents.push_back ("pre-fatal-error");
validProgramEvents.push_back ("pre-command-line");
validProgramEvents.push_back ("post-command-line");
validProgramEvents.push_back ("pre-command-line-override");
validProgramEvents.push_back ("post-command-line-override");
validProgramEvents.push_back ("pre-config-create");
validProgramEvents.push_back ("post-config-create");
validProgramEvents.push_back ("pre-config-read");
validProgramEvents.push_back ("post-config-read");
validProgramEvents.push_back ("pre-config-value-read");
validProgramEvents.push_back ("post-config-value-read");
validProgramEvents.push_back ("pre-config-value-write");
validProgramEvents.push_back ("post-config-value-write");
validProgramEvents.push_back ("pre-file-lock");
validProgramEvents.push_back ("post-file-lock");
validProgramEvents.push_back ("pre-file-unlock");
validProgramEvents.push_back ("post-file-unlock");
validProgramEvents.push_back ("pre-output");
validProgramEvents.push_back ("post-output");
validProgramEvents.push_back ("pre-debug");
validProgramEvents.push_back ("post-debug");
validProgramEvents.push_back ("pre-header");
validProgramEvents.push_back ("post-header");
validProgramEvents.push_back ("pre-footnote");
validProgramEvents.push_back ("post-footnote");
validProgramEvents.push_back ("pre-dispatch");
validProgramEvents.push_back ("post-dispatch");
validProgramEvents.push_back ("pre-archive");
validProgramEvents.push_back ("post-archive");
validProgramEvents.push_back ("pre-purge");
validProgramEvents.push_back ("post-purge");
validProgramEvents.push_back ("pre-recurrence");
validProgramEvents.push_back ("post-recurrence");
validProgramEvents.push_back ("pre-interactive");
validProgramEvents.push_back ("post-interactive");
validProgramEvents.push_back ("pre-undo");
validProgramEvents.push_back ("post-undo");
validProgramEvents.push_back ("pre-confirm");
validProgramEvents.push_back ("post-confirm");
validProgramEvents.push_back ("pre-shell-prompt");
validProgramEvents.push_back ("post-shell-prompt");
validProgramEvents.push_back ("pre-add-command");
validProgramEvents.push_back ("post-add-command");
validProgramEvents.push_back ("pre-annotate-command");
validProgramEvents.push_back ("post-annotate-command");
validProgramEvents.push_back ("pre-denotate-command");
validProgramEvents.push_back ("post-denotate-command");
validProgramEvents.push_back ("pre-append-command");
validProgramEvents.push_back ("post-append-command");
validProgramEvents.push_back ("pre-calendar-command");
validProgramEvents.push_back ("post-calendar-command");
validProgramEvents.push_back ("pre-color-command");
validProgramEvents.push_back ("post-color-command");
validProgramEvents.push_back ("pre-config-command");
validProgramEvents.push_back ("post-config-command");
validProgramEvents.push_back ("pre-custom-report-command");
validProgramEvents.push_back ("post-custom-report-command");
validProgramEvents.push_back ("pre-default-command");
validProgramEvents.push_back ("post-default-command");
validProgramEvents.push_back ("pre-delete-command");
validProgramEvents.push_back ("post-delete-command");
validProgramEvents.push_back ("pre-done-command");
validProgramEvents.push_back ("post-done-command");
validProgramEvents.push_back ("pre-duplicate-command");
validProgramEvents.push_back ("post-duplicate-command");
validProgramEvents.push_back ("pre-count-command");
validProgramEvents.push_back ("post-count-command");
validProgramEvents.push_back ("pre-edit-command");
validProgramEvents.push_back ("post-edit-command");
validProgramEvents.push_back ("pre-export-command");
validProgramEvents.push_back ("post-export-command");
validProgramEvents.push_back ("pre-ghistory-command");
validProgramEvents.push_back ("post-ghistory-command");
validProgramEvents.push_back ("pre-history-command");
validProgramEvents.push_back ("post-history-command");
validProgramEvents.push_back ("pre-burndown-command");
validProgramEvents.push_back ("post-burndown-command");
validProgramEvents.push_back ("pre-import-command");
validProgramEvents.push_back ("post-import-command");
validProgramEvents.push_back ("pre-info-command");
validProgramEvents.push_back ("post-info-command");
validProgramEvents.push_back ("pre-merge-command");
validProgramEvents.push_back ("post-merge-command");
validProgramEvents.push_back ("pre-modify-command");
validProgramEvents.push_back ("post-modify-command");
validProgramEvents.push_back ("pre-prepend-command");
validProgramEvents.push_back ("post-prepend-command");
validProgramEvents.push_back ("pre-projects-command");
validProgramEvents.push_back ("post-projects-command");
validProgramEvents.push_back ("pre-pull-command");
validProgramEvents.push_back ("post-pull-command");
validProgramEvents.push_back ("pre-push-command");
validProgramEvents.push_back ("post-push-command");
validProgramEvents.push_back ("pre-shell-command");
validProgramEvents.push_back ("post-shell-command");
validProgramEvents.push_back ("pre-start-command");
validProgramEvents.push_back ("post-start-command");
validProgramEvents.push_back ("pre-stats-command");
validProgramEvents.push_back ("post-stats-command");
validProgramEvents.push_back ("pre-stop-command");
validProgramEvents.push_back ("post-stop-command");
validProgramEvents.push_back ("pre-summary-command");
validProgramEvents.push_back ("post-summary-command");
validProgramEvents.push_back ("pre-tags-command");
validProgramEvents.push_back ("post-tags-command");
validProgramEvents.push_back ("pre-timesheet-command");
validProgramEvents.push_back ("post-timesheet-command");
validProgramEvents.push_back ("pre-undo-command");
validProgramEvents.push_back ("post-undo-command");
validProgramEvents.push_back ("pre-usage-command");
validProgramEvents.push_back ("post-usage-command");
validProgramEvents.push_back ("pre-version-command");
validProgramEvents.push_back ("post-version-command");
validTaskEvents.push_back ("pre-display");
validTaskEvents.push_back ("pre-modification");
validTaskEvents.push_back ("post-modification");
validTaskEvents.push_back ("pre-delete");
validTaskEvents.push_back ("post-delete");
validTaskEvents.push_back ("pre-add");
validTaskEvents.push_back ("post-add");
validTaskEvents.push_back ("pre-undo");
validTaskEvents.push_back ("post-undo");
validTaskEvents.push_back ("pre-wait");
validTaskEvents.push_back ("post-wait");
validTaskEvents.push_back ("pre-unwait");
validTaskEvents.push_back ("post-unwait");
validTaskEvents.push_back ("pre-completed");
validTaskEvents.push_back ("post-completed");
validTaskEvents.push_back ("pre-priority-change");
validTaskEvents.push_back ("post-priority-change");
validTaskEvents.push_back ("pre-project-change");
validTaskEvents.push_back ("post-project-change");
validTaskEvents.push_back ("pre-substitution");
validTaskEvents.push_back ("post-substitution");
validTaskEvents.push_back ("pre-annotation");
validTaskEvents.push_back ("post-annotation");
validTaskEvents.push_back ("pre-tag");
validTaskEvents.push_back ("post-tag");
validTaskEvents.push_back ("pre-detag");
validTaskEvents.push_back ("post-detag");
validTaskEvents.push_back ("pre-colorization");
validTaskEvents.push_back ("post-colorization");
validFieldEvents.push_back ("format-number");
validFieldEvents.push_back ("format-date");
validFieldEvents.push_back ("format-duration");
validFieldEvents.push_back ("format-text");
validFieldEvents.push_back ("format-id");
validFieldEvents.push_back ("format-uuid");
validFieldEvents.push_back ("format-project");
validFieldEvents.push_back ("format-priority");
validFieldEvents.push_back ("format-priority_long");
validFieldEvents.push_back ("format-entry");
validFieldEvents.push_back ("format-start");
validFieldEvents.push_back ("format-end");
validFieldEvents.push_back ("format-due");
validFieldEvents.push_back ("format-countdown");
validFieldEvents.push_back ("format-countdown_compact");
validFieldEvents.push_back ("format-age");
validFieldEvents.push_back ("format-age_compact");
validFieldEvents.push_back ("format-active");
validFieldEvents.push_back ("format-tags");
validFieldEvents.push_back ("format-recur");
validFieldEvents.push_back ("format-recurrence_indicator");
validFieldEvents.push_back ("format-tag_indicator");
validFieldEvents.push_back ("format-description_only");
validFieldEvents.push_back ("format-description");
validFieldEvents.push_back ("format-wait");
validFieldEvents.push_back ("format-prompt");
validFieldEvents.push_back ("format-depends");
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -395,36 +206,6 @@ bool Hooks::trigger (const std::string& event, Task& task)
return true; return true;
} }
////////////////////////////////////////////////////////////////////////////////
// Field hooks.
bool Hooks::trigger (
const std::string& event,
const std::string& name,
std::string& value)
{
#ifdef HAVE_LIBLUA
std::vector <Hook>::iterator it;
for (it = all.begin (); it != all.end (); ++it)
{
if (it->event == event)
{
Timer timer (std::string ("Hooks::trigger ") + event);
if (validFieldEvent (event))
{
context.debug (std::string ("Event ") + event + " triggered");
if (! api.callFieldHook (it->file, it->function, name, value))
return false;
}
else
throw std::string ("Unrecognized hook event '") + event + "'.";
}
}
#endif
return true;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
bool Hooks::validProgramEvent (const std::string& event) bool Hooks::validProgramEvent (const std::string& event)
{ {
@ -442,12 +223,4 @@ bool Hooks::validTaskEvent (const std::string& event)
return false; return false;
} }
bool Hooks::validFieldEvent (const std::string& event)
{
if (std::find (validFieldEvents.begin (), validFieldEvents.end (), event) != validFieldEvents.end ())
return true;
return false;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View file

@ -60,12 +60,10 @@ public:
bool trigger (const std::string&); // Program bool trigger (const std::string&); // Program
bool trigger (const std::string&, Task&); // Task bool trigger (const std::string&, Task&); // Task
bool trigger (const std::string&, const std::string&, std::string&); // Field
private: private:
bool validProgramEvent (const std::string&); bool validProgramEvent (const std::string&);
bool validTaskEvent (const std::string&); bool validTaskEvent (const std::string&);
bool validFieldEvent (const std::string&);
private: private:
#ifdef HAVE_LIBLUA #ifdef HAVE_LIBLUA
@ -75,7 +73,6 @@ private:
std::vector <std::string> validProgramEvents; std::vector <std::string> validProgramEvents;
std::vector <std::string> validTaskEvents; std::vector <std::string> validTaskEvents;
std::vector <std::string> validFieldEvents;
}; };
#endif #endif

View file

@ -191,25 +191,21 @@ void TDB::location (const std::string& path)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void TDB::lock (bool lockFile /* = true */) void TDB::lock (bool lockFile /* = true */)
{ {
if (context.hooks.trigger ("pre-file-lock")) mLock = lockFile;
mPending.clear ();
mNew.clear ();
mCompleted.clear ();
mModified.clear ();
foreach (location, mLocations)
{ {
mLock = lockFile; location->pending = openAndLock (location->path + "/pending.data");
location->completed = openAndLock (location->path + "/completed.data");
mPending.clear (); location->undo = openAndLock (location->path + "/undo.data");
mNew.clear ();
mCompleted.clear ();
mModified.clear ();
foreach (location, mLocations)
{
location->pending = openAndLock (location->path + "/pending.data");
location->completed = openAndLock (location->path + "/completed.data");
location->undo = openAndLock (location->path + "/undo.data");
}
mAllOpenAndLocked = true;
context.hooks.trigger ("post-file-lock");
} }
mAllOpenAndLocked = true;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -492,7 +488,6 @@ void TDB::update (const Task& task)
int TDB::commit () int TDB::commit ()
{ {
Timer t ("TDB::commit"); Timer t ("TDB::commit");
context.hooks.trigger ("pre-commit");
int quantity = mNew.size () + mModified.size (); int quantity = mNew.size () + mModified.size ();
@ -512,7 +507,6 @@ int TDB::commit ()
writeUndo (*task, mLocations[0].undo); writeUndo (*task, mLocations[0].undo);
mNew.clear (); mNew.clear ();
context.hooks.trigger ("post-commit");
return quantity; return quantity;
} }
@ -579,7 +573,6 @@ int TDB::commit ()
mNew.clear (); mNew.clear ();
} }
context.hooks.trigger ("post-commit");
return quantity; return quantity;
} }
@ -713,7 +706,6 @@ int TDB::nextId ()
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void TDB::undo () void TDB::undo ()
{ {
context.hooks.trigger ("pre-undo");
Directory location (context.config.get ("data.location")); Directory location (context.config.get ("data.location"));
std::string undoFile = location.data + "/undo.data"; std::string undoFile = location.data + "/undo.data";
@ -997,7 +989,6 @@ void TDB::undo ()
!confirm ("The undo command is not reversible. Are you sure you want to revert to the previous state?")) !confirm ("The undo command is not reversible. Are you sure you want to revert to the previous state?"))
{ {
std::cout << "No changes made.\n"; std::cout << "No changes made.\n";
context.hooks.trigger ("post-undo");
return; return;
} }
@ -1035,7 +1026,6 @@ void TDB::undo ()
// Rewrite files. // Rewrite files.
File::write (pendingFile, p); File::write (pendingFile, p);
File::write (undoFile, u); File::write (undoFile, u);
context.hooks.trigger ("post-undo");
return; return;
} }
} }
@ -1074,7 +1064,6 @@ void TDB::undo ()
} }
std::cout << "Undo complete.\n"; std::cout << "Undo complete.\n";
context.hooks.trigger ("post-undo");
return; return;
} }
} }

View file

@ -341,25 +341,21 @@ void TDB::location (const std::string& path)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void TDB::lock (bool lockFile /* = true */) void TDB::lock (bool lockFile /* = true */)
{ {
if (context.hooks.trigger ("pre-file-lock")) mLock = lockFile;
mPending.clear ();
mNew.clear ();
mCompleted.clear ();
mModified.clear ();
foreach (location, mLocations)
{ {
mLock = lockFile; location->pending = openAndLock (location->path + "/pending.data");
location->completed = openAndLock (location->path + "/completed.data");
mPending.clear (); location->undo = openAndLock (location->path + "/undo.data");
mNew.clear ();
mCompleted.clear ();
mModified.clear ();
foreach (location, mLocations)
{
location->pending = openAndLock (location->path + "/pending.data");
location->completed = openAndLock (location->path + "/completed.data");
location->undo = openAndLock (location->path + "/undo.data");
}
mAllOpenAndLocked = true;
context.hooks.trigger ("post-file-lock");
} }
mAllOpenAndLocked = true;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -642,7 +638,6 @@ void TDB::update (const Task& task)
int TDB::commit () int TDB::commit ()
{ {
Timer t ("TDB::commit"); Timer t ("TDB::commit");
context.hooks.trigger ("pre-commit");
int quantity = mNew.size () + mModified.size (); int quantity = mNew.size () + mModified.size ();
@ -662,7 +657,6 @@ int TDB::commit ()
writeUndo (*task, mLocations[0].undo); writeUndo (*task, mLocations[0].undo);
mNew.clear (); mNew.clear ();
context.hooks.trigger ("post-commit");
return quantity; return quantity;
} }
@ -729,7 +723,6 @@ int TDB::commit ()
mNew.clear (); mNew.clear ();
} }
context.hooks.trigger ("post-commit");
return quantity; return quantity;
} }
@ -863,7 +856,6 @@ int TDB::nextId ()
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void TDB::undo () void TDB::undo ()
{ {
context.hooks.trigger ("pre-undo");
Directory location (context.config.get ("data.location")); Directory location (context.config.get ("data.location"));
std::string undoFile = location.data + "/undo.data"; std::string undoFile = location.data + "/undo.data";
@ -1147,7 +1139,6 @@ void TDB::undo ()
!confirm ("The undo command is not reversible. Are you sure you want to revert to the previous state?")) !confirm ("The undo command is not reversible. Are you sure you want to revert to the previous state?"))
{ {
std::cout << "No changes made.\n"; std::cout << "No changes made.\n";
context.hooks.trigger ("post-undo");
return; return;
} }
@ -1185,7 +1176,6 @@ void TDB::undo ()
// Rewrite files. // Rewrite files.
File::write (pendingFile, p); File::write (pendingFile, p);
File::write (undoFile, u); File::write (undoFile, u);
context.hooks.trigger ("post-undo");
return; return;
} }
} }
@ -1224,7 +1214,6 @@ void TDB::undo ()
} }
std::cout << "Undo complete.\n"; std::cout << "Undo complete.\n";
context.hooks.trigger ("post-undo");
return; return;
} }
} }

View file

@ -974,47 +974,41 @@ int handleReportBurndownDaily (std::string& outs)
{ {
int rc = 0; int rc = 0;
if (context.hooks.trigger ("pre-burndown-command")) // Scan the pending tasks, applying any filter.
std::vector <Task> tasks;
context.tdb.lock (context.config.getBoolean ("locking"));
handleRecurrence ();
context.tdb.load (tasks, context.filter);
context.tdb.commit ();
context.tdb.unlock ();
// Create a chart, scan the tasks, then render.
Chart chart ('D');
// Use any filter as a title.
if (context.filter.size ())
{ {
// Scan the pending tasks, applying any filter. std::string combined = "(";
std::vector <Task> tasks;
context.tdb.lock (context.config.getBoolean ("locking"));
handleRecurrence ();
context.tdb.load (tasks, context.filter);
context.tdb.commit ();
context.tdb.unlock ();
// Create a chart, scan the tasks, then render. for (unsigned int i = 0; i < context.filter.size (); ++i)
Chart chart ('D');
// Use any filter as a title.
if (context.filter.size ())
{ {
std::string combined = "("; if (i)
combined += " ";
for (unsigned int i = 0; i < context.filter.size (); ++i) combined += context.filter[i].name ();
{
if (i)
combined += " ";
combined += context.filter[i].name (); if (context.filter[i].mod ().length ())
combined += "." + context.filter[i].mod ();
if (context.filter[i].mod ().length ()) combined += ":" + context.filter[i].value ();
combined += "." + context.filter[i].mod ();
combined += ":" + context.filter[i].value ();
}
combined += ")";
chart.description (combined);
} }
chart.scan (tasks); combined += ")";
outs = chart.render (); chart.description (combined);
context.hooks.trigger ("post-burndown-command");
} }
chart.scan (tasks);
outs = chart.render ();
return rc; return rc;
} }
@ -1023,47 +1017,41 @@ int handleReportBurndownWeekly (std::string& outs)
{ {
int rc = 0; int rc = 0;
if (context.hooks.trigger ("pre-burndown-command")) // Scan the pending tasks, applying any filter.
std::vector <Task> tasks;
context.tdb.lock (context.config.getBoolean ("locking"));
handleRecurrence ();
context.tdb.load (tasks, context.filter);
context.tdb.commit ();
context.tdb.unlock ();
// Create a chart, scan the tasks, then render.
Chart chart ('W');
// Use any filter as a title.
if (context.filter.size ())
{ {
// Scan the pending tasks, applying any filter. std::string combined = "(";
std::vector <Task> tasks;
context.tdb.lock (context.config.getBoolean ("locking"));
handleRecurrence ();
context.tdb.load (tasks, context.filter);
context.tdb.commit ();
context.tdb.unlock ();
// Create a chart, scan the tasks, then render. for (unsigned int i = 0; i < context.filter.size (); ++i)
Chart chart ('W');
// Use any filter as a title.
if (context.filter.size ())
{ {
std::string combined = "("; if (i)
combined += " ";
for (unsigned int i = 0; i < context.filter.size (); ++i) combined += context.filter[i].name ();
{
if (i)
combined += " ";
combined += context.filter[i].name (); if (context.filter[i].mod ().length ())
combined += "." + context.filter[i].mod ();
if (context.filter[i].mod ().length ()) combined += ":" + context.filter[i].value ();
combined += "." + context.filter[i].mod ();
combined += ":" + context.filter[i].value ();
}
combined += ")";
chart.description (combined);
} }
chart.scan (tasks); combined += ")";
outs = chart.render (); chart.description (combined);
context.hooks.trigger ("post-burndown-command");
} }
chart.scan (tasks);
outs = chart.render ();
return rc; return rc;
} }
@ -1072,47 +1060,41 @@ int handleReportBurndownMonthly (std::string& outs)
{ {
int rc = 0; int rc = 0;
if (context.hooks.trigger ("pre-burndown-command")) // Scan the pending tasks, applying any filter.
std::vector <Task> tasks;
context.tdb.lock (context.config.getBoolean ("locking"));
handleRecurrence ();
context.tdb.load (tasks, context.filter);
context.tdb.commit ();
context.tdb.unlock ();
// Create a chart, scan the tasks, then render.
Chart chart ('M');
// Use any filter as a title.
if (context.filter.size ())
{ {
// Scan the pending tasks, applying any filter. std::string combined = "(";
std::vector <Task> tasks;
context.tdb.lock (context.config.getBoolean ("locking"));
handleRecurrence ();
context.tdb.load (tasks, context.filter);
context.tdb.commit ();
context.tdb.unlock ();
// Create a chart, scan the tasks, then render. for (unsigned int i = 0; i < context.filter.size (); ++i)
Chart chart ('M');
// Use any filter as a title.
if (context.filter.size ())
{ {
std::string combined = "("; if (i)
combined += " ";
for (unsigned int i = 0; i < context.filter.size (); ++i) combined += context.filter[i].name ();
{
if (i)
combined += " ";
combined += context.filter[i].name (); if (context.filter[i].mod ().length ())
combined += "." + context.filter[i].mod ();
if (context.filter[i].mod ().length ()) combined += ":" + context.filter[i].value ();
combined += "." + context.filter[i].mod ();
combined += ":" + context.filter[i].value ();
}
combined += ")";
chart.description (combined);
} }
chart.scan (tasks); combined += ")";
outs = chart.render (); chart.description (combined);
context.hooks.trigger ("post-burndown-command");
} }
chart.scan (tasks);
outs = chart.render ();
return rc; return rc;
} }

View file

@ -2457,7 +2457,7 @@ void handleShell ()
std::string prompt = context.config.get ("shell.prompt"); std::string prompt = context.config.get ("shell.prompt");
if (context.hooks.trigger ("pre-shell-prompt")) if (context.hooks.trigger ("pre-shell-prompt"))
{ {
context.hooks.trigger ("format-prompt", "prompt", prompt); //context.hooks.trigger ("format-prompt", "prompt", prompt);
std::cout << prompt << " "; std::cout << prompt << " ";
} }
context.hooks.trigger ("post-shell-prompt"); context.hooks.trigger ("post-shell-prompt");

File diff suppressed because it is too large Load diff

View file

@ -652,32 +652,27 @@ int handleEdit (std::string& outs)
{ {
int rc = 0; int rc = 0;
if (context.hooks.trigger ("pre-edit-command")) std::stringstream out;
{
std::stringstream out;
std::vector <Task> tasks; std::vector <Task> tasks;
context.tdb.lock (context.config.getBoolean ("locking")); context.tdb.lock (context.config.getBoolean ("locking"));
handleRecurrence (); handleRecurrence ();
Filter filter; Filter filter;
context.tdb.loadPending (tasks, filter); context.tdb.loadPending (tasks, filter);
// Filter sequence. // Filter sequence.
std::vector <Task> all = tasks; std::vector <Task> all = tasks;
context.filter.applySequence (tasks, context.sequence); context.filter.applySequence (tasks, context.sequence);
std::vector <Task>::iterator task; std::vector <Task>::iterator task;
for (task = tasks.begin (); task != tasks.end (); ++task) for (task = tasks.begin (); task != tasks.end (); ++task)
if (editFile (*task)) if (editFile (*task))
context.tdb.update (*task); context.tdb.update (*task);
context.tdb.commit (); context.tdb.commit ();
context.tdb.unlock (); context.tdb.unlock ();
outs = out.str ();
context.hooks.trigger ("post-edit-command");
}
outs = out.str ();
return rc; return rc;
} }

View file

@ -41,50 +41,40 @@ extern Context context;
int handleExportCSV (std::string& outs) int handleExportCSV (std::string& outs)
{ {
int rc = 0; int rc = 0;
std::stringstream out;
if (context.hooks.trigger ("pre-export-command")) // Deliberately no 'id'.
{ out << "'uuid',"
std::stringstream out; << "'status',"
<< "'tags',"
<< "'entry',"
<< "'start',"
<< "'due',"
<< "'recur',"
<< "'end',"
<< "'project',"
<< "'priority',"
<< "'fg',"
<< "'bg',"
<< "'description'"
<< "\n";
// Deliberately no 'id'. // Get all the tasks.
out << "'uuid'," std::vector <Task> tasks;
<< "'status'," context.tdb.lock (context.config.getBoolean ("locking"));
<< "'tags'," handleRecurrence ();
<< "'entry'," context.tdb.load (tasks, context.filter);
<< "'start'," context.tdb.commit ();
<< "'due'," context.tdb.unlock ();
<< "'recur',"
<< "'end',"
<< "'project',"
<< "'priority',"
<< "'fg',"
<< "'bg',"
<< "'description'"
<< "\n";
// Get all the tasks. foreach (task, tasks)
std::vector <Task> tasks; if (task->getStatus () != Task::recurring)
context.tdb.lock (context.config.getBoolean ("locking")); out << task->composeCSV ().c_str ();
handleRecurrence ();
context.tdb.load (tasks, context.filter);
context.tdb.commit ();
context.tdb.unlock ();
foreach (task, tasks) outs = out.str ();
{
context.hooks.trigger ("pre-display", *task);
if (task->getStatus () != Task::recurring)
out << task->composeCSV ().c_str ();
}
outs = out.str ();
context.hooks.trigger ("post-export-command");
// Prevent messages from cluttering the export output.
context.headers.clear ();
}
// Prevent messages from cluttering the export output.
context.headers.clear ();
return rc; return rc;
} }
@ -95,133 +85,125 @@ int handleExportCSV (std::string& outs)
int handleExportiCal (std::string& outs) int handleExportiCal (std::string& outs)
{ {
int rc = 0; int rc = 0;
std::stringstream out;
if (context.hooks.trigger ("pre-export-command")) out << "BEGIN:VCALENDAR\n"
<< "VERSION:2.0\n"
<< "PRODID:-//GBF//" << PACKAGE_STRING << "//EN\n";
// Get all the tasks.
std::vector <Task> tasks;
context.tdb.lock (context.config.getBoolean ("locking"));
handleRecurrence ();
context.tdb.load (tasks, context.filter);
context.tdb.commit ();
context.tdb.unlock ();
foreach (task, tasks)
{ {
std::stringstream out; if (task->getStatus () != Task::recurring)
out << "BEGIN:VCALENDAR\n"
<< "VERSION:2.0\n"
<< "PRODID:-//GBF//" << PACKAGE_STRING << "//EN\n";
// Get all the tasks.
std::vector <Task> tasks;
context.tdb.lock (context.config.getBoolean ("locking"));
handleRecurrence ();
context.tdb.load (tasks, context.filter);
context.tdb.commit ();
context.tdb.unlock ();
foreach (task, tasks)
{ {
context.hooks.trigger ("pre-display", *task); out << "BEGIN:VTODO\n";
if (task->getStatus () != Task::recurring) // Required UID:20070313T123432Z-456553@example.com
out << "UID:" << task->get ("uuid") << "\n";
// Required DTSTAMP:20070313T123432Z
Date entry (atoi (task->get ("entry").c_str ()));
out << "DTSTAMP:" << entry.toISO () << "\n";
// Optional DTSTART:20070514T110000Z
if (task->has ("start"))
{ {
out << "BEGIN:VTODO\n"; Date start (atoi (task->get ("start").c_str ()));
out << "DTSTART:" << start.toISO () << "\n";
// Required UID:20070313T123432Z-456553@example.com
out << "UID:" << task->get ("uuid") << "\n";
// Required DTSTAMP:20070313T123432Z
Date entry (atoi (task->get ("entry").c_str ()));
out << "DTSTAMP:" << entry.toISO () << "\n";
// Optional DTSTART:20070514T110000Z
if (task->has ("start"))
{
Date start (atoi (task->get ("start").c_str ()));
out << "DTSTART:" << start.toISO () << "\n";
}
// Optional DUE:20070709T130000Z
if (task->has ("due"))
{
Date due (atoi (task->get ("due").c_str ()));
out << "DUE:" << due.toISO () << "\n";
}
// Optional COMPLETED:20070707T100000Z
if (task->has ("end") && task->getStatus () == Task::completed)
{
Date end (atoi (task->get ("end").c_str ()));
out << "COMPLETED:" << end.toISO () << "\n";
}
out << "SUMMARY:" << task->get ("description") << "\n";
// Optional CLASS:PUBLIC/PRIVATE/CONFIDENTIAL
std::string classification = context.config.get ("export.ical.class");
if (classification == "")
classification = "PRIVATE";
out << "CLASS:" << classification << "\n";
// Optional multiple CATEGORIES:FAMILY,FINANCE
if (task->getTagCount () > 0)
{
std::vector <std::string> tags;
task->getTags (tags);
std::string all;
join (all, ",", tags);
out << "CATEGORIES:" << all << "\n";
}
// Optional PRIORITY:
// 1-4 H
// 5 M
// 6-9 L
if (task->has ("priority"))
{
out << "PRIORITY:";
std::string priority = task->get ("priority");
if (priority == "H") out << "1";
else if (priority == "M") out << "5";
else out << "9";
out << "\n";
}
// Optional STATUS:NEEDS-ACTION/IN-PROCESS/COMPLETED/CANCELLED
out << "STATUS:";
Task::status stat = task->getStatus ();
if (stat == Task::pending || stat == Task::waiting)
{
if (task->has ("start"))
out << "IN-PROCESS";
else
out << "NEEDS-ACTION";
}
else if (stat == Task::completed)
{
out << "COMPLETED";
}
else if (stat == Task::deleted)
{
out << "CANCELLED";
}
out << "\n";
// Optional COMMENT:annotation1
// Optional COMMENT:annotation2
std::vector <Att> annotations;
task->getAnnotations (annotations);
foreach (anno, annotations)
out << "COMMENT:" << anno->value () << "\n";
out << "END:VTODO\n";
} }
// Optional DUE:20070709T130000Z
if (task->has ("due"))
{
Date due (atoi (task->get ("due").c_str ()));
out << "DUE:" << due.toISO () << "\n";
}
// Optional COMPLETED:20070707T100000Z
if (task->has ("end") && task->getStatus () == Task::completed)
{
Date end (atoi (task->get ("end").c_str ()));
out << "COMPLETED:" << end.toISO () << "\n";
}
out << "SUMMARY:" << task->get ("description") << "\n";
// Optional CLASS:PUBLIC/PRIVATE/CONFIDENTIAL
std::string classification = context.config.get ("export.ical.class");
if (classification == "")
classification = "PRIVATE";
out << "CLASS:" << classification << "\n";
// Optional multiple CATEGORIES:FAMILY,FINANCE
if (task->getTagCount () > 0)
{
std::vector <std::string> tags;
task->getTags (tags);
std::string all;
join (all, ",", tags);
out << "CATEGORIES:" << all << "\n";
}
// Optional PRIORITY:
// 1-4 H
// 5 M
// 6-9 L
if (task->has ("priority"))
{
out << "PRIORITY:";
std::string priority = task->get ("priority");
if (priority == "H") out << "1";
else if (priority == "M") out << "5";
else out << "9";
out << "\n";
}
// Optional STATUS:NEEDS-ACTION/IN-PROCESS/COMPLETED/CANCELLED
out << "STATUS:";
Task::status stat = task->getStatus ();
if (stat == Task::pending || stat == Task::waiting)
{
if (task->has ("start"))
out << "IN-PROCESS";
else
out << "NEEDS-ACTION";
}
else if (stat == Task::completed)
{
out << "COMPLETED";
}
else if (stat == Task::deleted)
{
out << "CANCELLED";
}
out << "\n";
// Optional COMMENT:annotation1
// Optional COMMENT:annotation2
std::vector <Att> annotations;
task->getAnnotations (annotations);
foreach (anno, annotations)
out << "COMMENT:" << anno->value () << "\n";
out << "END:VTODO\n";
} }
out << "END:VCALENDAR\n";
outs = out.str ();
context.hooks.trigger ("post-export-command");
// Prevent messages from cluttering the export output.
context.headers.clear ();
} }
out << "END:VCALENDAR\n";
outs = out.str ();
// Prevent messages from cluttering the export output.
context.headers.clear ();
return rc; return rc;
} }
@ -230,36 +212,27 @@ int handleExportYAML (std::string& outs)
{ {
int rc = 0; int rc = 0;
if (context.hooks.trigger ("pre-export-command")) // YAML header.
{ std::stringstream out;
// YAML header. out << "%YAML 1.1\n"
std::stringstream out; << "---\n";
out << "%YAML 1.1\n"
<< "---\n";
// Get all the tasks. // Get all the tasks.
std::vector <Task> tasks; std::vector <Task> tasks;
context.tdb.lock (context.config.getBoolean ("locking")); context.tdb.lock (context.config.getBoolean ("locking"));
handleRecurrence (); handleRecurrence ();
context.tdb.load (tasks, context.filter); context.tdb.load (tasks, context.filter);
context.tdb.commit (); context.tdb.commit ();
context.tdb.unlock (); context.tdb.unlock ();
foreach (task, tasks) foreach (task, tasks)
{ out << task->composeYAML ().c_str ();
context.hooks.trigger ("pre-display", *task);
out << task->composeYAML ().c_str ();
}
out << "...\n"; out << "...\n";
outs = out.str ();
outs = out.str ();
context.hooks.trigger ("post-export-command");
// Prevent messages from cluttering the export output.
context.headers.clear ();
}
// Prevent messages from cluttering the export output.
context.headers.clear ();
return rc; return rc;
} }

File diff suppressed because it is too large Load diff

View file

@ -1264,94 +1264,88 @@ static std::string importYAML (const std::vector <std::string>& lines)
int handleImport (std::string& outs) int handleImport (std::string& outs)
{ {
int rc = 0; int rc = 0;
std::stringstream out;
if (context.hooks.trigger ("pre-import-command")) // Use the description as a file name.
std::string file = trim (context.task.get ("description"));
std::string tmpfile = "";
Uri uri (file);
uri.parse ();
Transport* transport;
if ((transport = Transport::getTransport (uri)) != NULL )
{ {
std::stringstream out; std::string location (context.config.get ("data.location"));
tmpfile = location + "/import.data";
transport->recv (tmpfile);
delete transport;
// Use the description as a file name. file = tmpfile;
std::string file = trim (context.task.get ("description"));
std::string tmpfile = "";
Uri uri (file);
uri.parse ();
Transport* transport;
if ((transport = Transport::getTransport (uri)) != NULL )
{
std::string location (context.config.get ("data.location"));
tmpfile = location + "/import.data";
transport->recv (tmpfile);
delete transport;
file = tmpfile;
}
if (file.length () > 0)
{
// Load the file.
std::vector <std::string> all;
File::read (file, all);
std::vector <std::string> lines;
std::vector <std::string>::iterator it;
for (it = all.begin (); it != all.end (); ++it)
{
std::string line = *it;
trim (line);
// Skip blank lines
if (line.length () > 0)
lines.push_back (line);
}
// Take a guess at the file type.
fileType type = determineFileType (lines);
std::string identifier;
switch (type)
{
case task_1_4_3: identifier = "This looks like an older taskwarrior export file."; break;
case task_1_5_0: identifier = "This looks like a recent taskwarrior export file."; break;
case task_1_6_0: identifier = "This looks like a current taskwarrior export file."; break;
case task_cmd_line: identifier = "This looks like taskwarrior command line arguments."; break;
case todo_sh_2_0: identifier = "This looks like a todo.sh 2.x file."; break;
case csv: identifier = "This looks like a CSV file, but not a taskwarrior export file."; break;
case yaml: identifier = "This looks like a YAML file."; break;
case text: identifier = "This looks like a text file with one task per line."; break;
case not_a_clue:
throw std::string ("Taskwarrior cannot determine which type of file "
"this is, and cannot proceed.");
}
// For tty users, confirm the import, as it is destructive.
if (isatty (fileno (stdout)))
if (! confirm (identifier + " Okay to proceed?"))
throw std::string ("Taskwarrior will not import any data.");
// Determine which type it might be, then attempt an import.
switch (type)
{
case task_1_4_3: out << importTask_1_4_3 (lines); break;
case task_1_5_0: out << importTask_1_5_0 (lines); break;
case task_1_6_0: out << importTask_1_6_0 (lines); break;
case task_cmd_line: out << importTaskCmdLine (lines); break;
case todo_sh_2_0: out << importTodoSh_2_0 (lines); break;
case csv: out << importCSV (lines); break;
case yaml: out << importYAML (lines); break;
case text: out << importText (lines); break;
case not_a_clue: /* to stop the compiler from complaining. */ break;
}
if (tmpfile != "")
remove (tmpfile.c_str ());
}
else
throw std::string ("You must specify a file to import.");
outs = out.str ();
context.hooks.trigger ("post-import-command");
} }
if (file.length () > 0)
{
// Load the file.
std::vector <std::string> all;
File::read (file, all);
std::vector <std::string> lines;
std::vector <std::string>::iterator it;
for (it = all.begin (); it != all.end (); ++it)
{
std::string line = *it;
trim (line);
// Skip blank lines
if (line.length () > 0)
lines.push_back (line);
}
// Take a guess at the file type.
fileType type = determineFileType (lines);
std::string identifier;
switch (type)
{
case task_1_4_3: identifier = "This looks like an older taskwarrior export file."; break;
case task_1_5_0: identifier = "This looks like a recent taskwarrior export file."; break;
case task_1_6_0: identifier = "This looks like a current taskwarrior export file."; break;
case task_cmd_line: identifier = "This looks like taskwarrior command line arguments."; break;
case todo_sh_2_0: identifier = "This looks like a todo.sh 2.x file."; break;
case csv: identifier = "This looks like a CSV file, but not a taskwarrior export file."; break;
case yaml: identifier = "This looks like a YAML file."; break;
case text: identifier = "This looks like a text file with one task per line."; break;
case not_a_clue:
throw std::string ("Taskwarrior cannot determine which type of file "
"this is, and cannot proceed.");
}
// For tty users, confirm the import, as it is destructive.
if (isatty (fileno (stdout)))
if (! confirm (identifier + " Okay to proceed?"))
throw std::string ("Taskwarrior will not import any data.");
// Determine which type it might be, then attempt an import.
switch (type)
{
case task_1_4_3: out << importTask_1_4_3 (lines); break;
case task_1_5_0: out << importTask_1_5_0 (lines); break;
case task_1_6_0: out << importTask_1_6_0 (lines); break;
case task_cmd_line: out << importTaskCmdLine (lines); break;
case todo_sh_2_0: out << importTodoSh_2_0 (lines); break;
case csv: out << importCSV (lines); break;
case yaml: out << importYAML (lines); break;
case text: out << importText (lines); break;
case not_a_clue: /* to stop the compiler from complaining. */ break;
}
if (tmpfile != "")
remove (tmpfile.c_str ());
}
else
throw std::string ("You must specify a file to import.");
outs = out.str ();
return rc; return rc;
} }

File diff suppressed because it is too large Load diff

View file

@ -35,7 +35,7 @@ if (open my $fh, '>', 'hook.rc')
{ {
print $fh "data.location=.\n", print $fh "data.location=.\n",
"hooks=on\n", "hooks=on\n",
"hook.pre-exit=" . $ENV{'PWD'} . "/hook:test\n"; "hook.on-exit=" . $ENV{'PWD'} . "/hook:test\n";
close $fh; close $fh;
ok (-r 'hook.rc', 'Created hook.rc'); ok (-r 'hook.rc', 'Created hook.rc');
} }

View file

@ -35,7 +35,7 @@ if (open my $fh, '>', 'hook.rc')
{ {
print $fh "data.location=.\n", print $fh "data.location=.\n",
"hooks=on\n", "hooks=on\n",
"hook.post-start=" . $ENV{'PWD'} . "/hook:test\n"; "hook.on-launch=" . $ENV{'PWD'} . "/hook:test\n";
close $fh; close $fh;
ok (-r 'hook.rc', 'Created hook.rc'); ok (-r 'hook.rc', 'Created hook.rc');
} }