mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-07-07 20:06:36 +02:00
- Supports ::isatty call to shut off color, ncurses when stdout is not to a tty
This commit is contained in:
parent
97b120de67
commit
79f6ef075e
4 changed files with 111 additions and 38 deletions
|
@ -19,6 +19,7 @@ represents a feature release, and the Z represents a patch.
|
||||||
+ Added ability to override ~/.taskrc with rc:<file>
|
+ Added ability to override ~/.taskrc with rc:<file>
|
||||||
+ Added bar chart history report "task ghistory"
|
+ Added bar chart history report "task ghistory"
|
||||||
+ Added task filtering on all reports
|
+ Added task filtering on all reports
|
||||||
|
+ Automatically shuts off color, curses when output is not a tty
|
||||||
+ Supports relative due: dates (tomorrow, wednesday, 23rd, eom ...)
|
+ Supports relative due: dates (tomorrow, wednesday, 23rd, eom ...)
|
||||||
+ Bug: Fixed where Esc[0m sequences were being emitted for no good reason
|
+ Bug: Fixed where Esc[0m sequences were being emitted for no good reason
|
||||||
+ Bug: Fixed underlined table headers when color is turned off
|
+ Bug: Fixed underlined table headers when color is turned off
|
||||||
|
|
|
@ -57,6 +57,7 @@
|
||||||
<li>Added support for relative due: dates, such as "tomorrow", "friday",
|
<li>Added support for relative due: dates, such as "tomorrow", "friday",
|
||||||
"23rd", "eom"
|
"23rd", "eom"
|
||||||
<li>Added support for task filtering on all reports
|
<li>Added support for task filtering on all reports
|
||||||
|
<li>Automatically shuts off color, ncurses when output is not to a tty
|
||||||
<li>Fixed bug where Esc[0m sequences were being emitted for no good reason
|
<li>Fixed bug where Esc[0m sequences were being emitted for no good reason
|
||||||
<li>Fixed bug where table headers are underlined when color is turned off
|
<li>Fixed bug where table headers are underlined when color is turned off
|
||||||
<li>Fixed bug where adding a blank priority resulted in an assigned garbage value
|
<li>Fixed bug where adding a blank priority resulted in an assigned garbage value
|
||||||
|
|
146
src/task.cpp
146
src/task.cpp
|
@ -28,6 +28,7 @@
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
|
@ -275,6 +276,13 @@ int main (int argc, char** argv)
|
||||||
Config conf;
|
Config conf;
|
||||||
loadConfFile (argc, argv, conf);
|
loadConfFile (argc, argv, conf);
|
||||||
|
|
||||||
|
// When redirecting output to a file, do not use color, curses.
|
||||||
|
if (!isatty (fileno (stdout)))
|
||||||
|
{
|
||||||
|
conf.set ("curses", "off");
|
||||||
|
conf.set ("color", "off");
|
||||||
|
}
|
||||||
|
|
||||||
TDB tdb;
|
TDB tdb;
|
||||||
tdb.dataDirectory (conf.get ("data.location"));
|
tdb.dataDirectory (conf.get ("data.location"));
|
||||||
|
|
||||||
|
@ -585,16 +593,19 @@ void handleList (const TDB& tdb, T& task, Config& conf)
|
||||||
// Now format the matching task.
|
// Now format the matching task.
|
||||||
bool imminent = false;
|
bool imminent = false;
|
||||||
bool overdue = false;
|
bool overdue = false;
|
||||||
Date now;
|
|
||||||
std::string due = refTask.getAttribute ("due");
|
std::string due = refTask.getAttribute ("due");
|
||||||
if (due.length ())
|
if (due.length ())
|
||||||
{
|
{
|
||||||
|
switch (getDueState (due))
|
||||||
|
{
|
||||||
|
case 2: overdue = true; break;
|
||||||
|
case 1: imminent = true; break;
|
||||||
|
case 0:
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
Date dt (::atoi (due.c_str ()));
|
Date dt (::atoi (due.c_str ()));
|
||||||
due = dt.toString (conf.get ("dateformat", "m/d/Y"));
|
due = dt.toString (conf.get ("dateformat", "m/d/Y"));
|
||||||
|
|
||||||
overdue = (dt < now) ? true : false;
|
|
||||||
Date nextweek = now + 7 * 86400;
|
|
||||||
imminent = dt < nextweek ? true : false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string active;
|
std::string active;
|
||||||
|
@ -605,6 +616,7 @@ void handleList (const TDB& tdb, T& task, Config& conf)
|
||||||
std::string created = refTask.getAttribute ("entry");
|
std::string created = refTask.getAttribute ("entry");
|
||||||
if (created.length ())
|
if (created.length ())
|
||||||
{
|
{
|
||||||
|
Date now;
|
||||||
Date dt (::atoi (created.c_str ()));
|
Date dt (::atoi (created.c_str ()));
|
||||||
formatTimeDeltaDays (age, (time_t) (now - dt));
|
formatTimeDeltaDays (age, (time_t) (now - dt));
|
||||||
}
|
}
|
||||||
|
@ -711,16 +723,19 @@ void handleSmallList (const TDB& tdb, T& task, Config& conf)
|
||||||
// Now format the matching task.
|
// Now format the matching task.
|
||||||
bool imminent = false;
|
bool imminent = false;
|
||||||
bool overdue = false;
|
bool overdue = false;
|
||||||
Date now;
|
|
||||||
std::string due = refTask.getAttribute ("due");
|
std::string due = refTask.getAttribute ("due");
|
||||||
if (due.length ())
|
if (due.length ())
|
||||||
{
|
{
|
||||||
|
switch (getDueState (due))
|
||||||
|
{
|
||||||
|
case 2: overdue = true; break;
|
||||||
|
case 1: imminent = true; break;
|
||||||
|
case 0:
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
Date dt (::atoi (due.c_str ()));
|
Date dt (::atoi (due.c_str ()));
|
||||||
due = dt.toString (conf.get ("dateformat", "m/d/Y"));
|
due = dt.toString (conf.get ("dateformat", "m/d/Y"));
|
||||||
|
|
||||||
overdue = (dt < now) ? true : false;
|
|
||||||
Date nextweek = now + 7 * 86400;
|
|
||||||
imminent = dt < nextweek ? true : false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string active;
|
std::string active;
|
||||||
|
@ -731,6 +746,7 @@ void handleSmallList (const TDB& tdb, T& task, Config& conf)
|
||||||
std::string created = refTask.getAttribute ("entry");
|
std::string created = refTask.getAttribute ("entry");
|
||||||
if (created.length ())
|
if (created.length ())
|
||||||
{
|
{
|
||||||
|
Date now;
|
||||||
Date dt (::atoi (created.c_str ()));
|
Date dt (::atoi (created.c_str ()));
|
||||||
formatTimeDeltaDays (age, (time_t) (now - dt));
|
formatTimeDeltaDays (age, (time_t) (now - dt));
|
||||||
}
|
}
|
||||||
|
@ -1165,12 +1181,16 @@ void handleLongList (const TDB& tdb, T& task, Config& conf)
|
||||||
std::string due = refTask.getAttribute ("due");
|
std::string due = refTask.getAttribute ("due");
|
||||||
if (due.length ())
|
if (due.length ())
|
||||||
{
|
{
|
||||||
|
switch (getDueState (due))
|
||||||
|
{
|
||||||
|
case 2: overdue = true; break;
|
||||||
|
case 1: imminent = true; break;
|
||||||
|
case 0:
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
Date dt (::atoi (due.c_str ()));
|
Date dt (::atoi (due.c_str ()));
|
||||||
due = dt.toString (conf.get ("dateformat", "m/d/Y"));
|
due = dt.toString (conf.get ("dateformat", "m/d/Y"));
|
||||||
|
|
||||||
overdue = (dt < now) ? true : false;
|
|
||||||
Date nextweek = now + 7 * 86400;
|
|
||||||
imminent = dt < nextweek ? true : false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string age;
|
std::string age;
|
||||||
|
@ -1475,20 +1495,24 @@ void handleReportNext (const TDB& tdb, T& task, Config& conf)
|
||||||
foreach (i, matching)
|
foreach (i, matching)
|
||||||
{
|
{
|
||||||
T refTask (pending[*i]);
|
T refTask (pending[*i]);
|
||||||
|
Date now;
|
||||||
|
|
||||||
// Now format the matching task.
|
// Now format the matching task.
|
||||||
bool imminent = false;
|
bool imminent = false;
|
||||||
bool overdue = false;
|
bool overdue = false;
|
||||||
Date now;
|
|
||||||
std::string due = refTask.getAttribute ("due");
|
std::string due = refTask.getAttribute ("due");
|
||||||
if (due.length ())
|
if (due.length ())
|
||||||
{
|
{
|
||||||
|
switch (getDueState (due))
|
||||||
|
{
|
||||||
|
case 2: overdue = true; break;
|
||||||
|
case 1: imminent = true; break;
|
||||||
|
case 0:
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
Date dt (::atoi (due.c_str ()));
|
Date dt (::atoi (due.c_str ()));
|
||||||
due = dt.toString (conf.get ("dateformat", "m/d/Y"));
|
due = dt.toString (conf.get ("dateformat", "m/d/Y"));
|
||||||
|
|
||||||
overdue = (dt < now) ? true : false;
|
|
||||||
Date nextweek = now + 7 * 86400;
|
|
||||||
imminent = dt < nextweek ? true : false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string active;
|
std::string active;
|
||||||
|
@ -1932,8 +1956,8 @@ void handleReportGHistory (const TDB& tdb, T& task, Config& conf)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::string aBar = ""; while (aBar.length () < addedBar) aBar += "+";
|
std::string aBar = ""; while (aBar.length () < addedBar) aBar += "+";
|
||||||
std::string cBar = ""; while (cBar.length () < completedBar) cBar += "+";
|
std::string cBar = ""; while (cBar.length () < completedBar) cBar += "X";
|
||||||
std::string dBar = ""; while (dBar.length () < deletedBar) dBar += "+";
|
std::string dBar = ""; while (dBar.length () < deletedBar) dBar += "-";
|
||||||
|
|
||||||
bar = aBar + cBar + dBar;
|
bar = aBar + cBar + dBar;
|
||||||
}
|
}
|
||||||
|
@ -2301,18 +2325,22 @@ void handleReportActive (const TDB& tdb, T& task, Config& conf)
|
||||||
T refTask (tasks[i]);
|
T refTask (tasks[i]);
|
||||||
if (refTask.getAttribute ("start") != "")
|
if (refTask.getAttribute ("start") != "")
|
||||||
{
|
{
|
||||||
|
Date now;
|
||||||
bool imminent = false;
|
bool imminent = false;
|
||||||
bool overdue = false;
|
bool overdue = false;
|
||||||
std::string due = refTask.getAttribute ("due");
|
std::string due = refTask.getAttribute ("due");
|
||||||
if (due.length ())
|
if (due.length ())
|
||||||
{
|
{
|
||||||
|
switch (getDueState (due))
|
||||||
|
{
|
||||||
|
case 2: overdue = true; break;
|
||||||
|
case 1: imminent = true; break;
|
||||||
|
case 0:
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
Date dt (::atoi (due.c_str ()));
|
Date dt (::atoi (due.c_str ()));
|
||||||
due = dt.toString (conf.get ("dateformat", "m/d/Y"));
|
due = dt.toString (conf.get ("dateformat", "m/d/Y"));
|
||||||
|
|
||||||
Date now;
|
|
||||||
overdue = dt < now ? true : false;
|
|
||||||
Date nextweek = now + 7 * 86400;
|
|
||||||
imminent = dt < nextweek ? true : false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// All criteria match, so add refTask to the output table.
|
// All criteria match, so add refTask to the output table.
|
||||||
|
@ -2529,20 +2557,24 @@ void handleReportOldest (const TDB& tdb, T& task, Config& conf)
|
||||||
for (unsigned int i = 0; i < min (quantity, tasks.size ()); ++i)
|
for (unsigned int i = 0; i < min (quantity, tasks.size ()); ++i)
|
||||||
{
|
{
|
||||||
T refTask (tasks[i]);
|
T refTask (tasks[i]);
|
||||||
|
Date now;
|
||||||
|
|
||||||
// Now format the matching task.
|
// Now format the matching task.
|
||||||
bool imminent = false;
|
bool imminent = false;
|
||||||
bool overdue = false;
|
bool overdue = false;
|
||||||
Date now;
|
|
||||||
std::string due = refTask.getAttribute ("due");
|
std::string due = refTask.getAttribute ("due");
|
||||||
if (due.length ())
|
if (due.length ())
|
||||||
{
|
{
|
||||||
|
switch (getDueState (due))
|
||||||
|
{
|
||||||
|
case 2: overdue = true; break;
|
||||||
|
case 1: imminent = true; break;
|
||||||
|
case 0:
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
Date dt (::atoi (due.c_str ()));
|
Date dt (::atoi (due.c_str ()));
|
||||||
due = dt.toString (conf.get ("dateformat", "m/d/Y"));
|
due = dt.toString (conf.get ("dateformat", "m/d/Y"));
|
||||||
|
|
||||||
overdue = (dt < now) ? true : false;
|
|
||||||
Date nextweek = now + 7 * 86400;
|
|
||||||
imminent = dt < nextweek ? true : false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string active;
|
std::string active;
|
||||||
|
@ -2669,20 +2701,24 @@ void handleReportNewest (const TDB& tdb, T& task, Config& conf)
|
||||||
for (int i = total - 1; i >= max (0, total - quantity); --i)
|
for (int i = total - 1; i >= max (0, total - quantity); --i)
|
||||||
{
|
{
|
||||||
T refTask (tasks[i]);
|
T refTask (tasks[i]);
|
||||||
|
Date now;
|
||||||
|
|
||||||
// Now format the matching task.
|
// Now format the matching task.
|
||||||
bool imminent = false;
|
bool imminent = false;
|
||||||
bool overdue = false;
|
bool overdue = false;
|
||||||
Date now;
|
|
||||||
std::string due = refTask.getAttribute ("due");
|
std::string due = refTask.getAttribute ("due");
|
||||||
if (due.length ())
|
if (due.length ())
|
||||||
{
|
{
|
||||||
|
switch (getDueState (due))
|
||||||
|
{
|
||||||
|
case 2: overdue = true; break;
|
||||||
|
case 1: imminent = true; break;
|
||||||
|
case 0:
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
Date dt (::atoi (due.c_str ()));
|
Date dt (::atoi (due.c_str ()));
|
||||||
due = dt.toString (conf.get ("dateformat", "m/d/Y"));
|
due = dt.toString (conf.get ("dateformat", "m/d/Y"));
|
||||||
|
|
||||||
overdue = (dt < now) ? true : false;
|
|
||||||
Date nextweek = now + 7 * 86400;
|
|
||||||
imminent = dt < nextweek ? true : false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string active;
|
std::string active;
|
||||||
|
@ -3386,12 +3422,35 @@ void decorateRecurringTask (T& task)
|
||||||
task.getAttribute ("recur") != "")
|
task.getAttribute ("recur") != "")
|
||||||
{
|
{
|
||||||
task.setAttribute ("base", task.getAttribute ("due"));
|
task.setAttribute ("base", task.getAttribute ("due"));
|
||||||
|
|
||||||
// TODO Create "range".
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Determines whether a task is overdue. Returns
|
||||||
|
// 0 = not due at all
|
||||||
|
// 1 = imminent
|
||||||
|
// 2 = overdue
|
||||||
|
int getDueState (const std::string& due)
|
||||||
|
{
|
||||||
|
if (due.length ())
|
||||||
|
{
|
||||||
|
Date dt (::atoi (due.c_str ()));
|
||||||
|
Date now;
|
||||||
|
|
||||||
|
if (dt < now)
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
Date nextweek = now + 7 * 86400;
|
||||||
|
if (dt < nextweek)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Scan for recurring tasks, and generate any necessary instances of those
|
||||||
|
// tasks.
|
||||||
void checkRecurring (std::vector <T>& tasks)
|
void checkRecurring (std::vector <T>& tasks)
|
||||||
{
|
{
|
||||||
std::vector <T>::iterator it;
|
std::vector <T>::iterator it;
|
||||||
|
@ -3399,7 +3458,18 @@ void checkRecurring (std::vector <T>& tasks)
|
||||||
{
|
{
|
||||||
if (it->getStatus () == T::recurring)
|
if (it->getStatus () == T::recurring)
|
||||||
{
|
{
|
||||||
|
// This task is recurring. While it remains hidden from view, it spawns
|
||||||
|
// child tasks automatically, here, that are regular tasks, except they
|
||||||
|
// have a "parent" attribute that contains the UUID of the original.
|
||||||
|
|
||||||
|
// Generate a list of child tasks.
|
||||||
|
std::vector <T> children;
|
||||||
|
std::vector <T>::iterator them;
|
||||||
|
for (them = tasks.begin (); them != tasks.end (); ++them)
|
||||||
|
if (them->getAttribute ("parent") != "")
|
||||||
|
children.push_back (*them);
|
||||||
|
|
||||||
|
// TODO Determine if any new child tasks need to be generated.
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,6 +111,7 @@ std::string formatSeconds (time_t);
|
||||||
const std::string uuid ();
|
const std::string uuid ();
|
||||||
const char* optionalBlankLine (Config&);
|
const char* optionalBlankLine (Config&);
|
||||||
int convertDuration (const std::string&);
|
int convertDuration (const std::string&);
|
||||||
|
int getDueState (const std::string&);
|
||||||
int addDuration (const Date&, const std::string&);
|
int addDuration (const Date&, const std::string&);
|
||||||
|
|
||||||
// rules.cpp
|
// rules.cpp
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue