[Aptitude-svn-commit] r3433 - in branches/aptitude-0.3/aptitude: . src/vscreen

Daniel Burrows dburrows@costa.debian.org
Sat, 25 Jun 2005 20:29:22 +0000


Author: dburrows
Date: Sat Jun 25 20:29:20 2005
New Revision: 3433

Modified:
   branches/aptitude-0.3/aptitude/ChangeLog
   branches/aptitude-0.3/aptitude/src/vscreen/fragment.cc
Log:
Rewrite the main flow algorithm to handle wide characters.

Modified: branches/aptitude-0.3/aptitude/ChangeLog
==============================================================================
--- branches/aptitude-0.3/aptitude/ChangeLog	(original)
+++ branches/aptitude-0.3/aptitude/ChangeLog	Sat Jun 25 20:29:20 2005
@@ -1,5 +1,10 @@
 2005-06-25  Daniel Burrows  <dburrows@debian.org>
 
+	* src/vscreen/fragment.cc:
+
+	  Rewrite the main flow algorithm to handle wide characters (i.e.,
+	  separate the concepts of "visible width" and "character count").
+
 	* src/vscreen/columnify.cc, src/vscren/columnify.h, src/vscreen/config/column_definition.cc, src/vscreen/config/column_definition.h:
 
 	  Rewrite the columnification code to handle wide characters

Modified: branches/aptitude-0.3/aptitude/src/vscreen/fragment.cc
==============================================================================
--- branches/aptitude-0.3/aptitude/src/vscreen/fragment.cc	(original)
+++ branches/aptitude-0.3/aptitude/src/vscreen/fragment.cc	Sat Jun 25 20:29:20 2005
@@ -38,13 +38,13 @@
   size_t max_width(size_t first_indent,
 		   size_t rest_indent) const
   {
-    return first_indent+s.size();
+    return first_indent+wcswidth(s.c_str(), s.size());
   }
 
   size_t trailing_width(size_t first_indent,
 			size_t rest_indent) const
   {
-    return first_indent+s.size();
+    return first_indent+wcswidth(s.c_str(), s.size());
   }
 
   bool final_newline() const
@@ -258,15 +258,15 @@
 	  firstw=restw;
 	else if(lines.size()>0)
 	  {
-	    size_t deduct_from;
+	    int deduct_from;
 
 	    if(lines.size()==1)
 	      deduct_from=firstw;
 	    else
 	      deduct_from=restw;
 
-	    if(deduct_from>=lines.back().size())
-	      firstw=deduct_from-lines.back().size();
+	    if(deduct_from>=lines.back().width())
+	      firstw=deduct_from-lines.back().width();
 	    else
 	      firstw=0;
 	  }
@@ -433,39 +433,83 @@
 
 	    // If there are few enough characters to fit on a single
 	    // line, do that.
-	    if(s.size()-first<=firstw)
+	    fragment_line maybe_curr(s, first, s.size()-first);
+	    if(maybe_curr.width()<=(signed) firstw)
 	      {
-		rval.push_back(fragment_line(s, first, s.size()-first));
+		rval.push_back(maybe_curr);
 		firstw=restw;
 		first=s.size();
 		output_something=true;
 	      }
 	    else
 	      {
-		size_t amt=firstw;
+		int chunkw=0;
+		size_t chars=0;
+		while(chunkw<(signed) firstw && chars+first<s.size())
+		  {
+		    chunkw+=wcwidth(s[first+chars].ch);
+		    ++chars;
+		  }
 
-		while(amt>0 && !iswspace(s[first+amt].ch))
-		  --amt;
+		// Save this for later (see below).  Note that if we
+		// actually overshot the width goal, we need to
+		// possibly strip the last character off (it's
+		// guaranteed to be only one since otherwise we'd have
+		// stopped sooner...)
+		const size_t high_water_mark=chars;
+		const int high_water_width=chunkw;
+
+		// We pushed the line as far as possible; back up
+		// until we are no longer in the middle of a word AND
+		// the string is short enough.  (we know it's not at
+		// the end of the whole string because of the earlier
+		// test)
+		while(chars>0 && (chunkw>(signed) firstw ||
+				  !iswspace(s[first+chars].ch)))
+		  {
+		    --chars;
+		    chunkw-=wcwidth(s[first+chars].ch);
+		  }
 
-		// Oops, there's a word that's longer than the current line.
-		if(amt==0)
+		if(chars==0)
 		  {
-		    rval.push_back(fragment_line(s, first, firstw));
-		    first+=firstw;
+		    // Oops, there's a word that's longer than the
+		    // current line.  Push as much as fits onto the
+		    // current line.
+
+		    // First, try to exclude any characters that
+		    // overlap the right margin.
+		    chars=high_water_mark;
+		    chunkw=high_water_width;
+		    while(chars>0 && chunkw>(signed) firstw)
+		      {
+			--chars;
+			chunkw-=wcwidth(s[first+chars].ch);
+		      }
+
+		    // If even that's impossible, go ahead and push a
+		    // single character onto the end.  Note that this
+		    // means we're probably in such a tiny space that
+		    // the result will suck no matter what..
+		    if(chars==0)
+		      chars=1;
+
+		    rval.push_back(fragment_line(s, first, chars));
+		    first+=chars;
 		    firstw=restw;
 		    output_something=true;
 		  }
 		else
 		  {
-		    // Eh, strip trailing whitespace.
-		    while(amt>0 &&
-			  isspace(s[first+amt].ch) &&
-			  isspace(s[first+amt-1].ch))
-		      --amt;
+		    // Strip trailing whitespace, then `output' the
+		    // line.
+		    while(chars>0 &&
+			  iswspace(s[first+chars-1].ch))
+		      --chars;
 
-		    rval.push_back(fragment_line(s, first, amt));
+		    rval.push_back(fragment_line(s, first, chars));
 		    firstw=restw;
-		    first+=amt;
+		    first+=chars;
 		    output_something=true;
 		  }
 	      }