Enhancement - Integration

- Integrated Cmd object.
- Enhanced Context object with dispatch and shadow methods.
- Fixed bug in Context::parse.
- Implemented command parsing.
- Fixed Sequence bug, and unit tests.
This commit is contained in:
Paul Beckingham 2009-06-07 16:00:22 -04:00
parent 190c6b53fc
commit d702ba8f24
7 changed files with 128 additions and 35 deletions

View file

@ -134,7 +134,7 @@ void Cmd::loadCommands ()
commands.push_back (context.stringtable.get (CMD_OVERDUE, "overdue"));
commands.push_back (context.stringtable.get (CMD_PROJECTS, "projects"));
commands.push_back (context.stringtable.get (CMD_START, "start"));
commands.push_back (context.stringtable.get (CMD_STATS, "statistics"));
commands.push_back (context.stringtable.get (CMD_STATS, "stats"));
commands.push_back (context.stringtable.get (CMD_STOP, "stop"));
commands.push_back (context.stringtable.get (CMD_SUMMARY, "summary"));
commands.push_back (context.stringtable.get (CMD_TAGS, "tags"));

View file

@ -46,7 +46,8 @@ Context::Context ()
, task ()
, tdb ()
, stringtable ()
, command ("")
, program ("")
, cmd ()
{
// Set up randomness.
#ifdef HAVE_SRANDOM
@ -68,8 +69,9 @@ Context::Context (const Context& other)
task = other.task;
tdb = other.tdb;
stringtable = other.stringtable;
program = other.program;
args = other.args;
command = other.command;
cmd = other.cmd;
messages = other.messages;
footnotes = other.footnotes;
}
@ -88,8 +90,9 @@ Context& Context::operator= (const Context& other)
task = other.task;
tdb = other.tdb;
stringtable = other.stringtable;
program = other.program;
args = other.args;
command = other.command;
cmd = other.cmd;
messages = other.messages;
footnotes = other.footnotes;
}
@ -107,6 +110,9 @@ void Context::initialize (int argc, char** argv)
{
// Capture the args.
for (int i = 0; i < argc; ++i)
if (i == 0)
program = argv[i];
else
args.push_back (argv[i]);
// Load the configuration file from the home directory. If the file cannot
@ -148,12 +154,11 @@ int Context::run ()
std::cout << "--- start 1.8.0 ---" << std::endl;
try
{
parse ();
// TODO Dispatch to command handlers.
// TODO Auto shadow update.
// TODO Auto gc.
parse (); // Parse command line.
// TODO tdb.load (Filter);
dispatch (); // Dispatch to command handlers.
// TODO Auto gc.
shadow (); // Auto shadow update.
}
catch (const std::string& error)
@ -181,6 +186,86 @@ int Context::run ()
return 0;
}
////////////////////////////////////////////////////////////////////////////////
void Context::dispatch ()
{
/*
// If argc == 1 and there is a default.command, use it. Otherwise use
// argc/argv.
std::string defaultCommand = context.config.get ("default.command");
if (args.size () == 0 || defaultCommand != "")
{
// Stuff the command line.
args.clear ();
split (args, defaultCommand, ' ');
std::cout << "[task " << defaultCommand << "]" << std::endl;
}
loadCustomReports ();
std::string command;
T task;
parse (args, command, task);
bool gcMod = false; // Change occurred by way of gc.
bool cmdMod = false; // Change occurred by way of command type.
std::string out;
// Read-only commands with no side effects.
if (command == "export") { out = handleExport (tdb, task); }
else if (command == "projects") { out = handleProjects (tdb, task); }
else if (command == "tags") { out = handleTags (tdb, task); }
else if (command == "info") { out = handleInfo (tdb, task); }
else if (command == "stats") { out = handleReportStats (tdb, task); }
else if (command == "history") { out = handleReportHistory (tdb, task); }
else if (command == "ghistory") { out = handleReportGHistory (tdb, task); }
else if (command == "calendar") { out = handleReportCalendar (tdb, task); }
else if (command == "summary") { out = handleReportSummary (tdb, task); }
else if (command == "timesheet") { out = handleReportTimesheet (tdb, task); }
else if (command == "colors") { out = handleColor ( ); }
else if (command == "version") { out = handleVersion ( ); }
else if (command == "help") { out = longUsage ( ); }
// Commands that cause updates.
else if (command == "" && task.getId ()) { cmdMod = true; out = handleModify (tdb, task); }
else if (command == "add") { cmdMod = true; out = handleAdd (tdb, task); }
else if (command == "append") { cmdMod = true; out = handleAppend (tdb, task); }
else if (command == "annotate") { cmdMod = true; out = handleAnnotate (tdb, task); }
else if (command == "done") { cmdMod = true; out = handleDone (tdb, task); }
else if (command == "undelete") { cmdMod = true; out = handleUndelete (tdb, task); }
else if (command == "delete") { cmdMod = true; out = handleDelete (tdb, task); }
else if (command == "start") { cmdMod = true; out = handleStart (tdb, task); }
else if (command == "stop") { cmdMod = true; out = handleStop (tdb, task); }
else if (command == "undo") { cmdMod = true; out = handleUndo (tdb, task); }
else if (command == "import") { cmdMod = true; out = handleImport (tdb, task); }
else if (command == "duplicate") { cmdMod = true; out = handleDuplicate (tdb, task); }
else if (command == "edit") { cmdMod = true; out = handleEdit (tdb, task); }
// Command that display IDs and therefore need TDB::gc first.
else if (command == "completed") { if (gc) gcMod = tdb.gc (); out = handleCompleted (tdb, task); }
else if (command == "next") { if (gc) gcMod = tdb.gc (); out = handleReportNext (tdb, task); }
else if (command == "active") { if (gc) gcMod = tdb.gc (); out = handleReportActive (tdb, task); }
else if (command == "overdue") { if (gc) gcMod = tdb.gc (); out = handleReportOverdue (tdb, task); }
else if (isCustomReport (command)) { if (gc) gcMod = tdb.gc (); out = handleCustomReport (tdb, task, command); }
// If the command is not recognized, display usage.
else { out = shortUsage (); }
// Only update the shadow file if such an update was not suppressed (shadow),
// and if an actual change occurred (gcMod || cmdMod).
if (shadow && (gcMod || cmdMod))
updateShadowFile (tdb);
return out;
*/
}
////////////////////////////////////////////////////////////////////////////////
void Context::shadow ()
{
throw std::string ("unimplemented Context::shadow");
}
////////////////////////////////////////////////////////////////////////////////
void Context::loadCorrectConfigFile ()
{
@ -237,7 +322,6 @@ void Context::loadCorrectConfigFile ()
////////////////////////////////////////////////////////////////////////////////
void Context::parse ()
{
command = "";
std::string descCandidate = "";
bool terminated = false;
bool foundSequence = false;
@ -249,15 +333,18 @@ void Context::parse ()
{
// The '--' argument shuts off all parsing - everything is an argument.
if (*arg == "--")
{
std::cout << "# parse terminator '" << *arg << "'" << std::endl;
terminated = true;
}
// Sequence
// Note: "add" doesn't require an ID
else if (command != "add" &&
sequence.valid (*arg) &&
! foundSomethingAfterSequence)
else if (cmd.command != "add" &&
! foundSomethingAfterSequence &&
sequence.valid (*arg))
{
std::cout << "# found sequence" << std::endl;
std::cout << "# parse sequence '" << *arg << "'" << std::endl;
sequence.parse (*arg);
foundSequence = true;
}
@ -309,30 +396,25 @@ void Context::parse ()
if (foundSequence)
foundSomethingAfterSequence = true;
std::cout << "# found subst" << std::endl;
std::cout << "# parse subst '" << *arg << "'" << std::endl;
subst.parse (*arg);
}
/*
// Command.
else if (command == "")
// It might be a command if one has not already been found.
else if (cmd.command == "" &&
cmd.valid (*arg))
{
std::cout << "# parse cmd '" << *arg << "'" << std::endl;
cmd.parse (*arg);
if (foundSequence)
foundSomethingAfterSequence = true;
}
std::string l = lowerCase (arg);
if (isCommand (l) && validCommand (l))
command = l;
else
{
if (descCandidate.length ())
descCandidate += " ";
descCandidate += arg;
}
}
*/
// Anything else is just considered description.
else
{
std::cout << "# parse description '" << *arg << "'" << std::endl;
if (foundSequence)
foundSomethingAfterSequence = true;
@ -345,6 +427,7 @@ void Context::parse ()
// terminated, therefore everything subsequently is a description.
else
{
std::cout << "# parse post-termination description '" << *arg << "'" << std::endl;
if (foundSequence)
foundSomethingAfterSequence = true;

View file

@ -32,6 +32,7 @@
#include "Config.h"
#include "Sequence.h"
#include "Subst.h"
#include "Cmd.h"
#include "T2.h"
#include "TDB2.h"
#include "StringTable.h"
@ -47,6 +48,8 @@ public:
void initialize (int, char**); // all startup
int run (); // task classic
int interactive (); // task interactive (not implemented)
void dispatch (); // command handler dispatch
void shadow (); // shadow file update
void message (const std::string&); // Message sink
void footnote (const std::string&); // Footnote sink
@ -64,8 +67,9 @@ public:
T2 task;
TDB2 tdb;
StringTable stringtable;
std::string program;
std::vector <std::string> args;
std::string command;
Cmd cmd;
private:
std::vector <std::string> messages;

View file

@ -68,6 +68,12 @@ bool Sequence::valid (const std::string& input) const
if (range.size () < 1 ||
range.size () > 2)
return false;
if (range.size () == 1 && !validId (range[0]))
return false;
if (range.size () == 2 && !validId (range[1]))
return false;
}
return true;

View file

@ -5,7 +5,7 @@ LIBS =
OBJECTS = main.o ../Context.o ../TDB2.o ../T2.o ../Sequence.o ../Filter.o \
../Att.o ../Keymap.o ../Record.o ../StringTable.o ../Location.o \
../util.o ../text.o ../Date.o ../Config.o ../Subst.o ../Nibbler.o \
../parse.o ../Duration.o ../T.o
../parse.o ../Duration.o ../T.o ../Cmd.o
all: $(PROJECT)

View file

@ -304,7 +304,7 @@ int main (int argc, char** argv)
try
{
context.initialize (argc, argv);
if (context.args[0].find ("itask") != std::string::npos)
if (context.program.find ("itask") != std::string::npos)
status = context.interactive ();
else
status = context.run ();

View file

@ -48,6 +48,8 @@ int main (int argc, char** argv)
t.notok (seq.valid ("1--2"), "not valid 1--2");
t.notok (seq.valid ("1-2-3"), "not valid 1-2-3");
t.notok (seq.valid ("-1-2"), "not valid -1-2");
t.notok (seq.valid ("1-two"), "not valid 1-two");
t.notok (seq.valid ("one-2"), "not valid one-2");
t.ok (seq.valid ("1"), "valid 1");
t.ok (seq.valid ("1,3"), "valid 1,3");
@ -55,8 +57,6 @@ int main (int argc, char** argv)
t.ok (seq.valid ("1,3-5,7"), "valid 1,3-5,7");
t.ok (seq.valid ("1-1000"), "valid 1-1000");
t.ok (seq.valid ("1-1001"), "valid 1-1001");
t.ok (seq.valid ("1-two"), "valid 1-two");
t.ok (seq.valid ("one-2"), "valid one-2");
t.ok (seq.valid ("1-5,3-7"), "valid 1-5,3-7");
// 1