Enhancment - interactive shell

- At the request of several, and the great example of John Florian,
  task has an interactive shell.
This commit is contained in:
Paul Beckingham 2009-06-21 08:39:53 -04:00
parent 93a68361a7
commit fab37d3383
13 changed files with 142 additions and 9 deletions

View file

@ -20,6 +20,7 @@ Contributing Authors:
P.C. Shyamshankar P.C. Shyamshankar
Johan Friis Johan Friis
Steven de Brouwer Steven de Brouwer
John Florian
With thanks to: With thanks to:
Eugene Kramer Eugene Kramer

View file

@ -57,6 +57,7 @@
226 undelete 226 undelete
227 undo 227 undo
228 version 228 version
229 shell
# 3xx Attributes - must be sequential # 3xx Attributes - must be sequential
300 project 300 project

View file

@ -32,6 +32,7 @@
#include "util.h" #include "util.h"
#include "text.h" #include "text.h"
#include "i18n.h" #include "i18n.h"
#include "main.h"
extern Context context; extern Context context;
@ -124,6 +125,9 @@ void Cmd::load ()
commands.push_back (context.stringtable.get (CMD_INFO, "info")); commands.push_back (context.stringtable.get (CMD_INFO, "info"));
commands.push_back (context.stringtable.get (CMD_NEXT, "next")); commands.push_back (context.stringtable.get (CMD_NEXT, "next"));
commands.push_back (context.stringtable.get (CMD_PROJECTS, "projects")); commands.push_back (context.stringtable.get (CMD_PROJECTS, "projects"));
#ifdef FEATURE_SHELL
commands.push_back (context.stringtable.get (CMD_SHELL, "shell"));
#endif
commands.push_back (context.stringtable.get (CMD_START, "start")); commands.push_back (context.stringtable.get (CMD_START, "start"));
commands.push_back (context.stringtable.get (CMD_STATS, "stats")); 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_STOP, "stop"));
@ -207,6 +211,7 @@ bool Cmd::isReadOnlyCommand ()
command == context.stringtable.get (CMD_INFO, "info") || command == context.stringtable.get (CMD_INFO, "info") ||
command == context.stringtable.get (CMD_NEXT, "next") || command == context.stringtable.get (CMD_NEXT, "next") ||
command == context.stringtable.get (CMD_PROJECTS, "projects") || command == context.stringtable.get (CMD_PROJECTS, "projects") ||
command == context.stringtable.get (CMD_SHELL, "shell") ||
command == context.stringtable.get (CMD_STATS, "stats") || command == context.stringtable.get (CMD_STATS, "stats") ||
command == context.stringtable.get (CMD_SUMMARY, "summary") || command == context.stringtable.get (CMD_SUMMARY, "summary") ||
command == context.stringtable.get (CMD_TAGS, "tags") || command == context.stringtable.get (CMD_TAGS, "tags") ||

View file

@ -67,13 +67,6 @@ Context::~Context ()
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void Context::initialize (int argc, char** argv) void Context::initialize (int argc, char** argv)
{ {
// Set up randomness.
#ifdef HAVE_SRANDOM
srandom (time (NULL));
#else
srand (time (NULL));
#endif
// Capture the args. // Capture the args.
for (int i = 0; i < argc; ++i) for (int i = 0; i < argc; ++i)
if (i == 0) if (i == 0)
@ -87,6 +80,13 @@ void Context::initialize (int argc, char** argv)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void Context::initialize () void Context::initialize ()
{ {
// Set up randomness.
#ifdef HAVE_SRANDOM
srandom (time (NULL));
#else
srand (time (NULL));
#endif
// Load the configuration file from the home directory. If the file cannot // Load the configuration file from the home directory. If the file cannot
// be found, offer to create a sample one. // be found, offer to create a sample one.
loadCorrectConfigFile (); loadCorrectConfigFile ();
@ -205,6 +205,9 @@ std::string Context::dispatch ()
else if (cmd.command == "import") { out = handleImport (); } else if (cmd.command == "import") { out = handleImport (); }
else if (cmd.command == "duplicate") { out = handleDuplicate (); } else if (cmd.command == "duplicate") { out = handleDuplicate (); }
else if (cmd.command == "edit") { out = handleEdit (); } else if (cmd.command == "edit") { out = handleEdit (); }
#ifdef FEATURE_SHELL
else if (cmd.command == "shell") { handleShell (); }
#endif
else if (cmd.command == "" && else if (cmd.command == "" &&
sequence.size ()) { out = handleModify (); } sequence.size ()) { out = handleModify (); }
@ -533,6 +536,28 @@ void Context::parse (
} }
} }
////////////////////////////////////////////////////////////////////////////////
void Context::clear ()
{
// Config config;
filter.clear ();
// Keymap keymap;
sequence.clear ();
subst.clear ();
// task.clear ();
task = Task ();
tdb.clear ();
// stringtable.clear ();
program = "";
args.clear ();
cmd.command = "";
tagAdditions.clear ();
tagRemovals.clear ();
clearMessages ();
inShadow = false;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Add all the attributes in the task to the filter. All except uuid. // Add all the attributes in the task to the filter. All except uuid.
void Context::autoFilter (Task& t, Filter& f) void Context::autoFilter (Task& t, Filter& f)
@ -633,6 +658,7 @@ void Context::clearMessages ()
headers.clear (); headers.clear ();
messages.clear (); messages.clear ();
footnotes.clear (); footnotes.clear ();
debugMessages.clear ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View file

@ -60,6 +60,7 @@ public:
void parse (); void parse ();
void parse (std::vector <std::string>&, Cmd&, Task&, Sequence&, Subst&, Filter&); void parse (std::vector <std::string>&, Cmd&, Task&, Sequence&, Subst&, Filter&);
void clear ();
private: private:
void loadCorrectConfigFile (); void loadCorrectConfigFile ();

View file

@ -168,3 +168,11 @@ void Subst::apply (
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void Subst::clear ()
{
mFrom = "";
mTo = "";
mGlobal = false;
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -42,6 +42,7 @@ public:
bool valid (const std::string&) const; bool valid (const std::string&) const;
void parse (const std::string&); void parse (const std::string&);
void apply (std::string&, std::vector <Att>&) const; void apply (std::string&, std::vector <Att>&) const;
void clear ();
public: public:
std::string mFrom; std::string mFrom;

View file

@ -85,7 +85,6 @@ TDB::~TDB ()
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void TDB::clear () void TDB::clear ()
{ {
mPending.clear ();
mLocations.clear (); mLocations.clear ();
mLock = true; mLock = true;
@ -93,6 +92,10 @@ void TDB::clear ()
unlock (); unlock ();
mAllOpenAndLocked = false; mAllOpenAndLocked = false;
mId = 1;
mPending.clear ();
mNew.clear ();
mModified.clear ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View file

@ -38,6 +38,7 @@
#include "text.h" #include "text.h"
#include "util.h" #include "util.h"
#include "main.h" #include "main.h"
#include "../auto.h"
#ifdef HAVE_LIBNCURSES #ifdef HAVE_LIBNCURSES
#include <ncurses.h> #include <ncurses.h>
@ -394,6 +395,9 @@ std::string handleVersion ()
"defaultwidth displayweeknumber due echo.command locale locking " "defaultwidth displayweeknumber due echo.command locale locking "
"monthsperline nag next project shadow.command shadow.file shadow.notify " "monthsperline nag next project shadow.command shadow.file shadow.notify "
"weekstart editor import.synonym.id import.synonym.uuid " "weekstart editor import.synonym.id import.synonym.uuid "
#ifdef FEATURE_SHELL
"shell.prompt "
#endif
"import.synonym.status import.synonym.tags import.synonym.entry " "import.synonym.status import.synonym.tags import.synonym.entry "
"import.synonym.start import.synonym.due import.synonym.recur " "import.synonym.start import.synonym.due import.synonym.recur "
"import.synonym.end import.synonym.project import.synonym.priority " "import.synonym.end import.synonym.project import.synonym.priority "
@ -956,6 +960,79 @@ std::string handleDuplicate ()
return out.str (); return out.str ();
} }
////////////////////////////////////////////////////////////////////////////////
#ifdef FEATURE_SHELL
void handleShell ()
{
// Display some kind of welcome message.
std::cout << ((context.config.get ("color", true) || context.config.get (std::string ("_forcecolor"), false))
? Text::colorize (Text::bold, Text::nocolor, PACKAGE)
: PACKAGE)
<< " shell"
<< std::endl
<< std::endl
<< "Enter any task command (such as 'list'), or hit 'Enter'."
<< std::endl
<< "There is no need to include the 'task' command itself."
<< std::endl
<< std::endl;
// Preserve any special override arguments, and reapply them for each
// shell command.
std::vector <std::string> special;
foreach (arg, context.args)
if (arg->substr (0, 3) == "rc." ||
arg->substr (0, 3) == "rc:")
special.push_back (*arg);
std::string quit = "quit"; // TODO i18n
std::string command;
bool keepGoing = true;
do
{
std::cout << context.config.get ("shell.prompt", "task>") << " ";
command = "";
std::getline (std::cin, command);
command = lowerCase (trim (command));
if (command.length () > 0 &&
command.length () <= quit.length () &&
command == quit.substr (0, command.length ()))
{
keepGoing = false;
}
else
{
try
{
context.clear ();
std::vector <std::string> args;
split (args, command, ' ');
foreach (arg, special) context.args.push_back (*arg);
foreach (arg, args) context.args.push_back (*arg);
context.initialize ();
context.run ();
}
catch (std::string& error)
{
std::cout << error << std::endl;
}
catch (...)
{
std::cerr << context.stringtable.get (100, "Unknown error.") << std::endl;
}
}
}
while (keepGoing);
}
#endif
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
std::string handleColor () std::string handleColor ()
{ {

View file

@ -93,6 +93,7 @@
#define CMD_UNDELETE 226 #define CMD_UNDELETE 226
#define CMD_UNDO 227 #define CMD_UNDO 227
#define CMD_VERSION 228 #define CMD_VERSION 228
#define CMD_SHELL 229
// 3xx Attributes // 3xx Attributes
#define ATT_PROJECT 300 #define ATT_PROJECT 300

View file

@ -27,6 +27,7 @@
#define FEATURE_TDB_OPT 1 // TDB Optimization reduces file I/O. #define FEATURE_TDB_OPT 1 // TDB Optimization reduces file I/O.
#define FEATURE_NEW_ID 1 // Echoes back new id. #define FEATURE_NEW_ID 1 // Echoes back new id.
#define FEATURE_SHELL 1 // Interactive shell.
#include <string> #include <string>
#include <vector> #include <vector>
@ -72,6 +73,9 @@ std::string handleUndo ();
std::string handleColor (); std::string handleColor ();
std::string handleAnnotate (); std::string handleAnnotate ();
std::string handleDuplicate (); std::string handleDuplicate ();
#ifdef FEATURE_SHELL
void handleShell ();
#endif
int deltaAppend (Task&); int deltaAppend (Task&);
int deltaDescription (Task&); int deltaDescription (Task&);
int deltaTags (Task&); int deltaTags (Task&);

View file

@ -99,6 +99,12 @@ std::string shortUsage ()
table.addCell (row, 1, "task edit ID"); table.addCell (row, 1, "task edit ID");
table.addCell (row, 2, "Launches an editor to let you modify all aspects of a task directly, therefore it is to be used carefully."); table.addCell (row, 2, "Launches an editor to let you modify all aspects of a task directly, therefore it is to be used carefully.");
#ifdef FEATURE_SHELL
row = table.addRow ();
table.addCell (row, 1, "task shell");
table.addCell (row, 2, "Launches an interactive shell.");
#endif
row = table.addRow (); row = table.addRow ();
table.addCell (row, 1, "task duplicate ID [tags] [attrs] [desc...]"); table.addCell (row, 1, "task duplicate ID [tags] [attrs] [desc...]");
table.addCell (row, 2, "Duplicates the specified task, and allows modifications."); table.addCell (row, 2, "Duplicates the specified task, and allows modifications.");

View file

@ -64,7 +64,6 @@ bool confirm (const std::string& question)
std::getline (std::cin, answer); std::getline (std::cin, answer);
answer = lowerCase (trim (answer)); answer = lowerCase (trim (answer));
if (answer == "\n") std::cout << "newline\n"; // TODO i18n
} }
while (answer != "y" && // TODO i18n while (answer != "y" && // TODO i18n
answer != "ye" && // TODO i18n answer != "ye" && // TODO i18n