Bug #804 - URL link and break line

- Addressed bug #804 by allowing rc.hyphenate to control whether hyphens are
  inserted when long lines are broken.  This may help prevent xterm from
  mis-parsing URLs in task annotations, when wrapped (thanks to Yann Davin).
- Added unit tests.
This commit is contained in:
Paul Beckingham 2011-08-17 22:39:28 -04:00
parent 08fcb5362e
commit 7dd3e081c7
20 changed files with 147 additions and 28 deletions

View file

@ -105,4 +105,5 @@ suggestions:
Wim Schuermann
Tom Duffy
Miguel de Val Borro
Yann Davin

View file

@ -162,6 +162,9 @@
(thanks to Bryce Harrington).
+ Applied patch for #803, allowing rc.confirmation to bypass confirmation of
the deletion of a recurring task (thanks to Matt Kraai).
+ Addressed bug #804 by allowing rc.hyphenate to control whether hyphens are
inserted when long lines are broken. This may help prevent xterm from
mis-parsing URLs in task annotations, when wrapped (thanks to Yann Davin).
+ Fixed bug #807, which caused a lack of Lua to prevent tests from building
(thanks to Owen Clarke).
+ Fixed bug #808, which generated compiler warnings on Solarix (thanks to

2
NEWS
View file

@ -61,6 +61,8 @@ New configuration options in taskwarrior 2.0.0
- New 'color.completed' and 'color.deleted' color rules.
- New 'abbreviation.minimum' setting controls how short an abbreviated
command or value may be.
- New 'hyphenate' setting controls whether long lines are hyphenated when
broken during text-wrapping.
Newly deprecated features in taskwarrior 2.0.0

View file

@ -177,6 +177,10 @@ Causes the width of the terminal minus one to be used as the full width. This
avoids placing color codes in the last column which can cause problems for
Cygwin users. Default value is 'no'.
.TP
.B hyphenate=on
Hyphenates lines when wrapping breaks occur mid-word. Default value is 'on'.
.TP
.B editor=vi
Specifies which text editor you wish to use for when the

View file

@ -72,6 +72,7 @@ std::string Config::defaults =
"detection=on # Detects terminal width\n"
"defaultwidth=80 # Without detection, assumed width\n"
"avoidlastcolumn=no # Fixes Cygwin width problem\n"
"hyphenate=on # Hyphenates lines wrapped on non-word-breaks\n"
"#editor=vi # Preferred text editor\n"
"edit.verbose=yes # Include comments in files created during task edit\n"
"\n"

View file

@ -51,6 +51,8 @@ ColumnDepends::ColumnDepends ()
_examples.push_back ("1 2 10");
_examples.push_back ("[3]");
_examples.push_back (context.config.get ("dependency.indicator"));
_hyphenate = context.config.getBoolean ("hyphenate");
}
////////////////////////////////////////////////////////////////////////////////
@ -150,7 +152,7 @@ void ColumnDepends::render (
join (combined, " ", blocking_ids);
std::vector <std::string> all;
wrapText (all, combined, width);
wrapText (all, combined, width, _hyphenate);
std::vector <std::string>::iterator i;
for (i = all.begin (); i != all.end (); ++i)

View file

@ -46,6 +46,7 @@ public:
void render (std::vector <std::string>&, Task&, int, Color&);
private:
bool _hyphenate;
};
#endif

View file

@ -71,6 +71,8 @@ ColumnDescription::ColumnDescription ()
+ " " + t + " " + a4);
_examples.push_back (d.substr (0, 20) + "...");
_examples.push_back (d + " [4]");
_hyphenate = context.config.getBoolean ("hyphenate");
}
////////////////////////////////////////////////////////////////////////////////
@ -199,7 +201,7 @@ void ColumnDescription::render (
}
std::vector <std::string> raw;
wrapText (raw, description, width);
wrapText (raw, description, width, _hyphenate);
std::vector <std::string>::iterator i;
for (i = raw.begin (); i != raw.end (); ++i)
@ -210,7 +212,7 @@ void ColumnDescription::render (
else if (_style == "desc")
{
std::vector <std::string> raw;
wrapText (raw, description, width);
wrapText (raw, description, width, _hyphenate);
std::vector <std::string>::iterator i;
for (i = raw.begin (); i != raw.end (); ++i)
@ -237,7 +239,7 @@ void ColumnDescription::render (
}
std::vector <std::string> raw;
wrapText (raw, description, width);
wrapText (raw, description, width, _hyphenate);
std::vector <std::string>::iterator i;
for (i = raw.begin (); i != raw.end (); ++i)
@ -264,7 +266,7 @@ void ColumnDescription::render (
description += " [" + format ((int) annos.size ()) + "]";
std::vector <std::string> raw;
wrapText (raw, description, width);
wrapText (raw, description, width, _hyphenate);
std::vector <std::string>::iterator i;
for (i = raw.begin (); i != raw.end (); ++i)

View file

@ -45,6 +45,7 @@ public:
void render (std::vector <std::string>&, Task&, int, Color&);
private:
bool _hyphenate;
};
#endif

View file

@ -47,6 +47,8 @@ ColumnProject::ColumnProject ()
_examples.push_back (STRING_COLUMN_EXAMPLES_PROJ);
_examples.push_back (STRING_COLUMN_EXAMPLES_PAR);
_hyphenate = context.config.getBoolean ("hyphenate");
}
////////////////////////////////////////////////////////////////////////////////
@ -96,7 +98,7 @@ void ColumnProject::render (
}
std::vector <std::string> raw;
wrapText (raw, project, width);
wrapText (raw, project, width, _hyphenate);
std::vector <std::string>::iterator i;
for (i = raw.begin (); i != raw.end (); ++i)

View file

@ -45,6 +45,7 @@ public:
void render (std::vector <std::string>&, Task&, int, Color&);
private:
bool _hyphenate;
};
#endif

View file

@ -51,6 +51,8 @@ ColumnString::ColumnString ()
_styles.push_back (" Hello (wrapped)");
_styles.push_back ("Hello (no-wrap) ");
_styles.push_back (" Hello (no-wrap)");
_hyphenate = context.config.getBoolean ("hyphenate");
}
////////////////////////////////////////////////////////////////////////////////
@ -96,7 +98,7 @@ void ColumnString::render (
if (_style == "default" || _style == "left")
{
std::vector <std::string> raw;
wrapText (raw, value, width);
wrapText (raw, value, width, _hyphenate);
std::vector <std::string>::iterator i;
for (i = raw.begin (); i != raw.end (); ++i)
@ -105,7 +107,7 @@ void ColumnString::render (
else if (_style == "right")
{
std::vector <std::string> raw;
wrapText (raw, value, width);
wrapText (raw, value, width, _hyphenate);
std::vector <std::string>::iterator i;
for (i = raw.begin (); i != raw.end (); ++i)

View file

@ -45,6 +45,7 @@ public:
void render (std::vector <std::string>&, const std::string&, int, Color&);
private:
bool _hyphenate;
};
#endif

View file

@ -50,6 +50,8 @@ ColumnTags::ColumnTags ()
_examples.push_back (STRING_COLUMN_EXAMPLES_TAGS);
_examples.push_back (context.config.get ("tag.indicator"));
_examples.push_back ("[2]");
_hyphenate = context.config.getBoolean ("hyphenate");
}
////////////////////////////////////////////////////////////////////////////////
@ -136,7 +138,7 @@ void ColumnTags::render (
{
std::replace (tags.begin (), tags.end (), ',', ' ');
std::vector <std::string> all;
wrapText (all, tags, width);
wrapText (all, tags, width, _hyphenate);
std::vector <std::string>::iterator i;
for (i = all.begin (); i != all.end (); ++i)

View file

@ -46,6 +46,7 @@ public:
void render (std::vector <std::string>&, Task&, int, Color&);
private:
bool _hyphenate;
};
#endif

View file

@ -151,6 +151,7 @@ int CmdShow::execute (std::string& output)
" extensions"
" fontunderline"
" gc"
" hyphenate"
" import.synonym.bg"
" import.synonym.description"
" import.synonym.due"

View file

@ -52,7 +52,8 @@ static void replace_positional (std::string&, const std::string&, const std::str
void wrapText (
std::vector <std::string>& lines,
const std::string& text,
const int width)
const int width,
bool hyphenate)
{
std::string copy = text;
std::string line;
@ -61,7 +62,7 @@ void wrapText (
while (copy.length ()) // Used as Boolean, therefore UTF8 safe.
{
extractLine (copy, line, modified_width);
extractLine (copy, line, modified_width, hyphenate);
lines.push_back (line);
}
}
@ -316,7 +317,11 @@ int longestLine (const std::string& input)
}
////////////////////////////////////////////////////////////////////////////////
void extractLine (std::string& text, std::string& line, int length)
void extractLine (
std::string& text,
std::string& line,
int length,
bool hyphenate)
{
size_t eol = text.find ("\n");
@ -356,8 +361,16 @@ void extractLine (std::string& text, std::string& line, int length)
{
if (length > 1)
{
line = text.substr (0, length - 1) + "-";
text = text.substr (length - 1);
if (hyphenate)
{
line = text.substr (0, length - 1) + "-";
text = text.substr (length - 1);
}
else
{
line = text.substr (0, length);
text = text.substr (length);
}
}
else
{

View file

@ -33,14 +33,14 @@
#include <cmake.h>
// text.cpp, Non-UTF-8 aware.
void wrapText (std::vector <std::string>&, const std::string&, const int);
void wrapText (std::vector <std::string>&, const std::string&, const int, bool);
std::string trimLeft (const std::string& in, const std::string& t = " ");
std::string trimRight (const std::string& in, const std::string& t = " ");
std::string trim (const std::string& in, const std::string& t = " ");
std::string unquoteText (const std::string&);
int longestWord (const std::string&);
int longestLine (const std::string&);
void extractLine (std::string&, std::string&, int);
void extractLine (std::string&, std::string&, int, bool);
void splitq (std::vector<std::string>&, const std::string&, const char);
void split (std::vector<std::string>&, const std::string&, const char);
void split (std::vector<std::string>&, const std::string&, const std::string&);

79
test/bug.804.t Executable file
View file

@ -0,0 +1,79 @@
#! /usr/bin/perl
################################################################################
## taskwarrior - a command line task list manager.
##
## Copyright 2006 - 2011, Paul Beckingham, Federico Hernandez.
## 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 => 11;
# Create the rc file.
if (open my $fh, '>', 'bug.rc')
{
print $fh "data.location=.\n";
print $fh "bulk=100\n";
print $fh "confirmation=no\n";
close $fh;
ok (-r 'bug.rc', 'Created bug.rc');
}
# Bug 804: URL link and break line
# Setup: Add a tasks, annotate with long word.
qx{../src/task rc:bug.rc add One};
qx{../src/task rc:bug.rc 1 annotate abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz};
# List with rc.hyphenate=on.
my $output = qx{../src/task rc:bug.rc rc.defaultwidth:40 rc.hyphenate:on ls};
like ($output, qr/vwx-$/ms, 'hyphenated 1');
like ($output, qr/tuv-$/ms, 'hyphenated 2');
# List with rc.hyphenate=off.
$output = qx{../src/task rc:bug.rc rc.defaultwidth:40 rc.hyphenate:off ls};
like ($output, qr/vwxy$/ms, 'not hyphenated 1');
like ($output, qr/uvwx$/ms, 'not hyphenated 2');
# Cleanup.
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
unlink 'completed.data';
ok (!-r 'completed.data', 'Removed completed.data');
unlink 'undo.data';
ok (!-r 'undo.data', 'Removed undo.data');
unlink 'backlog.data';
ok (!-r 'backlog.data', 'Removed backlog.data');
unlink 'synch.key';
ok (!-r 'synch.key', 'Removed synch.key');
unlink 'bug.rc';
ok (!-r 'bug.rc', 'Removed bug.rc');
exit 0;

View file

@ -37,10 +37,10 @@ int main (int argc, char** argv)
{
UnitTest t (262);
// void wrapText (std::vector <std::string>& lines, const std::string& text, const int width)
// void wrapText (std::vector <std::string>& lines, const std::string& text, const int width, bool hyphenate)
std::string text = "This is a test of the line wrapping code.";
std::vector <std::string> lines;
wrapText (lines, text, 10);
wrapText (lines, text, 10, true);
t.is (lines.size (), (size_t) 5, "wrapText 'This is a test of the line wrapping code.' -> total 5 lines");
t.is (lines[0], "This is a", "wrapText line 0 -> 'This is a'");
t.is (lines[1], "test of", "wrapText line 1 -> 'test of'");
@ -51,7 +51,7 @@ int main (int argc, char** argv)
// void wrapText (std::vector <std::string>& lines, const std::string& text, const int width)
text = "This ☺ is a test of utf8 line extraction.";
lines.clear ();
wrapText (lines, text, 7);
wrapText (lines, text, 7, true);
t.is (lines.size (), (size_t) 7, "wrapText 'This ☺ is a test of utf8 line extraction.' -> total 7 lines");
t.is (lines[0], "This ☺", "wrapText line 0 -> 'This ☺'");
t.is (lines[1], "is a", "wrapText line 1 -> 'is a'");
@ -61,33 +61,33 @@ int main (int argc, char** argv)
t.is (lines[5], "extrac-", "wrapText line 5 -> 'extrac-'");
t.is (lines[6], "tion.", "wrapText line 6 -> 'tion.'");
// void extractLine (std::string& text, std::string& line, int length)
// void extractLine (std::string& text, std::string& line, int length, bool hyphenate)
text = "This ☺ is a test of utf8 line extraction.";
std::string line;
extractLine (text, line, 7);
extractLine (text, line, 7, true);
t.is (line, "line 1", "extractLine 7 'This ☺ is a test of utf8 line extraction.' -> 'This ☺'");
// void extractLine (std::string& text, std::string& line, int length)
text = "line 1\nlengthy second line that exceeds width";
extractLine (text, line, 10);
extractLine (text, line, 10, true);
t.is (line, "line 1", "extractLine 10 'line 1\\nlengthy second line that exceeds width' -> 'line 1'");
extractLine (text, line, 10);
extractLine (text, line, 10, true);
t.is (line, "lengthy", "extractLine 10 'lengthy second line that exceeds width' -> 'lengthy'");
extractLine (text, line, 10);
extractLine (text, line, 10, true);
t.is (line, "second", "extractLine 10 'second line that exceeds width' -> 'second'");
extractLine (text, line, 10);
extractLine (text, line, 10, true);
t.is (line, "line that", "extractLine 10 'line that exceeds width' -> 'line that'");
extractLine (text, line, 10);
extractLine (text, line, 10, true);
t.is (line, "exceeds", "extractLine 10 'exceeds width' -> 'exceeds'");
extractLine (text, line, 10);
extractLine (text, line, 10, true);
t.is (line, "width", "extractLine 10 'width' -> 'width'");
extractLine (text, line, 10);
extractLine (text, line, 10, true);
t.is (line, "", "extractLine 10 '' -> ''");
// void split (std::vector<std::string>& results, const std::string& input, const char delimiter)