/* ==================================================================== * 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 "Tab.h" #include "util/utf8.h" /** * \brief construct a Tab object. * * \param tabWidth use tabwidth spaces for a single tab in the column * calculations. */ Tab::Tab( unsigned int tabWidth ) : _tabwidth(tabWidth) { } /** * \brief calc the number of columns in a string. * A CRLF counts as a single column. * * \param s an utf-8 encoded 0 terminated string. */ unsigned int Tab::calcColumns( const char* s ) { unsigned int chars = 0; if( ! s ) { return 0; } while( *s ) { if( *s == '\t' && (chars % _tabwidth == 0) ) { chars += _tabwidth; } else if( *s == '\r' || *s == '\n' ) { // on any line end marker we are done break; } else { chars += 1; } s = utf8::next8( s ); } return chars; } /** * \brief calc next column, on tab jump tabwidth. * A CRLF counts as a single column. * * \param s an utf-8 encoded 0 terminated string. * \param pos current column position. */ int Tab::calcColumnForNextChar( const char* s, int pos ) { int col = 0; if( ! s ) { return pos; } while( *s && col <= pos ) { if( *s == '\t' && (col % _tabwidth == 0) ) { col += _tabwidth; } else { col += 1; // on any line end marker we are done // next col is after end of line if( *s == '\r' || *s == '\n' ) { break; } } s = utf8::next8( s ); } return col; } /** * \brief calc prev column, on tab jump tabwidth. * A CRLF counts as a single column. * * \param s an utf-8 encoded 0 terminated string. * \param pos current column position. */ int Tab::calcColumnForPrevChar( const char* s, int pos ) { int col = 0; if( ! s ) { return pos; } while( *s && col < pos ) { int plus = 0; if( *s == '\t' && (col % _tabwidth == 0) ) { plus = _tabwidth; } else if( *s == '\r' || *s == '\n' ) { // shouldn't happen } else { plus = 1; } if( col + plus >= pos ) { break; } col += plus; s = utf8::next8( s ); } return col; } /** * \brief calc the character offset for the character at the given column. * A CRLF counts as a single column. * * \param s an utf-8 encoded 0 terminated string. * \param col the column for which we calculate the character offset. */ int Tab::calcCharOffsetForColumn( const char* s, int col ) { int pos = 0; int chr = 0; if( ! s ) { return pos; } while( *s && pos < col ) { if( *s == '\t' && (pos % _tabwidth == 0) ) { pos += _tabwidth; } else if( *s == '\r' || *s == '\n' ) { // shouldn't happen break; } else { pos += 1; } s = utf8::next8( s ); chr++; } return chr; } /** * \brief calc the nearest column position for the given column. * This is used if you click into the space of a tab to position * a cursor at the column where the tab begins or the tab ends. * * \param s an utf-8 encoded 0 terminated string. * \param col the column for which we calculate the new column. */ int Tab::calcColumnForColumn( const char* s, int col ) { int ncol = 0; if( ! s ) { return 0; } while( *s && ncol <= col ) { int add = 0; if( *s == '\t' && (ncol % _tabwidth == 0) ) { add = _tabwidth; } else if( *s == '\r' || *s == '\n' ) { // count CRLF as one column } else { add = 1; } if( ncol + add > col ) { break; } ncol += add; s = utf8::next8( s ); } return ncol; }