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.
|
||||
Controlled by the 'list.all.projects' and 'list.all.tags' configuration
|
||||
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).
|
||||
+ Modified the 'next' report to only display a page, by default.
|
||||
+ Added feature #408, making it possible to delete annotations with the new
|
||||
denotate command and the provided description (thanks to Dirk Deimeke).
|
||||
+ Fixed bug #406 so that task now includes command aliases in the _commands
|
||||
|
|
|
@ -302,7 +302,10 @@ Specifies background color.
|
|||
|
||||
.TP
|
||||
.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
|
||||
.B wait:<wait-date>
|
||||
|
|
|
@ -344,8 +344,8 @@ bool Att::validNameValue (
|
|||
|
||||
else if (name == "limit")
|
||||
{
|
||||
if (value == "" || !digitsOnly (value))
|
||||
throw std::string ("The '") + name + "' attribute must be an integer.";
|
||||
if (value == "" || (value != "page" && !digitsOnly (value)))
|
||||
throw std::string ("The '") + name + "' attribute must be an integer, or the value 'page'.";
|
||||
}
|
||||
|
||||
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.labels=ID,Project,Pri,Due,Active,Age,Description\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.annotations=full\n"
|
||||
"\n";
|
||||
|
|
|
@ -55,6 +55,7 @@ public:
|
|||
void shadow (); // shadow file update
|
||||
|
||||
int getWidth (); // determine terminal width
|
||||
int getHeight (); // determine terminal height
|
||||
|
||||
void header (const std::string&); // Header message sink
|
||||
void footnote (const std::string&); // Footnote message sink
|
||||
|
@ -93,7 +94,6 @@ public:
|
|||
std::vector <std::string> tagRemovals;
|
||||
Hooks hooks;
|
||||
|
||||
private:
|
||||
std::vector <std::string> headers;
|
||||
std::vector <std::string> footnotes;
|
||||
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");
|
||||
|
||||
// May not exceed maxlines, if non-zero.
|
||||
int renderedlines = 0;
|
||||
|
||||
calculateColumnWidths ();
|
||||
|
||||
// Print column headers in column order.
|
||||
|
@ -1048,8 +1051,12 @@ const std::string Table::render (int maximum /* = 0 */)
|
|||
}
|
||||
|
||||
output += "\n";
|
||||
++renderedlines;
|
||||
if (underline.length ())
|
||||
{
|
||||
output += underline + "\n";
|
||||
++renderedlines;
|
||||
}
|
||||
|
||||
// Determine row order, according to sort options.
|
||||
std::vector <int> order;
|
||||
|
@ -1060,14 +1067,17 @@ const std::string Table::render (int maximum /* = 0 */)
|
|||
if (mSortColumns.size ())
|
||||
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.
|
||||
int limit = mRows;
|
||||
if (maximum != 0)
|
||||
limit = min (maximum, mRows);
|
||||
int limitrows = mRows;
|
||||
if (maxrows != 0)
|
||||
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.
|
||||
for (int row = 0; row < limit; ++row)
|
||||
for (int row = 0; row < limitrows; ++row)
|
||||
{
|
||||
std::vector <std::vector <std::string> > columns;
|
||||
std::vector <std::string> blanks;
|
||||
|
@ -1105,6 +1115,11 @@ const std::string Table::render (int maximum /* = 0 */)
|
|||
// Trim right.
|
||||
output.erase (output.find_last_not_of (" ") + 1);
|
||||
output += "\n";
|
||||
|
||||
++renderedlines;
|
||||
|
||||
if (maxlines != 0 && renderedlines >= maxlines)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1113,6 +1128,9 @@ const std::string Table::render (int maximum /* = 0 */)
|
|||
output.erase (output.find_last_not_of (" ") + 1);
|
||||
output += "\n";
|
||||
}
|
||||
|
||||
if (maxlines != 0 && renderedlines >= maxlines)
|
||||
break;
|
||||
}
|
||||
|
||||
optimize (output);
|
||||
|
|
|
@ -92,7 +92,7 @@ public:
|
|||
|
||||
int rowCount ();
|
||||
int columnCount ();
|
||||
const std::string render (int maximum = 0);
|
||||
const std::string render (int maxrows = 0, int maxlines = 0);
|
||||
|
||||
private:
|
||||
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 "
|
||||
"import.synonym.id import.synonym.uuid complete.all.projects "
|
||||
"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
|
||||
"shell.prompt "
|
||||
#endif
|
||||
|
@ -735,7 +735,7 @@ int handleShow (std::string &outs)
|
|||
|
||||
out << std::endl
|
||||
<< table.render ()
|
||||
<< (table.rowCount () == 0 ? "No matching configuration variables\n" : "")
|
||||
<< (table.rowCount () == 0 ? "No matching configuration variables\n" : "")
|
||||
<< std::endl;
|
||||
|
||||
// Display the unrecognized variables.
|
||||
|
|
|
@ -715,23 +715,37 @@ int runCustomReport (
|
|||
table.setTableAlternateColor (alternate);
|
||||
}
|
||||
|
||||
// Limit the number of rows according to the report definition.
|
||||
int maximum = context.config.getInteger (std::string ("report.") + report + ".limit");
|
||||
// Report output can be limited by rows or lines.
|
||||
int maxrows = 0;
|
||||
int maxlines = 0;
|
||||
getLimits (report, maxrows, maxlines);
|
||||
|
||||
// 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"))
|
||||
maximum = atoi (context.task.get ("limit").c_str ());
|
||||
// Adjust for fluff in the output.
|
||||
if (maxlines)
|
||||
maxlines -= (context.config.getBoolean ("blanklines") ? 2 : 0)
|
||||
+ 1
|
||||
+ context.headers.size ()
|
||||
+ context.footnotes.size ();
|
||||
|
||||
std::stringstream out;
|
||||
if (table.rowCount ())
|
||||
{
|
||||
out << optionalBlankLine ()
|
||||
<< table.render (maximum)
|
||||
<< table.render (maxrows, maxlines)
|
||||
<< optionalBlankLine ()
|
||||
<< table.rowCount ()
|
||||
<< (table.rowCount () == 1 ? " task" : " tasks")
|
||||
<< std::endl;
|
||||
else {
|
||||
<< (table.rowCount () == 1 ? " task" : " tasks");
|
||||
|
||||
if (maxrows)
|
||||
out << ", " << maxrows << " shown";
|
||||
|
||||
if (maxlines)
|
||||
out << ", truncated to " << maxlines-1 << " lines";
|
||||
|
||||
out << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
out << "No matches."
|
||||
<< std::endl;
|
||||
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&);
|
||||
void validReportColumns (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
|
||||
void initializeColorRules ();
|
||||
|
|
|
@ -283,7 +283,7 @@ int longUsage (std::string &outs)
|
|||
<< " until: Recurrence end date" << "\n"
|
||||
<< " fg: Foreground 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"
|
||||
<< "\n"
|
||||
<< "Attribute modifiers improve filters. Supported modifiers are:" << "\n"
|
||||
|
@ -2318,6 +2318,7 @@ int handleReportCalendar (std::string &outs)
|
|||
holTable.addCell (row, 1, holName);
|
||||
}
|
||||
}
|
||||
|
||||
out << optionalBlankLine ()
|
||||
<< holTable.render ()
|
||||
<< 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