1
0
forked from Alepha/Alepha

Progress towards a word-wrap stream helper.

This commit is contained in:
2023-10-13 05:26:17 -04:00
parent 76940b2cb2
commit 046cf6d43f
3 changed files with 114 additions and 18 deletions

View File

@ -6,6 +6,8 @@ static_assert( __cplusplus > 2020 );
#include <tuple>
#include <iostream>
#include <iterator>
#include <sstream>
#include "evaluation_helpers.h"
@ -15,7 +17,7 @@ namespace Alepha::Cavorite ::detail:: word_wrap
{
// Returns the number of chars in the line just written to.
std::size_t
applyWordToLine( const std::size_t maximumWidth, const std::size_t nextLineOffset, const std::size_t currentLineWidth, std::string &&word, std::string &result )
applyWordToLine( const std::size_t maximumWidth, const std::size_t nextLineOffset, const std::size_t currentLineWidth, std::string &&word, std::ostream &result )
{
if( word.empty() ) return currentLineWidth;
@ -23,25 +25,67 @@ namespace Alepha::Cavorite ::detail:: word_wrap
{
if( currentLineWidth + word.size() > maximumWidth )
{
result+= '\n';
std::fill_n( back_inserter( result ), nextLineOffset, ' ' );
result << "\n";
std::fill_n( std::ostream_iterator< char >( result ), nextLineOffset, ' ' );
return nextLineOffset;
}
else return currentLineWidth;
};
const auto rv= lineWidth + word.size();
result+= std::move( word );
result << std::move( word );
return rv;
}
}
void
WordWrapStreambuf::writeChar( const char ch )
{
std::ostream outWrap{ underlying };
if( ch == '\n' )
{
const auto prev= currentLineLength;
const auto size= currentWord.size();
currentLineLength= applyWordToLine( maximumWidth, nextLineOffset, currentLineLength, std::move( currentWord ), outWrap );
currentWord.clear();
outWrap << '\n';
if( currentLineLength == prev + size )
{
std::fill_n( std::ostream_iterator< char >{ outWrap }, nextLineOffset, ' ' );
currentLineLength= nextLineOffset;
}
else currentLineLength= 0;
}
else if( ch == ' ' )
{
currentLineLength= applyWordToLine( maximumWidth, nextLineOffset, currentLineLength, std::move( currentWord ), outWrap );
currentWord.clear();
if( currentLineLength < maximumWidth )
{
outWrap << ' ';
++currentLineLength;
}
}
else currentWord+= ch;
}
void
WordWrapStreambuf::drain()
{
if( currentWord.empty() ) return;
std::ostream outWrap{ underlying };
applyWordToLine( maximumWidth, nextLineOffset, currentLineLength, std::move( currentWord ), outWrap );
}
std::string
exports::wordWrap( const std::string &text, const std::size_t width, const std::size_t nextLineOffset )
{
#if NEVER
auto putWord= [width, nextLineOffset]( std::string &&word, std::string &line, const std::size_t lineLength )
{
const auto rv= applyWordToLine( width, nextLineOffset, lineLength, std::move( word ), line );
std::ostringstream out;
const auto rv= applyWordToLine( width, nextLineOffset, lineLength, std::move( word ), out );
line+= std::move( out ).str();
return rv;
};
@ -78,5 +122,20 @@ namespace Alepha::Cavorite ::detail:: word_wrap
}
if( not word.empty() ) std::ignore= putWord( std::move( word ), result, lineLength );
return result;
#else
std::ostringstream oss;
WordWrapStreambuf buf;
buf.maximumWidth= width;
buf.nextLineOffset= nextLineOffset;
buf.underlying= static_cast< std::ostream & >( oss ).rdbuf();
static_cast< std::ostream & >( oss ).rdbuf( &buf );
oss << text;
buf.drain();
auto rv= std::move( oss ).str();
return rv;
#endif
}
}

View File

@ -5,13 +5,50 @@ static_assert( __cplusplus > 2020'00 );
#include <cstddef>
#include <string>
#include <streambuf>
namespace Alepha::inline Cavorite ::detail:: word_wrap
{
inline namespace exports
{
std::string wordWrap( const std::string &text, std::size_t width, std::size_t nextLineOffset= 0 );
class WordWrapStreambuf;
}
class exports::WordWrapStreambuf
: public std::streambuf
{
public:
std::streambuf *underlying= nullptr;
std::size_t maximumWidth= 0;
std::size_t nextLineOffset= 0;
std::size_t currentLineLength= 0;
std::string currentWord;
void writeChar( const char ch );
void drain();
public:
int
overflow( const int ch ) override
{
if( ch == EOF ) throw std::logic_error( "EOF!" );
writeChar( ch );
return 1;
}
std::streamsize
xsputn( const char *const data, const std::streamsize amt ) override
{
for( std::streamsize i= 0; i< amt; ++i ) overflow( data[ i ] );
return amt;
}
};
}
namespace Alepha::Cavorite::inline exports::inline word_wrap

View File

@ -91,19 +91,19 @@ static auto init= Alepha::Utility::enroll <=[]
},
{ "wider terminal, complex text: Hamlet's \"To Be or Not To Be\"",
{
"To be, or not to be: "
"that is the question: "
"Whether 'tis nobler in the mind to suffer "
"The slings and arrows of outrageous fortune, "
"Or to take arms against a sea of troubles, "
"And by opposing end them? "
"To die: to sleep; "
"No more; and by a sleep to say we end "
"The heart-ache and the thousand natural shocks "
"That flesh is heir to, 'tis a consummation "
"Devoutly to be wish'd. To die, to sleep; "
"To sleep: perchance to dream: ay, there's the rub;",
80, 0
"To be, or not to be: "
"that is the question: "
"Whether 'tis nobler in the mind to suffer "
"The slings and arrows of outrageous fortune, "
"Or to take arms against a sea of troubles, "
"And by opposing end them? "
"To die: to sleep; "
"No more; and by a sleep to say we end "
"The heart-ache and the thousand natural shocks "
"That flesh is heir to, 'tis a consummation "
"Devoutly to be wish'd. To die, to sleep; "
"To sleep: perchance to dream: ay, there's the rub;",
80, 0
},
"To be, or not to be: that is the question: Whether 'tis nobler in the mind to \n"
"suffer The slings and arrows of outrageous fortune, Or to take arms against a \n"