mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-06-26 10:54:26 +02:00
Feature #415
- Added feature #415, which supports displaying just a single page of tasks, by specifying either 'limit:page' to a command, or 'report.xxx.limit:page' in a report specification (thanks to T. Charles Yun). - Modified the 'next' report to only display a page, by default.
This commit is contained in:
parent
2f85941d37
commit
916b8641b3
13 changed files with 239 additions and 28 deletions
|
@ -20,7 +20,11 @@
|
||||||
list all used projects/tags, not just the ones used in current pending tasks.
|
list all used projects/tags, not just the ones used in current pending tasks.
|
||||||
Controlled by the 'list.all.projects' and 'list.all.tags' configuration
|
Controlled by the 'list.all.projects' and 'list.all.tags' configuration
|
||||||
variables (thanks to Dirk Deimeke).
|
variables (thanks to Dirk Deimeke).
|
||||||
|
+ Added feature #415, which supports displaying just a single page of tasks,
|
||||||
|
by specifying either 'limit:page' to a command, or 'report.xxx.limit:page'
|
||||||
|
in a report specification (thanks to T. Charles Yun).
|
||||||
+ Improvements to the man pages (thanks to T. Charles Yun).
|
+ Improvements to the man pages (thanks to T. Charles Yun).
|
||||||
|
+ Modified the 'next' report to only display a page, by default.
|
||||||
+ Added feature #408, making it possible to delete annotations with the new
|
+ Added feature #408, making it possible to delete annotations with the new
|
||||||
denotate command and the provided description (thanks to Dirk Deimeke).
|
denotate command and the provided description (thanks to Dirk Deimeke).
|
||||||
+ Fixed bug #406 so that task now includes command aliases in the _commands
|
+ Fixed bug #406 so that task now includes command aliases in the _commands
|
||||||
|
|
|
@ -302,7 +302,10 @@ Specifies background color.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B limit:<number-of-rows>
|
.B limit:<number-of-rows>
|
||||||
Specifies the desired number of rows a report should have.
|
Specifies the desired number of tasks a report should show, if a positive
|
||||||
|
integer is given. The value 'page' may also be used, and will limit the
|
||||||
|
report output to as many lines of text as will fit on screen. This defaults
|
||||||
|
to 25 lines, if ncurses is not installed or enabled.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B wait:<wait-date>
|
.B wait:<wait-date>
|
||||||
|
|
|
@ -344,8 +344,8 @@ bool Att::validNameValue (
|
||||||
|
|
||||||
else if (name == "limit")
|
else if (name == "limit")
|
||||||
{
|
{
|
||||||
if (value == "" || !digitsOnly (value))
|
if (value == "" || (value != "page" && !digitsOnly (value)))
|
||||||
throw std::string ("The '") + name + "' attribute must be an integer.";
|
throw std::string ("The '") + name + "' attribute must be an integer, or the value 'page'.";
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (name == "status")
|
else if (name == "status")
|
||||||
|
|
|
@ -293,7 +293,7 @@ std::string Config::defaults =
|
||||||
"report.next.columns=id,project,priority,due,active,age,description\n"
|
"report.next.columns=id,project,priority,due,active,age,description\n"
|
||||||
"report.next.labels=ID,Project,Pri,Due,Active,Age,Description\n"
|
"report.next.labels=ID,Project,Pri,Due,Active,Age,Description\n"
|
||||||
"report.next.sort=due+,priority-,project+\n"
|
"report.next.sort=due+,priority-,project+\n"
|
||||||
"report.next.filter=status:pending\n"
|
"report.next.filter=status:pending limit:page\n"
|
||||||
"#report.next.dateformat=m/d/Y\n"
|
"#report.next.dateformat=m/d/Y\n"
|
||||||
"#report.next.annotations=full\n"
|
"#report.next.annotations=full\n"
|
||||||
"\n";
|
"\n";
|
||||||
|
|
|
@ -55,6 +55,7 @@ public:
|
||||||
void shadow (); // shadow file update
|
void shadow (); // shadow file update
|
||||||
|
|
||||||
int getWidth (); // determine terminal width
|
int getWidth (); // determine terminal width
|
||||||
|
int getHeight (); // determine terminal height
|
||||||
|
|
||||||
void header (const std::string&); // Header message sink
|
void header (const std::string&); // Header message sink
|
||||||
void footnote (const std::string&); // Footnote message sink
|
void footnote (const std::string&); // Footnote message sink
|
||||||
|
@ -93,7 +94,6 @@ public:
|
||||||
std::vector <std::string> tagRemovals;
|
std::vector <std::string> tagRemovals;
|
||||||
Hooks hooks;
|
Hooks hooks;
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector <std::string> headers;
|
std::vector <std::string> headers;
|
||||||
std::vector <std::string> footnotes;
|
std::vector <std::string> footnotes;
|
||||||
std::vector <std::string> debugMessages;
|
std::vector <std::string> debugMessages;
|
||||||
|
|
|
@ -1024,10 +1024,13 @@ void Table::clean (std::string& value)
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
const std::string Table::render (int maximum /* = 0 */)
|
const std::string Table::render (int maxrows /* = 0 */, int maxlines /* = 0 */)
|
||||||
{
|
{
|
||||||
Timer t ("Table::render");
|
Timer t ("Table::render");
|
||||||
|
|
||||||
|
// May not exceed maxlines, if non-zero.
|
||||||
|
int renderedlines = 0;
|
||||||
|
|
||||||
calculateColumnWidths ();
|
calculateColumnWidths ();
|
||||||
|
|
||||||
// Print column headers in column order.
|
// Print column headers in column order.
|
||||||
|
@ -1048,8 +1051,12 @@ const std::string Table::render (int maximum /* = 0 */)
|
||||||
}
|
}
|
||||||
|
|
||||||
output += "\n";
|
output += "\n";
|
||||||
|
++renderedlines;
|
||||||
if (underline.length ())
|
if (underline.length ())
|
||||||
|
{
|
||||||
output += underline + "\n";
|
output += underline + "\n";
|
||||||
|
++renderedlines;
|
||||||
|
}
|
||||||
|
|
||||||
// Determine row order, according to sort options.
|
// Determine row order, according to sort options.
|
||||||
std::vector <int> order;
|
std::vector <int> order;
|
||||||
|
@ -1060,14 +1067,17 @@ const std::string Table::render (int maximum /* = 0 */)
|
||||||
if (mSortColumns.size ())
|
if (mSortColumns.size ())
|
||||||
sort (order);
|
sort (order);
|
||||||
|
|
||||||
// If a non-zero maximum is specified, then it limits the number of rows of
|
// If a non-zero maxrows is specified, then it limits the number of rows of
|
||||||
// the table that are rendered.
|
// the table that are rendered.
|
||||||
int limit = mRows;
|
int limitrows = mRows;
|
||||||
if (maximum != 0)
|
if (maxrows != 0)
|
||||||
limit = min (maximum, mRows);
|
limitrows = min (maxrows, mRows);
|
||||||
|
|
||||||
|
// If a non-zero maxlines is specified, then it limits the number of lines
|
||||||
|
// of output from the table that are rendered.
|
||||||
|
|
||||||
// Print all rows.
|
// Print all rows.
|
||||||
for (int row = 0; row < limit; ++row)
|
for (int row = 0; row < limitrows; ++row)
|
||||||
{
|
{
|
||||||
std::vector <std::vector <std::string> > columns;
|
std::vector <std::vector <std::string> > columns;
|
||||||
std::vector <std::string> blanks;
|
std::vector <std::string> blanks;
|
||||||
|
@ -1105,6 +1115,11 @@ const std::string Table::render (int maximum /* = 0 */)
|
||||||
// Trim right.
|
// Trim right.
|
||||||
output.erase (output.find_last_not_of (" ") + 1);
|
output.erase (output.find_last_not_of (" ") + 1);
|
||||||
output += "\n";
|
output += "\n";
|
||||||
|
|
||||||
|
++renderedlines;
|
||||||
|
|
||||||
|
if (maxlines != 0 && renderedlines >= maxlines)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1113,6 +1128,9 @@ const std::string Table::render (int maximum /* = 0 */)
|
||||||
output.erase (output.find_last_not_of (" ") + 1);
|
output.erase (output.find_last_not_of (" ") + 1);
|
||||||
output += "\n";
|
output += "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (maxlines != 0 && renderedlines >= maxlines)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
optimize (output);
|
optimize (output);
|
||||||
|
|
|
@ -92,7 +92,7 @@ public:
|
||||||
|
|
||||||
int rowCount ();
|
int rowCount ();
|
||||||
int columnCount ();
|
int columnCount ();
|
||||||
const std::string render (int maximum = 0);
|
const std::string render (int maxrows = 0, int maxlines = 0);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string getCell (const int, const int);
|
std::string getCell (const int, const int);
|
||||||
|
|
|
@ -647,7 +647,7 @@ int handleShow (std::string &outs)
|
||||||
"next project shadow.command shadow.file shadow.notify weekstart editor "
|
"next project shadow.command shadow.file shadow.notify weekstart editor "
|
||||||
"import.synonym.id import.synonym.uuid complete.all.projects "
|
"import.synonym.id import.synonym.uuid complete.all.projects "
|
||||||
"complete.all.tags search.case.sensitive hooks active.indicator tag.indicator "
|
"complete.all.tags search.case.sensitive hooks active.indicator tag.indicator "
|
||||||
"recurrence.indicator recurrence.limit "
|
"recurrence.indicator recurrence.limit list.all.projects list.all.tags "
|
||||||
#ifdef FEATURE_SHELL
|
#ifdef FEATURE_SHELL
|
||||||
"shell.prompt "
|
"shell.prompt "
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -715,23 +715,37 @@ int runCustomReport (
|
||||||
table.setTableAlternateColor (alternate);
|
table.setTableAlternateColor (alternate);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Limit the number of rows according to the report definition.
|
// Report output can be limited by rows or lines.
|
||||||
int maximum = context.config.getInteger (std::string ("report.") + report + ".limit");
|
int maxrows = 0;
|
||||||
|
int maxlines = 0;
|
||||||
|
getLimits (report, maxrows, maxlines);
|
||||||
|
|
||||||
// If the custom report has a defined limit, then allow a numeric override.
|
// Adjust for fluff in the output.
|
||||||
// This is an integer specified as a filter (limit:10).
|
if (maxlines)
|
||||||
if (context.task.has ("limit"))
|
maxlines -= (context.config.getBoolean ("blanklines") ? 2 : 0)
|
||||||
maximum = atoi (context.task.get ("limit").c_str ());
|
+ 1
|
||||||
|
+ context.headers.size ()
|
||||||
|
+ context.footnotes.size ();
|
||||||
|
|
||||||
std::stringstream out;
|
std::stringstream out;
|
||||||
if (table.rowCount ())
|
if (table.rowCount ())
|
||||||
|
{
|
||||||
out << optionalBlankLine ()
|
out << optionalBlankLine ()
|
||||||
<< table.render (maximum)
|
<< table.render (maxrows, maxlines)
|
||||||
<< optionalBlankLine ()
|
<< optionalBlankLine ()
|
||||||
<< table.rowCount ()
|
<< table.rowCount ()
|
||||||
<< (table.rowCount () == 1 ? " task" : " tasks")
|
<< (table.rowCount () == 1 ? " task" : " tasks");
|
||||||
<< std::endl;
|
|
||||||
else {
|
if (maxrows)
|
||||||
|
out << ", " << maxrows << " shown";
|
||||||
|
|
||||||
|
if (maxlines)
|
||||||
|
out << ", truncated to " << maxlines-1 << " lines";
|
||||||
|
|
||||||
|
out << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
out << "No matches."
|
out << "No matches."
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
rc = 1;
|
rc = 1;
|
||||||
|
@ -813,3 +827,44 @@ void validSortColumns (
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// A value of zero mean unlimited.
|
||||||
|
// A value of 'page' means however many screen lines there are.
|
||||||
|
// A value of a positive integer is a row limit.
|
||||||
|
void getLimits (const std::string& report, int& rows, int& lines)
|
||||||
|
{
|
||||||
|
rows = 0;
|
||||||
|
lines = 0;
|
||||||
|
|
||||||
|
int screenheight = 0;
|
||||||
|
|
||||||
|
// If a report has a stated limit, use it.
|
||||||
|
if (report != "")
|
||||||
|
{
|
||||||
|
std::string name = "report." + report + ".limit";
|
||||||
|
if (context.config.get (name) == "page")
|
||||||
|
lines = screenheight = context.getHeight ();
|
||||||
|
else
|
||||||
|
rows = context.config.getInteger (name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the custom report has a defined limit, then allow a numeric override.
|
||||||
|
// This is an integer specified as a filter (limit:10).
|
||||||
|
if (context.task.has ("limit"))
|
||||||
|
{
|
||||||
|
if (context.task.get ("limit") == "page")
|
||||||
|
{
|
||||||
|
if (screenheight == 0)
|
||||||
|
screenheight = context.getHeight ();
|
||||||
|
|
||||||
|
rows = 0;
|
||||||
|
lines = screenheight;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rows = atoi (context.task.get ("limit").c_str ());
|
||||||
|
lines = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -167,3 +167,36 @@ int Context::getWidth ()
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int Context::getHeight ()
|
||||||
|
{
|
||||||
|
// Determine window size, and set table accordingly.
|
||||||
|
int height = 25; // TODO Is there a better number?
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBNCURSES
|
||||||
|
if (config.getBoolean ("curses"))
|
||||||
|
{
|
||||||
|
#ifdef FEATURE_NCURSES_COLS
|
||||||
|
initscr ();
|
||||||
|
height = LINES;
|
||||||
|
#else
|
||||||
|
WINDOW* w = initscr ();
|
||||||
|
height = w->_maxy + 1;
|
||||||
|
#endif
|
||||||
|
endwin ();
|
||||||
|
|
||||||
|
std::stringstream out;
|
||||||
|
out << "Context::getHeight: ncurses determined height of " << height << " characters";
|
||||||
|
debug (out.str ());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
debug ("Context::getHeight: ncurses available but disabled.");
|
||||||
|
#else
|
||||||
|
std::stringstream out;
|
||||||
|
out << "Context::getHeight: no ncurses, using height of " << height << " characters";
|
||||||
|
debug (out.str ());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -117,6 +117,7 @@ int runCustomReport (const std::string&, const std::string&,
|
||||||
std::string&);
|
std::string&);
|
||||||
void validReportColumns (const std::vector <std::string>&);
|
void validReportColumns (const std::vector <std::string>&);
|
||||||
void validSortColumns (const std::vector <std::string>&, const std::vector <std::string>&);
|
void validSortColumns (const std::vector <std::string>&, const std::vector <std::string>&);
|
||||||
|
void getLimits (const std::string&, int&, int&);
|
||||||
|
|
||||||
// rules.cpp
|
// rules.cpp
|
||||||
void initializeColorRules ();
|
void initializeColorRules ();
|
||||||
|
|
|
@ -283,7 +283,7 @@ int longUsage (std::string &outs)
|
||||||
<< " until: Recurrence end date" << "\n"
|
<< " until: Recurrence end date" << "\n"
|
||||||
<< " fg: Foreground color" << "\n"
|
<< " fg: Foreground color" << "\n"
|
||||||
<< " bg: Background color" << "\n"
|
<< " bg: Background color" << "\n"
|
||||||
<< " limit: Desired number of rows in report" << "\n"
|
<< " limit: Desired number of rows in report, or 'page'" << "\n"
|
||||||
<< " wait: Date until task becomes pending" << "\n"
|
<< " wait: Date until task becomes pending" << "\n"
|
||||||
<< "\n"
|
<< "\n"
|
||||||
<< "Attribute modifiers improve filters. Supported modifiers are:" << "\n"
|
<< "Attribute modifiers improve filters. Supported modifiers are:" << "\n"
|
||||||
|
@ -2318,6 +2318,7 @@ int handleReportCalendar (std::string &outs)
|
||||||
holTable.addCell (row, 1, holName);
|
holTable.addCell (row, 1, holName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out << optionalBlankLine ()
|
out << optionalBlankLine ()
|
||||||
<< holTable.render ()
|
<< holTable.render ()
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
|
|
96
src/tests/limit.t
Executable file
96
src/tests/limit.t
Executable file
|
@ -0,0 +1,96 @@
|
||||||
|
#! /usr/bin/perl
|
||||||
|
################################################################################
|
||||||
|
## task - a command line task list manager.
|
||||||
|
##
|
||||||
|
## Copyright 2006 - 2010, Paul Beckingham.
|
||||||
|
## All rights reserved.
|
||||||
|
##
|
||||||
|
## This program is free software; you can redistribute it and/or modify it under
|
||||||
|
## the terms of the GNU General Public License as published by the Free Software
|
||||||
|
## Foundation; either version 2 of the License, or (at your option) any later
|
||||||
|
## version.
|
||||||
|
##
|
||||||
|
## This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
## details.
|
||||||
|
##
|
||||||
|
## You should have received a copy of the GNU General Public License along with
|
||||||
|
## this program; if not, write to the
|
||||||
|
##
|
||||||
|
## Free Software Foundation, Inc.,
|
||||||
|
## 51 Franklin Street, Fifth Floor,
|
||||||
|
## Boston, MA
|
||||||
|
## 02110-1301
|
||||||
|
## USA
|
||||||
|
##
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use Test::More tests => 8;
|
||||||
|
|
||||||
|
# Create the rc file.
|
||||||
|
if (open my $fh, '>', 'limit.rc')
|
||||||
|
{
|
||||||
|
print $fh "data.location=.\n";
|
||||||
|
close $fh;
|
||||||
|
ok (-r 'limit.rc', 'Created limit.rc');
|
||||||
|
}
|
||||||
|
|
||||||
|
# Add a large number of tasks (> 25).
|
||||||
|
qx{../task rc:limit.rc add one};
|
||||||
|
qx{../task rc:limit.rc add two};
|
||||||
|
qx{../task rc:limit.rc add three};
|
||||||
|
qx{../task rc:limit.rc add four};
|
||||||
|
qx{../task rc:limit.rc add five};
|
||||||
|
qx{../task rc:limit.rc add six};
|
||||||
|
qx{../task rc:limit.rc add seven};
|
||||||
|
qx{../task rc:limit.rc add eight};
|
||||||
|
qx{../task rc:limit.rc add nine};
|
||||||
|
qx{../task rc:limit.rc add ten};
|
||||||
|
qx{../task rc:limit.rc add eleven};
|
||||||
|
qx{../task rc:limit.rc add twelve};
|
||||||
|
qx{../task rc:limit.rc add thirteen};
|
||||||
|
qx{../task rc:limit.rc add fourteen};
|
||||||
|
qx{../task rc:limit.rc add fifteen};
|
||||||
|
qx{../task rc:limit.rc add sixteen};
|
||||||
|
qx{../task rc:limit.rc add seventeen};
|
||||||
|
qx{../task rc:limit.rc add eighteen};
|
||||||
|
qx{../task rc:limit.rc add nineteen};
|
||||||
|
qx{../task rc:limit.rc add twenty};
|
||||||
|
qx{../task rc:limit.rc add twenty one};
|
||||||
|
qx{../task rc:limit.rc add twenty two};
|
||||||
|
qx{../task rc:limit.rc add twenty three};
|
||||||
|
qx{../task rc:limit.rc add twenty four};
|
||||||
|
qx{../task rc:limit.rc add twenty five};
|
||||||
|
qx{../task rc:limit.rc add twenty six};
|
||||||
|
qx{../task rc:limit.rc add twenty seven};
|
||||||
|
qx{../task rc:limit.rc add twenty eight};
|
||||||
|
qx{../task rc:limit.rc add twenty nine};
|
||||||
|
qx{../task rc:limit.rc add thirty};
|
||||||
|
|
||||||
|
my $output = qx{../task rc:limit.rc ls};
|
||||||
|
like ($output, qr/^30 tasks$/ms, 'unlimited');
|
||||||
|
|
||||||
|
$output = qx{../task rc:limit.rc ls limit:0};
|
||||||
|
like ($output, qr/^30 tasks$/ms, 'limited to 0 - unlimited');
|
||||||
|
|
||||||
|
$output = qx{../task rc:limit.rc ls limit:3};
|
||||||
|
like ($output, qr/^30 tasks, 3 shown$/ms, 'limited to 3');
|
||||||
|
|
||||||
|
$output = qx{../task rc:limit.rc ls limit:page};
|
||||||
|
like ($output, qr/^30 tasks, truncated to 20 lines$/ms, 'limited to page');
|
||||||
|
|
||||||
|
# Cleanup.
|
||||||
|
unlink 'pending.data';
|
||||||
|
ok (!-r 'pending.data', 'Removed pending.data');
|
||||||
|
|
||||||
|
unlink 'undo.data';
|
||||||
|
ok (!-r 'undo.data', 'Removed undo.data');
|
||||||
|
|
||||||
|
unlink 'limit.rc';
|
||||||
|
ok (!-r 'limit.rc', 'Removed limit.rc');
|
||||||
|
|
||||||
|
exit 0;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue