/* ==================================================================== * 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; } } }