1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
|
/* ====================================================================
* 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;
}
}
}
|