diff --git a/ChangeLog b/ChangeLog index 10f9b45c1..bcf84f960 100644 --- a/ChangeLog +++ b/ChangeLog @@ -26,6 +26,9 @@ information. + The 'config' command now complains about use of deprecated color names in your .taskrc file. + + Added feature #296, that allows the 'config' command to modify your .taskrc + settings directly, with the command 'task config ', or + 'task config ' to remove the setting. + Task now supports nested .taskrc files using the "include /path" directive. + The 'entry', 'start' and 'end' columns now have equivalents that include the time, and are called 'entry_time', 'start_time', and 'end_time', for use in diff --git a/doc/man/task.1 b/doc/man/task.1 index ef639bd5c..065c2c8d9 100644 --- a/doc/man/task.1 +++ b/doc/man/task.1 @@ -129,8 +129,22 @@ Displays all possible colors, or a sample. Shows the task version number .TP -.B config -Shows the current settings in the task configuration file. +.B config [name [value | '']] +Shows the current settings in the task configuration file. Also supports +directly modifying the .taskrc file. This command either modifies +the 'name' setting with a new value of 'value', or adds a new entry that +is equivalent to 'name=value': + + task config name value + +This command sets a blank value. This has the effect of suppressing any +default value: + + task config name '' + +Finally, this command removes any 'name=...' entry from the .taskrc file: + + task config name .TP .B help @@ -157,9 +171,13 @@ Shows all tasks matching the specified criteria that are completed. .TP -.B ls [tags] [attrs] [description] +.B minimal [tags] [attrs] [description] Provides a minimal listing of tasks with specified criteria. +.TP +.B ls [tags] [attrs] [description] +Provides a short listing of tasks with specified criteria. + .TP .B list [tags] [attrs] [description] Provides a more detailed listing of tasks with specified criteria. diff --git a/src/Config.cpp b/src/Config.cpp index cefde2359..6d4a2e0b2 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -271,7 +271,10 @@ void Config::load (const std::string& file, int nest /* = 1 */) // First time in, load the default values. if (nest == 1) + { setDefaults (); + original_file = File (file); + } // Read the file, then parse the contents. std::string contents; diff --git a/src/Config.h b/src/Config.h index 866ee5450..925b72c21 100644 --- a/src/Config.h +++ b/src/Config.h @@ -30,6 +30,7 @@ #include #include #include +#include "File.h" class Config : public std::map { @@ -60,6 +61,9 @@ public: std::string checkForDeprecatedColor (); +public: + File original_file; + private: static std::string defaults; }; diff --git a/src/command.cpp b/src/command.cpp index e4737dafa..cfadb7a36 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -505,6 +505,101 @@ int handleConfig (std::string &outs) { int rc = 0; std::stringstream out; + + // Support: + // task config name value # set name to value + // task config name "" # set name to blank + // task config name # remove name + if (context.args.size () >= 2) + { + std::string name = context.args[1]; + std::string value = ""; + + if (context.args.size () >= 3) + value = context.args[2]; + + if (name != "") + { + bool change = false; + + // Read .taskrc (or equivalent) + std::string contents; + File::read (context.config.original_file, contents); + + // task config name value + // task config name "" + if (context.args.size () >= 3) + { + // Find existing entry & overwrite + std::string::size_type pos = contents.find (name + "="); + if (pos != std::string::npos) + { + std::string::size_type eol = contents.find_first_of ("\r\f\n", pos); + if (eol == std::string::npos) + throw std::string ("Cannot find EOL after entry '") + name + "'"; + + if (confirm (std::string ("Are you sure you want to overwrite the value of '") + name + "' with '" + value + "'?")) + { + contents = contents.substr (0, pos) + + name + "=" + value + + contents.substr (eol); + change = true; + } + } + + // Not found, so append instead. + else + { + if (confirm (std::string ("Are you sure you want to add '") + name + "' with a value of '" + value + "'?")) + { + contents = contents + + "\n" + + name + "=" + value + + "\n"; + change = true; + } + } + } + + // task config name + else + { + // Remove name + std::string::size_type pos = contents.find (name + "="); + if (pos == std::string::npos) + throw std::string ("No entry named '") + name + "' found"; + + std::string::size_type eol = contents.find_first_of ("\r\f\n", pos); + if (eol == std::string::npos) + throw std::string ("Cannot find EOL after entry '") + name + "'"; + + if (confirm (std::string ("Are you sure you want to remove '") + name + "'?")) + { + contents = contents.substr (0, pos) + contents.substr (eol + 1); + change = true; + } + } + + // Write .taskrc (or equivalent) + if (change) + { + File::write (context.config.original_file, contents); + out << "Config file " + << context.config.original_file.data + << " modified." + << std::endl; + } + else + out << "No changes made." << std::endl; + } + else + throw std::string ("Specify the name of a config variable to modify."); + + outs = out.str (); + return rc; + } + + // No arguments - display config values instead. int width = context.getWidth (); std::vector all; @@ -534,12 +629,9 @@ int handleConfig (std::string &outs) foreach (i, all) { std::string value = context.config.get (*i); - if (value != "") - { - int row = table.addRow (); - table.addCell (row, 0, *i); - table.addCell (row, 1, value); - } + int row = table.addRow (); + table.addCell (row, 0, *i); + table.addCell (row, 1, value); } Color bold ("bold"); diff --git a/src/report.cpp b/src/report.cpp index 1333d5cec..69708aa15 100644 --- a/src/report.cpp +++ b/src/report.cpp @@ -187,8 +187,8 @@ int shortUsage (std::string &outs) table.addCell (row, 2, "Shows the task version number."); row = table.addRow (); - table.addCell (row, 1, "task config"); - table.addCell (row, 2, "Shows the task configuration."); + table.addCell (row, 1, "task config [name [value | '']]"); + table.addCell (row, 2, "Shows the task configuration, or can add, modify and remove settings."); row = table.addRow (); table.addCell (row, 1, "task help"); diff --git a/src/tests/rc.t b/src/tests/rc.t index 9b05079e4..38faee75b 100755 --- a/src/tests/rc.t +++ b/src/tests/rc.t @@ -29,7 +29,7 @@ use strict; use warnings; use File::Path; -use Test::More tests => 8; +use Test::More tests => 12; # Create the rc file, using rc.name:value. unlink 'foo.rc'; @@ -51,6 +51,23 @@ qx{echo 'y'|../task rc:foo.rc rc.data.location:foo}; ok (-r 'foo.rc', 'Created default rc file'); ok (-d 'foo', 'Created default data directory'); +# Add a setting. +qx{echo 'y'|../task rc:foo.rc config must_be_unique old}; +my $output = qx{../task rc:foo.rc config}; +like ($output, qr/^must_be_unique\s+old$/ms, 'config setting a new value'); + +qx{echo 'y'|../task rc:foo.rc config must_be_unique new}; +$output = qx{../task rc:foo.rc config}; +like ($output, qr/^must_be_unique\s+new$/ms, 'config overwriting an existing value'); + +qx{echo 'y'|../task rc:foo.rc config must_be_unique ''}; +$output = qx{../task rc:foo.rc config}; +like ($output, qr/^must_be_unique$/ms, 'config setting a blank value'); + +qx{echo 'y'|../task rc:foo.rc config must_be_unique}; +$output = qx{../task rc:foo.rc config}; +unlike ($output, qr/^must_be_unique/ms, 'config removing a value'); + rmtree 'foo', 0, 0; ok (!-r 'foo', 'Removed foo');