mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-06-26 10:54:26 +02:00
Journal Feature
- Added change log display to the 'info' command, controlled by the 'journal.info' configuration setting.
This commit is contained in:
parent
31cf470cc8
commit
4c3354fa50
8 changed files with 219 additions and 16 deletions
10
ChangeLog
10
ChangeLog
|
@ -2,11 +2,13 @@
|
||||||
------ current release ---------------------------
|
------ current release ---------------------------
|
||||||
|
|
||||||
1.9.4 ()
|
1.9.4 ()
|
||||||
+ Added burndown charts - burndown.daily, burndown.weekly, burndown.monthly,
|
+ Added burndown charts - 'burndown.daily', 'burndown.weekly',
|
||||||
that use color.burndown.pending, color.burndown.started and
|
'burndown.monthly', that use 'color.burndown.pending', 'color.burndown.started'
|
||||||
color.burndown.done colors.
|
and 'color.burndown.done' colors.
|
||||||
+ Added highlighting for the show command that indicates which values differ
|
+ Added highlighting for the 'show' command that indicates which values differ
|
||||||
from the defaults.
|
from the defaults.
|
||||||
|
+ Added change log display to the 'info' command, controlled by the
|
||||||
|
'journal.info' configuration setting.
|
||||||
+ Added feature #158, regular expression support for filters and substitutions.
|
+ Added feature #158, regular expression support for filters and substitutions.
|
||||||
+ Added feature #247, providing infinite width reports when redirecting output
|
+ Added feature #247, providing infinite width reports when redirecting output
|
||||||
to a file, by setting defaultwidth to 0.
|
to a file, by setting defaultwidth to 0.
|
||||||
|
|
3
NEWS
3
NEWS
|
@ -7,6 +7,7 @@ New Features in taskwarrior 1.9.4
|
||||||
- Regular expression support in filters and substitutions.
|
- Regular expression support in filters and substitutions.
|
||||||
- Added highlighting for the show command that indicates which values differ
|
- Added highlighting for the show command that indicates which values differ
|
||||||
from the defaults.
|
from the defaults.
|
||||||
|
- Added change log display to the 'info' command.
|
||||||
|
|
||||||
Please refer to the ChangeLog file for full details. There are too many to
|
Please refer to the ChangeLog file for full details. There are too many to
|
||||||
list here.
|
list here.
|
||||||
|
@ -29,6 +30,8 @@ New configuration options in taskwarrior 1.9.4
|
||||||
- regex=on enables regular expression searches for filters (task list a...e
|
- regex=on enables regular expression searches for filters (task list a...e
|
||||||
matches 'above') and substitutions (task <id> /a...e/over/ changes 'above'
|
matches 'above') and substitutions (task <id> /a...e/over/ changes 'above'
|
||||||
to 'over'). Default is off, as this is an advanced feature.
|
to 'over'). Default is off, as this is an advanced feature.
|
||||||
|
- journal.info controls whether a change log for each task is displayed by
|
||||||
|
the 'info' command.
|
||||||
|
|
||||||
Newly deprecated features in taskwarrior 1.9.4
|
Newly deprecated features in taskwarrior 1.9.4
|
||||||
|
|
||||||
|
|
|
@ -474,7 +474,7 @@ turned off by setting the variable to none. The default value is "none".
|
||||||
.B journal.time=no
|
.B journal.time=no
|
||||||
May be yes or no, and determines whether the 'start' and 'stop' commands should
|
May be yes or no, and determines whether the 'start' and 'stop' commands should
|
||||||
record an annotation when being executed. The default value is "no". The text of
|
record an annotation when being executed. The default value is "no". The text of
|
||||||
the corresponding annotations is controlled by
|
the corresponding annotations is controlled by:
|
||||||
|
|
||||||
.TP journal.time.start.annotation=Started task
|
.TP journal.time.start.annotation=Started task
|
||||||
The text of the annotation that is recorded when executing the start command and
|
The text of the annotation that is recorded when executing the start command and
|
||||||
|
@ -484,6 +484,10 @@ having set journal.time.
|
||||||
The text of the annotation that is recorded when executing the stop command and
|
The text of the annotation that is recorded when executing the stop command and
|
||||||
having set journal.time.
|
having set journal.time.
|
||||||
|
|
||||||
|
.TP journal.info=on
|
||||||
|
When enabled, this setting causes a change log of each task to be displayed by
|
||||||
|
the 'info' command. Default value is "on".
|
||||||
|
|
||||||
.SS Holidays
|
.SS Holidays
|
||||||
Holidays are entered either directly in the .taskrc file or via an include file
|
Holidays are entered either directly in the .taskrc file or via an include file
|
||||||
that is specified in .taskrc. For each holiday the name and the date is
|
that is specified in .taskrc. For each holiday the name and the date is
|
||||||
|
|
|
@ -103,6 +103,7 @@ std::string Config::defaults =
|
||||||
"journal.time=no # Record start/stop commands as annotation\n"
|
"journal.time=no # Record start/stop commands as annotation\n"
|
||||||
"journal.time.start.annotation=Started task # Annotation description for the start journal entry\n"
|
"journal.time.start.annotation=Started task # Annotation description for the start journal entry\n"
|
||||||
"journal.time.stop.annotation=Stopped task # Annotation description for the stop journal entry\n"
|
"journal.time.stop.annotation=Stopped task # Annotation description for the stop journal entry\n"
|
||||||
|
"journal.info=on # Display task journal with info command\n"
|
||||||
"\n"
|
"\n"
|
||||||
"# Dependency controls\n"
|
"# Dependency controls\n"
|
||||||
"dependency.reminder=on # Nags on dependency chain violations\n"
|
"dependency.reminder=on # Nags on dependency chain violations\n"
|
||||||
|
|
|
@ -907,7 +907,7 @@ int handleShow (std::string& outs)
|
||||||
"default.command default.priority default.project defaultwidth due "
|
"default.command default.priority default.project defaultwidth due "
|
||||||
"dependency.confirmation dependency.reminder locale displayweeknumber "
|
"dependency.confirmation dependency.reminder locale displayweeknumber "
|
||||||
"export.ical.class echo.command fontunderline locking monthsperline nag "
|
"export.ical.class echo.command fontunderline locking monthsperline nag "
|
||||||
"next journal.time journal.time.start.annotation "
|
"next journal.time journal.time.start.annotation journal.info "
|
||||||
"journal.time.stop.annotation project shadow.command shadow.file "
|
"journal.time.stop.annotation project shadow.command shadow.file "
|
||||||
"shadow.notify weekstart editor import.synonym.id import.synonym.uuid "
|
"shadow.notify weekstart editor import.synonym.id import.synonym.uuid "
|
||||||
"complete.all.projects complete.all.tags search.case.sensitive hooks "
|
"complete.all.projects complete.all.tags search.case.sensitive hooks "
|
||||||
|
|
|
@ -37,15 +37,15 @@
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#include "Context.h"
|
#include <Context.h>
|
||||||
#include "Directory.h"
|
#include <Directory.h>
|
||||||
#include "File.h"
|
#include <File.h>
|
||||||
#include "Date.h"
|
#include <Date.h>
|
||||||
#include "Duration.h"
|
#include <Duration.h>
|
||||||
#include "Table.h"
|
#include <Table.h>
|
||||||
#include "text.h"
|
#include <text.h>
|
||||||
#include "util.h"
|
#include <util.h>
|
||||||
#include "main.h"
|
#include <main.h>
|
||||||
|
|
||||||
#ifdef HAVE_LIBNCURSES
|
#ifdef HAVE_LIBNCURSES
|
||||||
#include <ncurses.h>
|
#include <ncurses.h>
|
||||||
|
@ -396,6 +396,15 @@ int handleInfo (std::string& outs)
|
||||||
// Filter sequence.
|
// Filter sequence.
|
||||||
context.filter.applySequence (tasks, context.sequence);
|
context.filter.applySequence (tasks, context.sequence);
|
||||||
|
|
||||||
|
// Read the undo file.
|
||||||
|
std::vector <std::string> undo;
|
||||||
|
if (context.config.getBoolean ("journal.info"))
|
||||||
|
{
|
||||||
|
Directory location (context.config.get ("data.location"));
|
||||||
|
std::string undoFile = location.data + "/undo.data";
|
||||||
|
File::read (undoFile, undo);
|
||||||
|
}
|
||||||
|
|
||||||
// Find the task.
|
// Find the task.
|
||||||
std::stringstream out;
|
std::stringstream out;
|
||||||
foreach (task, tasks)
|
foreach (task, tasks)
|
||||||
|
@ -614,7 +623,7 @@ int handleInfo (std::string& outs)
|
||||||
// uuid
|
// uuid
|
||||||
row = table.addRow ();
|
row = table.addRow ();
|
||||||
table.addCell (row, 0, "UUID");
|
table.addCell (row, 0, "UUID");
|
||||||
value = task->get ("uuid");
|
std::string uuid = value = task->get ("uuid");
|
||||||
context.hooks.trigger ("format-uuid", "uuid", value);
|
context.hooks.trigger ("format-uuid", "uuid", value);
|
||||||
table.addCell (row, 1, value);
|
table.addCell (row, 1, value);
|
||||||
|
|
||||||
|
@ -659,17 +668,82 @@ int handleInfo (std::string& outs)
|
||||||
//table.addCell (row, 0, "Urgency");
|
//table.addCell (row, 0, "Urgency");
|
||||||
//table.addCell (row, 1, task->urgency ());
|
//table.addCell (row, 1, task->urgency ());
|
||||||
|
|
||||||
|
Table journal;
|
||||||
|
|
||||||
// If an alternating row color is specified, notify the table.
|
// If an alternating row color is specified, notify the table.
|
||||||
if (context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor"))
|
if (context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor"))
|
||||||
{
|
{
|
||||||
Color alternate (context.config.get ("color.alternate"));
|
Color alternate (context.config.get ("color.alternate"));
|
||||||
if (alternate.nontrivial ())
|
if (alternate.nontrivial ())
|
||||||
|
{
|
||||||
table.setTableAlternateColor (alternate);
|
table.setTableAlternateColor (alternate);
|
||||||
|
journal.setTableAlternateColor (alternate);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out << optionalBlankLine ()
|
out << optionalBlankLine ()
|
||||||
<< table.render ()
|
<< table.render ()
|
||||||
<< "\n";
|
<< "\n";
|
||||||
|
|
||||||
|
journal.setTableWidth (context.getWidth ());
|
||||||
|
journal.setDateFormat (context.config.get ("dateformat"));
|
||||||
|
|
||||||
|
journal.addColumn ("Date");
|
||||||
|
journal.addColumn ("Modification");
|
||||||
|
|
||||||
|
if ((context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor")) &&
|
||||||
|
context.config.getBoolean ("fontunderline"))
|
||||||
|
{
|
||||||
|
journal.setColumnUnderline (0);
|
||||||
|
journal.setColumnUnderline (1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
journal.setTableDashedUnderline ();
|
||||||
|
|
||||||
|
journal.setColumnWidth (0, Table::minimum);
|
||||||
|
journal.setColumnWidth (1, Table::flexible);
|
||||||
|
|
||||||
|
journal.setColumnJustification (0, Table::left);
|
||||||
|
journal.setColumnJustification (1, Table::left);
|
||||||
|
|
||||||
|
if (context.config.getBoolean ("journal.info") &&
|
||||||
|
undo.size () > 3)
|
||||||
|
{
|
||||||
|
// Scan the undo data for entries matching this task.
|
||||||
|
std::string when;
|
||||||
|
std::string previous;
|
||||||
|
std::string current;
|
||||||
|
unsigned int i = 0;
|
||||||
|
while (i < undo.size ())
|
||||||
|
{
|
||||||
|
when = undo[i++];
|
||||||
|
previous = "";
|
||||||
|
if (undo[i].substr (0, 3) == "old")
|
||||||
|
previous = undo[i++];
|
||||||
|
|
||||||
|
current = undo[i++];
|
||||||
|
i++; // Separator
|
||||||
|
|
||||||
|
if (current.find ("uuid:\"" + uuid) != std::string::npos)
|
||||||
|
{
|
||||||
|
if (previous != "")
|
||||||
|
{
|
||||||
|
int row = journal.addRow ();
|
||||||
|
|
||||||
|
Date timestamp (atoi (when.substr (5).c_str ()));
|
||||||
|
journal.addCell (row, 0, timestamp.toString (context.config.get ("dateformat")));
|
||||||
|
|
||||||
|
Task before (previous.substr (4));
|
||||||
|
Task after (current.substr (4));
|
||||||
|
journal.addCell (row, 1, taskInfoDifferences (before, after));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (journal.rowCount () > 0)
|
||||||
|
out << journal.render ()
|
||||||
|
<< "\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! tasks.size ())
|
if (! tasks.size ())
|
||||||
|
|
118
src/util.cpp
118
src/util.cpp
|
@ -435,6 +435,124 @@ std::string taskDifferences (const Task& before, const Task& after)
|
||||||
return out.str ();
|
return out.str ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
std::string taskInfoDifferences (const Task& before, const Task& after)
|
||||||
|
{
|
||||||
|
// Attributes are all there is, so figure the different attribute names
|
||||||
|
// between before and after.
|
||||||
|
std::vector <std::string> beforeAtts;
|
||||||
|
foreach (att, before)
|
||||||
|
beforeAtts.push_back (att->first);
|
||||||
|
|
||||||
|
std::vector <std::string> afterAtts;
|
||||||
|
foreach (att, after)
|
||||||
|
afterAtts.push_back (att->first);
|
||||||
|
|
||||||
|
std::vector <std::string> beforeOnly;
|
||||||
|
std::vector <std::string> afterOnly;
|
||||||
|
listDiff (beforeAtts, afterAtts, beforeOnly, afterOnly);
|
||||||
|
|
||||||
|
// Now start generating a description of the differences.
|
||||||
|
std::stringstream out;
|
||||||
|
foreach (name, beforeOnly)
|
||||||
|
{
|
||||||
|
if (*name == "depends")
|
||||||
|
{
|
||||||
|
std::vector <int> deps_before;
|
||||||
|
before.getDependencies (deps_before);
|
||||||
|
std::string from;
|
||||||
|
join (from, ",", deps_before);
|
||||||
|
|
||||||
|
out << "dependencies '"
|
||||||
|
<< from
|
||||||
|
<< "' deleted\n";
|
||||||
|
}
|
||||||
|
else if (name->substr (0, 11) == "annotation_")
|
||||||
|
{
|
||||||
|
out << "annotation '"
|
||||||
|
<< before.get (*name)
|
||||||
|
<< "' deleted";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out << *name
|
||||||
|
<< " deleted\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (name, afterOnly)
|
||||||
|
{
|
||||||
|
if (*name == "depends")
|
||||||
|
{
|
||||||
|
std::vector <int> deps_after;
|
||||||
|
after.getDependencies (deps_after);
|
||||||
|
std::string to;
|
||||||
|
join (to, ",", deps_after);
|
||||||
|
|
||||||
|
out << *name
|
||||||
|
<< " set to '"
|
||||||
|
<< to
|
||||||
|
<< "'\n";
|
||||||
|
}
|
||||||
|
else if (name->substr (0, 11) == "annotation_")
|
||||||
|
{
|
||||||
|
out << "annotation added '"
|
||||||
|
<< after.get (*name)
|
||||||
|
<< "'";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
out << *name
|
||||||
|
<< " set to '"
|
||||||
|
<< renderAttribute (*name, after.get (*name))
|
||||||
|
<< "'\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (name, beforeAtts)
|
||||||
|
if (*name != "uuid" &&
|
||||||
|
before.get (*name) != after.get (*name))
|
||||||
|
{
|
||||||
|
if (*name == "depends")
|
||||||
|
{
|
||||||
|
std::vector <int> deps_before;
|
||||||
|
before.getDependencies (deps_before);
|
||||||
|
std::string from;
|
||||||
|
join (from, ",", deps_before);
|
||||||
|
|
||||||
|
std::vector <int> deps_after;
|
||||||
|
after.getDependencies (deps_after);
|
||||||
|
std::string to;
|
||||||
|
join (to, ",", deps_after);
|
||||||
|
|
||||||
|
out << *name
|
||||||
|
<< " changed from '"
|
||||||
|
<< from
|
||||||
|
<< "' to '"
|
||||||
|
<< to
|
||||||
|
<< "'\n";
|
||||||
|
}
|
||||||
|
else if (name->substr (0, 11) == "annotation_")
|
||||||
|
{
|
||||||
|
out << "annotation '"
|
||||||
|
<< after.get (*name)
|
||||||
|
<< "'";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
out << *name
|
||||||
|
<< " changed from '"
|
||||||
|
<< renderAttribute (*name, before.get (*name))
|
||||||
|
<< "' to '"
|
||||||
|
<< renderAttribute (*name, after.get (*name))
|
||||||
|
<< "'\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Shouldn't just say nothing.
|
||||||
|
if (out.str ().length () == 0)
|
||||||
|
out << "No changes made.\n";
|
||||||
|
|
||||||
|
return out.str ();
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
std::string renderAttribute (const std::string& name, const std::string& value)
|
std::string renderAttribute (const std::string& name, const std::string& value)
|
||||||
{
|
{
|
||||||
|
|
|
@ -70,6 +70,7 @@ const std::string uuid ();
|
||||||
|
|
||||||
bool taskDiff (const Task&, const Task&);
|
bool taskDiff (const Task&, const Task&);
|
||||||
std::string taskDifferences (const Task&, const Task&);
|
std::string taskDifferences (const Task&, const Task&);
|
||||||
|
std::string taskInfoDifferences (const Task&, const Task&);
|
||||||
std::string renderAttribute (const std::string&, const std::string&);
|
std::string renderAttribute (const std::string&, const std::string&);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue