diff --git a/src/CLI.cpp b/src/CLI.cpp
index 87e5beb58..f6b03f9da 100644
--- a/src/CLI.cpp
+++ b/src/CLI.cpp
@@ -217,6 +217,95 @@ const std::string A::dump () const
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 ()
: _strict (false)
@@ -377,54 +466,6 @@ void CLI::applyOverrides ()
}
}
-////////////////////////////////////////////////////////////////////////////////
-void CLI::getOverride (std::string& home, File& rc)
-{
- std::vector ::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 ::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.
const std::string CLI::getFilter ()
diff --git a/src/CLI.h b/src/CLI.h
index 9478f26c3..f6461ab85 100644
--- a/src/CLI.h
+++ b/src/CLI.h
@@ -65,6 +65,9 @@ class CLI
{
public:
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:
CLI ();
@@ -75,8 +78,6 @@ public:
void add (const std::string&);
void analyze (bool parse = true, bool strict = false);
void applyOverrides ();
- void getOverride (std::string&, File&);
- void getDataLocation (Path&);
const std::string getFilter ();
const std::vector getWords ();
bool canonicalize (std::string&, const std::string&, const std::string&) const;
diff --git a/src/Context.cpp b/src/Context.cpp
index 76ab6e172..2ed260817 100644
--- a/src/Context.cpp
+++ b/src/Context.cpp
@@ -94,8 +94,8 @@ static const char* attributeNames[] =
////////////////////////////////////////////////////////////////////////////////
Context::Context ()
-: rc_file ()
-, data_dir ()
+: rc_file ("~/.taskrc")
+, data_dir ("~/.task")
, config ()
, tdb2 ()
, dom ()
@@ -127,17 +127,19 @@ int Context::initialize (int argc, const char** argv)
try
{
- // Assume default .taskrc and .task locations.
- assumeLocations ();
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // [1] Load the correct config file.
+ // - Default to ~/.taskrc (ctor).
+ // - Allow command line override rc:
+ // - Allow $TASKRC override.
+ // - Load resultant file.
+ // - Apply command line overrides to the config.
+ //
+ ////////////////////////////////////////////////////////////////////////////
- // The CLI parser needs all the help it can get.
- setupEntities ();
+ CLI::getOverride (argc, argv, home_dir, rc_file);
- // Scan command line for 'rc:' only.
- cli.initialize (argc, argv); // task arg0 arg1 ...
- cli.getOverride (home_dir, rc_file); // <--
-
- // TASKRC environment variable overrides the command line.
char* override = getenv ("TASKRC");
if (override)
{
@@ -145,21 +147,22 @@ int Context::initialize (int argc, const char** argv)
header (format (STRING_CONTEXT_RC_OVERRIDE, rc_file._data));
}
- // Dump any existing values and load rc file.
config.clear ();
config.load (rc_file);
- loadAliases ();
+ CLI::applyOverrides (argc, argv);
- // These are useful for parsing.
- Lexer::dateFormat = config.get ("dateformat");
- Variant::dateFormat = config.get ("dateformat");
- Variant::searchCaseSensitive = config.getBoolean ("search.case.sensitive");
- Variant::searchUsingRegex = config.getBoolean ("regex");
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // [2] Locate the data directory.
+ // - Default to ~/.task (ctor).
+ // - Allow command line override rc.data.location:
+ // - 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
- // 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=
+ CLI::getDataLocation (argc, argv, data_dir);
override = getenv ("TASKDATA");
if (override)
@@ -169,51 +172,81 @@ int Context::initialize (int argc, const char** argv)
header (format (STRING_CONTEXT_DATA_OVERRIDE, data_dir._data));
}
- // Create missing config file and data directory, if necessary.
- 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");
-
+ tdb2.set_location (data_dir);
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);
std::map ::iterator cmd;
for (cmd = commands.begin (); cmd != commands.end (); ++cmd)
{
cli.entity ("cmd", cmd->first);
+ cli.entity ((cmd->second->read_only () ? "readcmd" : "writecmd"), cmd->first);
if (cmd->first[0] == '_')
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 ::iterator col;
for (col = columns.begin (); col != columns.end (); ++col)
cli.entity ("attribute", col->first);
- staticInitialization (); // Decouple code from Context.
- cli.analyze (true, true); // Parse all elements, strict mode.
+ cli.entity ("pseudo", "limit");
- 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 operators;
+ Eval::getOperators (operators);
+ std::vector ::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:' only.
+ cli.initialize (argc, argv);
+ cli.analyze (true, true);
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // [8] Run on.launch hooks.
+ //
+ ////////////////////////////////////////////////////////////////////////////
- // First opportunity to run a hook script.
hooks.initialize ();
}
@@ -589,8 +622,10 @@ void Context::staticInitialization ()
Task::defaultProject = config.get ("default.project");
Task::defaultPriority = config.get ("default.priority");
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 ::iterator i;
for (i = columns.begin (); i != columns.end (); ++i)
@@ -614,47 +649,11 @@ void Context::staticInitialization ()
// Tag- and project-specific coefficients.
std::vector all;
config.all (all);
-
std::vector ::iterator var;
for (var = all.begin (); var != all.end (); ++var)
- {
if (var->substr (0, 13) == "urgency.user." ||
var->substr (0, 12) == "urgency.uda.")
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 operators;
- Eval::getOperators (operators);
- std::vector ::iterator op;
- for (op = operators.begin (); op != operators.end (); ++op)
- cli.entity ("operator", *op);
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/src/Context.h b/src/Context.h
index 0d1fd5c72..f9c608ab0 100644
--- a/src/Context.h
+++ b/src/Context.h
@@ -74,8 +74,6 @@ public:
private:
void staticInitialization ();
- void assumeLocations ();
- void setupEntities ();
void createDefaultConfig ();
void updateXtermTitle ();
void updateVerbosity ();
diff --git a/src/rules.cpp b/src/rules.cpp
index 14ab1942c..baa6e950d 100644
--- a/src/rules.cpp
+++ b/src/rules.cpp
@@ -41,6 +41,10 @@ static Date now;
////////////////////////////////////////////////////////////////////////////////
void initializeColorRules ()
{
+ // If color is not enable/supported, short circuit.
+ if (! context.color ())
+ return;
+
try
{
gsColor.clear ();
diff --git a/test/bug.819.t b/test/bug.819.t
index 256bf494c..320426235 100755
--- a/test/bug.819.t
+++ b/test/bug.819.t
@@ -51,8 +51,8 @@ qx{../src/task rc:$rc add 'baz (qux)' 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 \(bar\)/, "$ut: foo \(bar\) -- preserved");
-like ($output, qr/baz \(qux\)/, "$ut: baz \(qux\) -- preserved");
+like ($output, qr/foo \(bar\)/, "$ut: foo \(bar\) --> preserved");
+like ($output, qr/baz \(qux\)/, "$ut: baz \(qux\) --> preserved");
# Cleanup.
unlink qw(pending.data completed.data undo.data backlog.data), $rc;