/* ====================================================================
* Copyright (c) 2003-2006, Martin Hauner
* http://subcommander.tigris.org
*
* Subcommander is licensed as described in the file doc/COPYING, which
* you should have received as part of this distribution.
* ====================================================================
*/
// sc
#include "PaintLineFactory.h"
#include "PaintLine.h"
#include "LineConfig.h"
#include "Tab.h"
#include "util/String.h"
#include "util/Char.h"
#include "util/utf8.h"
const PaintLine* PaintLineFactory::create( const sc::String& source,
int leftCol, int rightCol, const LineConfig& cfg )
{
// we use cols here to have enough space for tabs.
// each column can contain a 4 byte utf character.
// plus 1 byte for the end marker.
Tab tab(cfg.getTabWidth());
// return/linefeed doesn't count as column, so add 1
unsigned int cols = tab.calcColumns( source ) + 1;
#if 0
// safety check, always return a "valid" PaintLine
if( cols == 0 )
{
PaintLine::Kind* kind = new PaintLine::Kind[2];
kind[0] = PaintLine::Whitespace;
kind[1] = PaintLine::End;
return new PaintLine( source, sc::String("?"), kind );
}
#endif
const char* src = source;
char* buf = new char[cols*4+2];
PaintLine::Kind* kind = new PaintLine::Kind[cols*4+2];
int ccol = 0; // column
int cbyte = 0; // byte offset
while( src && *src )
{
int addedbytes = 0;
int addedcols = addChar( src, buf+cbyte, ccol, &addedbytes, cfg );
bool whitespace = sc::Char::isWhitespace(*src);
for( int i = 0; i < addedbytes; i++ )
{
if( ccol >= leftCol && ccol < rightCol )
{
// highlighted
kind[cbyte+i] = whitespace ? PaintLine::WhitespaceHL : PaintLine::CharacterHL;
}
else
{
// normal
kind[cbyte+i] = whitespace ? PaintLine::Whitespace : PaintLine::Character;
}
}
ccol += addedcols;
cbyte += addedbytes;
src = utf8::next8(src);
}
buf[cbyte] = 0;
kind[cbyte] = PaintLine::End;
sc::String bufstr(buf);
delete [] buf;
return new PaintLine( source, bufstr, kind );
}
/**
* \brief add char from in to out and translate tabs and whitespaces.
*
* \param in source string.
* \param out destination string.
* \param col current column. col is needed for tab handling.
* \param bytes number of bytes copied from in to out.
* \param cfg the line configuration.
* \return number of columns copied.
*/
int PaintLineFactory::addChar( const char* in, char* out, int col, int* bytes,
const LineConfig& cfg )
{
switch( *in )
{
case ' ':
{
if( cfg.isVisibleSpace() )
{
out[0] = cfg.getCharSpace();
}
else
{
out[0] = *in;
}
*bytes = 1;
return 1;
}
case '\t':
{
if( cfg.isVisibleTab() )
{
out[0] = cfg.getCharTab();
}
else
{
out[0] = ' ';
}
int retval = 1;
for( int t = 1; (col+t)%cfg.getTabWidth() != 0; t++ )
{
out[t] = ' ';
retval++;
}
*bytes = retval;
return retval;
}
case '\r':
{
if( cfg.isVisibleCariageReturn() )
{
out[0] = cfg.getCharCariageReturn();
*bytes = 1;
return 1;
}
*bytes = 0;
return 0;
}
case '\n':
{
if( cfg.isVisibleLineFeed() )
{
out[0] = cfg.getCharLineFeed();
*bytes = 1;
return 1;
}
*bytes = 0;
return 0;
}
default:
{
const char* n = utf8::next8( in );
int i = 0;
for( /*i*/; in+i < n; i++ )
{
out[i] = in[i];
}
*bytes = i;
return 1;
}
}
}
syntax highlighted by Code2HTML, v. 0.9.1