CLI/Context
- Reordering init sequence. - Removed ::assumeLocations.
This commit is contained in:
137
src/CLI.cpp
137
src/CLI.cpp
@@ -217,6 +217,95 @@ const std::string A::dump () const
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Static method.
|
||||||
|
void CLI::getOverride (int argc, const char** argv, std::string& home, File& rc)
|
||||||
|
{
|
||||||
|
bool terminated = false;
|
||||||
|
for (int i = 1; i < argc; ++i)
|
||||||
|
{
|
||||||
|
std::string raw = argv[i];
|
||||||
|
|
||||||
|
if (raw == "--")
|
||||||
|
terminated = true;
|
||||||
|
|
||||||
|
if (! terminated &&
|
||||||
|
raw.length () > 3 &&
|
||||||
|
raw.substr (0, 3) == "rc:")
|
||||||
|
{
|
||||||
|
rc = raw.substr (3);
|
||||||
|
|
||||||
|
home = ".";
|
||||||
|
std::string::size_type last_slash = rc._data.rfind ("/");
|
||||||
|
if (last_slash != std::string::npos)
|
||||||
|
home = rc.parent ();
|
||||||
|
|
||||||
|
context.header (format (STRING_PARSER_ALTERNATE_RC, rc._data));
|
||||||
|
|
||||||
|
// Keep looping, because if there are multiple rc:file arguments, the last
|
||||||
|
// one should dominate.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Look for CONFIG data.location and initialize a Path object.
|
||||||
|
void CLI::getDataLocation (int argc, const char** argv, Path& data)
|
||||||
|
{
|
||||||
|
std::string location = context.config.get ("data.location");
|
||||||
|
if (location != "")
|
||||||
|
data = location;
|
||||||
|
|
||||||
|
bool terminated = false;
|
||||||
|
for (int i = 1; i < argc; ++i)
|
||||||
|
{
|
||||||
|
std::string raw = argv[i];
|
||||||
|
|
||||||
|
if (raw == "--")
|
||||||
|
terminated = true;
|
||||||
|
|
||||||
|
if (! terminated &&
|
||||||
|
raw.length () > 17 &&
|
||||||
|
raw.substr (0, 16) == "rc.data.location")
|
||||||
|
{
|
||||||
|
data = Directory (raw.substr (17));
|
||||||
|
context.header (format (STRING_PARSER_ALTERNATE_DATA, (std::string) data));
|
||||||
|
|
||||||
|
// Keep looping, because if there are multiple rc:file arguments, the last
|
||||||
|
// one should dominate.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CLI::applyOverrides (int argc, const char** argv)
|
||||||
|
{
|
||||||
|
bool terminated = false;
|
||||||
|
for (int i = 1; i < argc; ++i)
|
||||||
|
{
|
||||||
|
std::string raw = argv[i];
|
||||||
|
|
||||||
|
if (raw == "--")
|
||||||
|
terminated = true;
|
||||||
|
|
||||||
|
if (! terminated &&
|
||||||
|
raw.length () > 3 &&
|
||||||
|
raw.substr (0, 3) == "rc.")
|
||||||
|
{
|
||||||
|
std::string::size_type sep = raw.find ('=', 3);
|
||||||
|
if (sep == std::string::npos)
|
||||||
|
sep = raw.find (':', 3);
|
||||||
|
if (sep != std::string::npos)
|
||||||
|
{
|
||||||
|
std::string name = raw.substr (3, sep - 3);
|
||||||
|
std::string value = raw.substr (sep + 1);
|
||||||
|
context.config.set (name, value);
|
||||||
|
context.footnote (format (STRING_PARSER_OVERRIDE_RC, name, value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
CLI::CLI ()
|
CLI::CLI ()
|
||||||
: _strict (false)
|
: _strict (false)
|
||||||
@@ -377,54 +466,6 @@ void CLI::applyOverrides ()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
void CLI::getOverride (std::string& home, File& rc)
|
|
||||||
{
|
|
||||||
std::vector <A>::const_iterator a;
|
|
||||||
for (a = _args.begin (); a != _args.end (); ++a)
|
|
||||||
{
|
|
||||||
if (a->hasTag ("RC"))
|
|
||||||
{
|
|
||||||
rc = File (a->attribute ("file"));
|
|
||||||
home = rc;
|
|
||||||
|
|
||||||
std::string::size_type last_slash = rc._data.rfind ("/");
|
|
||||||
if (last_slash != std::string::npos)
|
|
||||||
home = rc._data.substr (0, last_slash);
|
|
||||||
else
|
|
||||||
home = ".";
|
|
||||||
|
|
||||||
context.header (format (STRING_PARSER_ALTERNATE_RC, rc._data));
|
|
||||||
|
|
||||||
// Keep looping, because if there are multiple rc:file arguments, the last
|
|
||||||
// one should dominate.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Look for CONFIG data.location and initialize a Path object.
|
|
||||||
void CLI::getDataLocation (Path& data)
|
|
||||||
{
|
|
||||||
std::string location = context.config.get ("data.location");
|
|
||||||
if (location != "")
|
|
||||||
data = location;
|
|
||||||
|
|
||||||
std::vector <A>::const_iterator a;
|
|
||||||
for (a = _args.begin (); a != _args.end (); ++a)
|
|
||||||
{
|
|
||||||
if (a->hasTag ("CONFIG") &&
|
|
||||||
a->attribute ("name") == "data.location")
|
|
||||||
{
|
|
||||||
data = Directory (a->attribute ("value"));
|
|
||||||
context.header (format (STRING_PARSER_ALTERNATE_DATA, (std::string) data));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keep looping, because if there are multiple overrides, the last one
|
|
||||||
// should dominate.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Extract all the FILTER-tagged items.
|
// Extract all the FILTER-tagged items.
|
||||||
const std::string CLI::getFilter ()
|
const std::string CLI::getFilter ()
|
||||||
|
|||||||
@@ -65,6 +65,9 @@ class CLI
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static int minimumMatchLength;
|
static int minimumMatchLength;
|
||||||
|
static void getOverride (int, const char**, std::string&, File&);
|
||||||
|
static void getDataLocation (int, const char**, Path&);
|
||||||
|
static void applyOverrides (int, const char**);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CLI ();
|
CLI ();
|
||||||
@@ -75,8 +78,6 @@ public:
|
|||||||
void add (const std::string&);
|
void add (const std::string&);
|
||||||
void analyze (bool parse = true, bool strict = false);
|
void analyze (bool parse = true, bool strict = false);
|
||||||
void applyOverrides ();
|
void applyOverrides ();
|
||||||
void getOverride (std::string&, File&);
|
|
||||||
void getDataLocation (Path&);
|
|
||||||
const std::string getFilter ();
|
const std::string getFilter ();
|
||||||
const std::vector <std::string> getWords ();
|
const std::vector <std::string> getWords ();
|
||||||
bool canonicalize (std::string&, const std::string&, const std::string&) const;
|
bool canonicalize (std::string&, const std::string&, const std::string&) const;
|
||||||
|
|||||||
169
src/Context.cpp
169
src/Context.cpp
@@ -94,8 +94,8 @@ static const char* attributeNames[] =
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
Context::Context ()
|
Context::Context ()
|
||||||
: rc_file ()
|
: rc_file ("~/.taskrc")
|
||||||
, data_dir ()
|
, data_dir ("~/.task")
|
||||||
, config ()
|
, config ()
|
||||||
, tdb2 ()
|
, tdb2 ()
|
||||||
, dom ()
|
, dom ()
|
||||||
@@ -127,17 +127,19 @@ int Context::initialize (int argc, const char** argv)
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Assume default .taskrc and .task locations.
|
////////////////////////////////////////////////////////////////////////////
|
||||||
assumeLocations ();
|
//
|
||||||
|
// [1] Load the correct config file.
|
||||||
|
// - Default to ~/.taskrc (ctor).
|
||||||
|
// - Allow command line override rc:<file>
|
||||||
|
// - Allow $TASKRC override.
|
||||||
|
// - Load resultant file.
|
||||||
|
// - Apply command line overrides to the config.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// The CLI parser needs all the help it can get.
|
CLI::getOverride (argc, argv, home_dir, rc_file);
|
||||||
setupEntities ();
|
|
||||||
|
|
||||||
// Scan command line for 'rc:<file>' only.
|
|
||||||
cli.initialize (argc, argv); // task arg0 arg1 ...
|
|
||||||
cli.getOverride (home_dir, rc_file); // <-- <file>
|
|
||||||
|
|
||||||
// TASKRC environment variable overrides the command line.
|
|
||||||
char* override = getenv ("TASKRC");
|
char* override = getenv ("TASKRC");
|
||||||
if (override)
|
if (override)
|
||||||
{
|
{
|
||||||
@@ -145,21 +147,22 @@ int Context::initialize (int argc, const char** argv)
|
|||||||
header (format (STRING_CONTEXT_RC_OVERRIDE, rc_file._data));
|
header (format (STRING_CONTEXT_RC_OVERRIDE, rc_file._data));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dump any existing values and load rc file.
|
|
||||||
config.clear ();
|
config.clear ();
|
||||||
config.load (rc_file);
|
config.load (rc_file);
|
||||||
loadAliases ();
|
CLI::applyOverrides (argc, argv);
|
||||||
|
|
||||||
// These are useful for parsing.
|
////////////////////////////////////////////////////////////////////////////
|
||||||
Lexer::dateFormat = config.get ("dateformat");
|
//
|
||||||
Variant::dateFormat = config.get ("dateformat");
|
// [2] Locate the data directory.
|
||||||
Variant::searchCaseSensitive = config.getBoolean ("search.case.sensitive");
|
// - Default to ~/.task (ctor).
|
||||||
Variant::searchUsingRegex = config.getBoolean ("regex");
|
// - Allow command line override rc.data.location:<dir>
|
||||||
|
// - Allow $TASKDATA override.
|
||||||
|
// - Inform TDB2 where to find data.
|
||||||
|
// - Create the rc_file and data_dir, if necessary.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// The data location, Context::data_dir, is determined from the assumed
|
CLI::getDataLocation (argc, argv, data_dir);
|
||||||
// location (~/.task), or set by data.location in the config file, or
|
|
||||||
// overridden by rc.data.location on the command line.
|
|
||||||
cli.getDataLocation (data_dir); // <-- rc.data.location=<location>
|
|
||||||
|
|
||||||
override = getenv ("TASKDATA");
|
override = getenv ("TASKDATA");
|
||||||
if (override)
|
if (override)
|
||||||
@@ -169,51 +172,81 @@ int Context::initialize (int argc, const char** argv)
|
|||||||
header (format (STRING_CONTEXT_DATA_OVERRIDE, data_dir._data));
|
header (format (STRING_CONTEXT_DATA_OVERRIDE, data_dir._data));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create missing config file and data directory, if necessary.
|
tdb2.set_location (data_dir);
|
||||||
cli.applyOverrides ();
|
|
||||||
|
|
||||||
// Setting the debug switch has ripple effects.
|
|
||||||
propagateDebug ();
|
|
||||||
|
|
||||||
// These may have changed, so reapply.
|
|
||||||
Lexer::dateFormat = config.get ("dateformat");
|
|
||||||
Variant::dateFormat = config.get ("dateformat");
|
|
||||||
Variant::searchCaseSensitive = config.getBoolean ("search.case.sensitive");
|
|
||||||
Variant::searchUsingRegex = config.getBoolean ("regex");
|
|
||||||
|
|
||||||
createDefaultConfig ();
|
createDefaultConfig ();
|
||||||
|
|
||||||
// Initialize the color rules, if necessary.
|
////////////////////////////////////////////////////////////////////////////
|
||||||
if (color ())
|
//
|
||||||
initializeColorRules ();
|
// [3] Instantiate Command objects and capture entities.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Instantiate built-in command objects.
|
|
||||||
Command::factory (commands);
|
Command::factory (commands);
|
||||||
std::map <std::string, Command*>::iterator cmd;
|
std::map <std::string, Command*>::iterator cmd;
|
||||||
for (cmd = commands.begin (); cmd != commands.end (); ++cmd)
|
for (cmd = commands.begin (); cmd != commands.end (); ++cmd)
|
||||||
{
|
{
|
||||||
cli.entity ("cmd", cmd->first);
|
cli.entity ("cmd", cmd->first);
|
||||||
|
cli.entity ((cmd->second->read_only () ? "readcmd" : "writecmd"), cmd->first);
|
||||||
|
|
||||||
if (cmd->first[0] == '_')
|
if (cmd->first[0] == '_')
|
||||||
cli.entity ("helper", cmd->first);
|
cli.entity ("helper", cmd->first);
|
||||||
|
|
||||||
cli.entity ((cmd->second->read_only () ? "readcmd" : "writecmd"), cmd->first);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Instantiate built-in column objects.
|
////////////////////////////////////////////////////////////////////////////
|
||||||
Column::factory (columns);
|
//
|
||||||
|
// [4] Instantiate Column objects and capture entities.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Extend the fixed list of attribute names with any dynamic ones.
|
Column::factory (columns);
|
||||||
std::map <std::string, Column*>::iterator col;
|
std::map <std::string, Column*>::iterator col;
|
||||||
for (col = columns.begin (); col != columns.end (); ++col)
|
for (col = columns.begin (); col != columns.end (); ++col)
|
||||||
cli.entity ("attribute", col->first);
|
cli.entity ("attribute", col->first);
|
||||||
|
|
||||||
staticInitialization (); // Decouple code from Context.
|
cli.entity ("pseudo", "limit");
|
||||||
cli.analyze (true, true); // Parse all elements, strict mode.
|
|
||||||
|
|
||||||
tdb2.set_location (data_dir); // Prepare the task database.
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// [5] Capture modifier and operator entities.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < NUM_MODIFIER_NAMES; ++i)
|
||||||
|
cli.entity ("modifier", modifierNames[i]);
|
||||||
|
|
||||||
|
std::vector <std::string> operators;
|
||||||
|
Eval::getOperators (operators);
|
||||||
|
std::vector <std::string>::iterator op;
|
||||||
|
for (op = operators.begin (); op != operators.end (); ++op)
|
||||||
|
cli.entity ("operator", *op);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// [6] Complete the Context initialization.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
initializeColorRules ();
|
||||||
|
staticInitialization ();
|
||||||
|
propagateDebug ();
|
||||||
|
loadAliases ();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// [7] Parse the command line.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Scan command line for 'rc:<file>' only.
|
||||||
|
cli.initialize (argc, argv);
|
||||||
|
cli.analyze (true, true);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// [8] Run on.launch hooks.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// First opportunity to run a hook script.
|
|
||||||
hooks.initialize ();
|
hooks.initialize ();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -589,8 +622,10 @@ void Context::staticInitialization ()
|
|||||||
Task::defaultProject = config.get ("default.project");
|
Task::defaultProject = config.get ("default.project");
|
||||||
Task::defaultPriority = config.get ("default.priority");
|
Task::defaultPriority = config.get ("default.priority");
|
||||||
Task::defaultDue = config.get ("default.due");
|
Task::defaultDue = config.get ("default.due");
|
||||||
Task::searchCaseSensitive = config.getBoolean ("search.case.sensitive");
|
|
||||||
Task::regex = config.getBoolean ("regex");
|
Task::searchCaseSensitive = Variant::searchCaseSensitive = config.getBoolean ("search.case.sensitive");
|
||||||
|
Task::regex = Variant::searchUsingRegex = config.getBoolean ("regex");
|
||||||
|
Lexer::dateFormat = Variant::dateFormat = config.get ("dateformat");
|
||||||
|
|
||||||
std::map <std::string, Column*>::iterator i;
|
std::map <std::string, Column*>::iterator i;
|
||||||
for (i = columns.begin (); i != columns.end (); ++i)
|
for (i = columns.begin (); i != columns.end (); ++i)
|
||||||
@@ -614,47 +649,11 @@ void Context::staticInitialization ()
|
|||||||
// Tag- and project-specific coefficients.
|
// Tag- and project-specific coefficients.
|
||||||
std::vector <std::string> all;
|
std::vector <std::string> all;
|
||||||
config.all (all);
|
config.all (all);
|
||||||
|
|
||||||
std::vector <std::string>::iterator var;
|
std::vector <std::string>::iterator var;
|
||||||
for (var = all.begin (); var != all.end (); ++var)
|
for (var = all.begin (); var != all.end (); ++var)
|
||||||
{
|
|
||||||
if (var->substr (0, 13) == "urgency.user." ||
|
if (var->substr (0, 13) == "urgency.user." ||
|
||||||
var->substr (0, 12) == "urgency.uda.")
|
var->substr (0, 12) == "urgency.uda.")
|
||||||
Task::coefficients[*var] = config.getReal (*var);
|
Task::coefficients[*var] = config.getReal (*var);
|
||||||
}
|
|
||||||
|
|
||||||
Lexer::dateFormat = config.get ("dateformat");
|
|
||||||
Variant::dateFormat = config.get ("dateformat");
|
|
||||||
Variant::searchCaseSensitive = config.getBoolean ("search.case.sensitive");
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
void Context::assumeLocations ()
|
|
||||||
{
|
|
||||||
rc_file = File ("~/.taskrc");
|
|
||||||
data_dir = Directory ("~/.task");
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
void Context::setupEntities ()
|
|
||||||
{
|
|
||||||
// Entities: Pseudo-attributes. Hard-coded.
|
|
||||||
cli.entity ("pseudo", "limit");
|
|
||||||
|
|
||||||
// Entities: Attributes.
|
|
||||||
for (unsigned int i = 0; i < NUM_ATTRIBUTE_NAMES; ++i)
|
|
||||||
cli.entity ("attribute", attributeNames[i]);
|
|
||||||
|
|
||||||
// Entities: Modifiers.
|
|
||||||
for (unsigned int i = 0; i < NUM_MODIFIER_NAMES; ++i)
|
|
||||||
cli.entity ("modifier", modifierNames[i]);
|
|
||||||
|
|
||||||
// Entities: Operators.
|
|
||||||
std::vector <std::string> operators;
|
|
||||||
Eval::getOperators (operators);
|
|
||||||
std::vector <std::string>::iterator op;
|
|
||||||
for (op = operators.begin (); op != operators.end (); ++op)
|
|
||||||
cli.entity ("operator", *op);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
@@ -74,8 +74,6 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void staticInitialization ();
|
void staticInitialization ();
|
||||||
void assumeLocations ();
|
|
||||||
void setupEntities ();
|
|
||||||
void createDefaultConfig ();
|
void createDefaultConfig ();
|
||||||
void updateXtermTitle ();
|
void updateXtermTitle ();
|
||||||
void updateVerbosity ();
|
void updateVerbosity ();
|
||||||
|
|||||||
@@ -41,6 +41,10 @@ static Date now;
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
void initializeColorRules ()
|
void initializeColorRules ()
|
||||||
{
|
{
|
||||||
|
// If color is not enable/supported, short circuit.
|
||||||
|
if (! context.color ())
|
||||||
|
return;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
gsColor.clear ();
|
gsColor.clear ();
|
||||||
|
|||||||
@@ -51,8 +51,8 @@ qx{../src/task rc:$rc add 'baz (qux)' 2>&1};
|
|||||||
|
|
||||||
my $output = qx{../src/task rc:$rc ls 2>&1};
|
my $output = qx{../src/task rc:$rc ls 2>&1};
|
||||||
like ($output, qr/foo's bar\./, "$ut: foo's bar. --> preserved");
|
like ($output, qr/foo's bar\./, "$ut: foo's bar. --> preserved");
|
||||||
like ($output, qr/foo \(bar\)/, "$ut: foo \(bar\) -- preserved");
|
like ($output, qr/foo \(bar\)/, "$ut: foo \(bar\) --> preserved");
|
||||||
like ($output, qr/baz \(qux\)/, "$ut: baz \(qux\) -- preserved");
|
like ($output, qr/baz \(qux\)/, "$ut: baz \(qux\) --> preserved");
|
||||||
|
|
||||||
# Cleanup.
|
# Cleanup.
|
||||||
unlink qw(pending.data completed.data undo.data backlog.data), $rc;
|
unlink qw(pending.data completed.data undo.data backlog.data), $rc;
|
||||||
|
|||||||
Reference in New Issue
Block a user