mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-06-26 10:54:26 +02:00
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:
parent
93a68361a7
commit
fab37d3383
13 changed files with 142 additions and 9 deletions
1
AUTHORS
1
AUTHORS
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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") ||
|
||||||
|
|
|
@ -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 ();
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -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 ();
|
||||||
|
|
|
@ -168,3 +168,11 @@ void Subst::apply (
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void Subst::clear ()
|
||||||
|
{
|
||||||
|
mFrom = "";
|
||||||
|
mTo = "";
|
||||||
|
mGlobal = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 ();
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -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 ()
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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&);
|
||||||
|
|
|
@ -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.");
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue