Add support for unicode surrogate characters to Kate/KWrite

Signed-off-by: Michele Calgaro <michele.calgaro@yahoo.it>
pull/340/head
Michele Calgaro 5 months ago
parent b56e68eac7
commit 1aa4271c12
Signed by: MicheleC
GPG Key ID: 2A75B7CA8ADED5CF

@ -2411,7 +2411,7 @@ bool KateDocument::openFile(TDEIO::Job * job)
// read dir config (if possible and wanted)
if (!m_reloading)
readDirConfig ();
readDirConfig ();
// do we have success ?
bool success = m_buffer->openFile (m_file);
@ -3135,15 +3135,27 @@ void KateDocument::backspace( KateView *view, const KateTextCursor& c )
if ((col == 0) && (line == 0))
return;
KateTextLine::Ptr tl = m_buffer->plainLine(line);
if (!tl)
{
return;
}
// Make sure to handle surrogate pairs correctly
uint fromCol = col - 1;
TQChar prevChar = tl->getChar(col - 1);
if (prevChar.isLowSurrogate() && tl->getChar(col - 2).isHighSurrogate())
{
fromCol = col - 2;
prevChar = tl->getChar(col - 2);
}
int complement = 0;
if (col > 0)
{
if (config()->configFlags() & KateDocument::cfAutoBrackets)
{
// if inside empty (), {}, [], '', "" delete both
KateTextLine::Ptr tl = m_buffer->plainLine(line);
if(!tl) return;
TQChar prevChar = tl->getChar(col-1);
TQChar nextChar = tl->getChar(col);
if ( (prevChar == '"' && nextChar == '"') ||
@ -3158,8 +3170,7 @@ void KateDocument::backspace( KateView *view, const KateTextCursor& c )
if (!(config()->configFlags() & KateDocument::cfBackspaceIndents))
{
// ordinary backspace
//c.cursor.col--;
removeText(line, col-1, line, col+complement);
removeText(line, fromCol, line, col+complement);
}
else
{
@ -3215,9 +3226,23 @@ void KateDocument::del( KateView *view, const KateTextCursor& c )
return;
}
if( c.col() < (int) m_buffer->plainLine(c.line())->length())
KateTextLine::Ptr tl = m_buffer->plainLine(c.line());
if (!tl)
{
removeText(c.line(), c.col(), c.line(), c.col()+1);
return;
}
uint lineLen = tl->length();
uint col = (uint)c.col();
if (col < lineLen)
{
// Make sure to handle surrogate pairs correctly
uint toCol = col + 1;
if (tl->getChar(col).isHighSurrogate() && tl->getChar(col + 1).isLowSurrogate())
{
toCol = col + 2;
}
removeText(c.line(), col, c.line(), toCol);
}
else if ( (uint)c.line() < lastLine() )
{

@ -400,7 +400,7 @@ void KateRenderer::paintTextLine(TQPainter& paint, const KateLineRange* range, i
uint nextCol = curCol + 1;
// text + attrib data from line
const uchar *textAttributes = textLine->attributes ();
const uchar *textAttributes = textLine->attributes();
bool noAttribs = !textAttributes;
// adjust to startcol ;)
@ -421,26 +421,29 @@ void KateRenderer::paintTextLine(TQPainter& paint, const KateLineRange* range, i
while (curCol - startcol < len)
{
const TQString &textString = textLine->string();
int currCharNumCols = textString[curCol].isHighSurrogate() ? 2 : 1;
nextCol = curCol + currCharNumCols;
// make sure curPos is updated correctly.
// ### if uncommented, causes an O(n^2) behaviour
//Q_ASSERT(curPos == textLine->cursorX(curCol, m_tabWidth));
TQChar curChar = textLine->string()[curCol];
// Decide if this character is a tab - we treat the spacing differently
// TODO: move tab width calculation elsewhere?
bool isTab = curChar == TQChar('\t');
bool isTab = textString[curCol] == TQChar('\t');
// Determine current syntax highlighting attribute
// A bit legacy but doesn't need to change
KateAttribute* curAt = (noAttribs || ((*textAttributes) >= atLen)) ? &attr[0] : &attr[*textAttributes];
// X position calculation. Incorrect for fonts with non-zero leftBearing() and rightBearing() results.
// TODO: make internal charWidth() function, use TQFontMetrics::charWidth().
xPosAfter += curAt->width(*fs, curChar, m_tabWidth);
// TODO: make internal charWidth() function.
xPosAfter += curAt->width(*fs, textString, curCol, m_tabWidth);
// Tab special treatment, move to charWidth().
if (isTab)
xPosAfter -= (xPosAfter % curAt->width(*fs, curChar, m_tabWidth));
xPosAfter -= (xPosAfter % curAt->width(*fs, textString[curCol], m_tabWidth));
// Only draw after the starting X value
// Haha, this was always wrong, due to the use of individual char width calculations...?? :(
@ -459,7 +462,9 @@ void KateRenderer::paintTextLine(TQPainter& paint, const KateLineRange* range, i
curColor = isSel ? &(curAt->selectedTextColor()) : &(curAt->textColor());
// Incorporate in arbitrary highlighting
if (curAt != oldAt || curColor != oldColor || (superRanges.count() && superRanges.currentBoundary() && *(superRanges.currentBoundary()) == currentPos)) {
if (curAt != oldAt || curColor != oldColor || (superRanges.count() &&
superRanges.currentBoundary() && *(superRanges.currentBoundary()) == currentPos))
{
if (superRanges.count() && superRanges.currentBoundary() && *(superRanges.currentBoundary()) == currentPos)
customHL = KateArbitraryHighlightRange::merge(superRanges.rangesIncluding(currentPos));
@ -495,10 +500,10 @@ void KateRenderer::paintTextLine(TQPainter& paint, const KateLineRange* range, i
|| (superRanges.count() && superRanges.currentBoundary() && *(superRanges.currentBoundary()) == KateTextCursor(line, nextCol))
// it is the end of the line OR
|| (curCol - startcol >= len - 1)
|| ((curCol - startcol) >= (len - currCharNumCols))
// the rest of the line is trailing whitespace OR
|| (curCol + 1 >= trailingWhitespaceColumn)
|| (nextCol >= trailingWhitespaceColumn)
// indentation lines OR
|| (showIndentLines() && curCol < lastIndentColumn)
@ -514,7 +519,7 @@ void KateRenderer::paintTextLine(TQPainter& paint, const KateLineRange* range, i
// the next char is a tab (removed the "and this isn't" because that's dealt with above)
// i.e. we have to draw the current text so the tab can be rendered as above.
|| (textLine->string()[nextCol] == TQChar('\t'))
|| (textString[nextCol] == TQChar('\t'))
// input method edit area
|| ( m_view && (isIMEdit != m_view->isIMEdit( line, nextCol )) )
@ -557,7 +562,7 @@ void KateRenderer::paintTextLine(TQPainter& paint, const KateLineRange* range, i
// If this is the last block of text, fill up to the end of the line if the
// selection stretches that far
if ((curCol >= len - 1) && m_view->lineEndSelected (line, endcol))
if (curCol >= (len - currCharNumCols) && m_view->lineEndSelected(line, endcol))
width = xEnd - oldXPos;
}
else
@ -632,7 +637,7 @@ void KateRenderer::paintTextLine(TQPainter& paint, const KateLineRange* range, i
else
{
// Here's where the money is...
paint.drawText(oldXPos-xStart, y, textLine->string(), blockStartCol, nextCol-blockStartCol);
paint.drawText(oldXPos-xStart, y, textString, blockStartCol, nextCol-blockStartCol);
// Draw preedit's underline
if (isIMEdit) {
@ -650,7 +655,6 @@ void KateRenderer::paintTextLine(TQPainter& paint, const KateLineRange* range, i
// variable advancement
blockStartCol = nextCol;
oldXPos = xPosAfter;
//oldS = s+1;
}
} // renderNow
@ -681,9 +685,8 @@ void KateRenderer::paintTextLine(TQPainter& paint, const KateLineRange* range, i
oldColor = curColor;
// col move
curCol++;
nextCol++;
currentPos.setCol(currentPos.col() + 1);
curCol += currCharNumCols;
currentPos.setCol(currentPos.col() + currCharNumCols);
// Update the current indentation pos.
if (isTab)
@ -756,8 +759,6 @@ uint KateRenderer::textWidth(const KateTextLine::Ptr &textLine, int cursorCol)
if (z < len) {
width = a->width(*fs, textString, z, m_tabWidth);
} else {
// DF: commented out. It happens all the time.
//Q_ASSERT(!m_doc->wrapCursor());
width = a->width(*fs, TQChar(' '), m_tabWidth);
}
@ -765,6 +766,11 @@ uint KateRenderer::textWidth(const KateTextLine::Ptr &textLine, int cursorCol)
if (z < len && unicode[z] == TQChar('\t'))
x -= x % width;
if (textString[z].isHighSurrogate())
{
++z;
}
}
return x;
@ -803,7 +809,11 @@ uint KateRenderer::textWidth(const KateTextLine::Ptr &textLine, uint startcol, u
if (unicode[z] == TQChar('\t'))
x -= x % width;
if (unicode[z].isSpace())
if (textString[z].isHighSurrogate())
{
++z;
}
else if (unicode[z].isSpace())
{
lastWhiteSpace = z+1;
lastWhiteSpaceX = x;
@ -876,7 +886,6 @@ uint KateRenderer::textWidth(const KateTextCursor &cursor)
uint KateRenderer::textWidth( KateTextCursor &cursor, int xPos, uint startCol)
{
bool wrapCursor = m_view->wrapCursor();
int x, oldX;
KateFontStruct *fs = config()->fontStruct();
@ -890,15 +899,17 @@ uint KateRenderer::textWidth( KateTextCursor &cursor, int xPos, uint startCol)
const TQChar *unicode = textLine->text();
const TQString &textString = textLine->string();
x = oldX = 0;
int x = 0;
int oldX = 0;
int oldZ = 0;
int width = 0;
uint z = startCol;
while (x < xPos && (!wrapCursor || z < len)) {
oldX = x;
oldZ = z;
KateAttribute* a = attribute(textLine->attribute(z));
int width = 0;
if (z < len)
width = a->width(*fs, textString, z, m_tabWidth);
else
@ -909,11 +920,11 @@ uint KateRenderer::textWidth( KateTextCursor &cursor, int xPos, uint startCol)
if (z < len && unicode[z] == TQChar('\t'))
x -= x % width;
z++;
z += textString[z].isHighSurrogate() ? 2 : 1;
}
if (xPos - oldX < x - xPos && z > 0) {
z--;
x = oldX;
z = oldZ;
}
cursor.setCol(z);
return x;
@ -942,23 +953,24 @@ uint KateRenderer::textPos(const KateTextLine::Ptr &textLine, int xPos, uint sta
KateFontStruct *fs = config()->fontStruct();
int x, oldX;
x = oldX = 0;
int x = 0;
int oldX = 0;
int oldZ = 0;
uint z = startCol;
const uint len = textLine->length();
const TQString &textString = textLine->string();
while ( (x < xPos) && (z < len)) {
oldX = x;
oldZ = z;
KateAttribute* a = attribute(textLine->attribute(z));
x += a->width(*fs, textString, z, m_tabWidth);
z++;
z += textString[z].isHighSurrogate() ? 2 : 1;
}
if ( ( (! nearest) || xPos - oldX < x - xPos ) && z > 0 ) {
z--;
z = oldZ;
// newXPos = oldX;
}// else newXPos = x;
return z;

@ -1091,11 +1091,44 @@ public:
void KateViewInternal::moveChar( Bias bias, bool sel )
{
if (bias == Bias::none)
{
return;
}
KateTextLine::Ptr tl = m_doc->m_buffer->plainLine(cursor.line());
if (!tl)
{
return;
}
// Make sure to handle surrogate pairs correctly
int offset = 0;
int col = cursor.col();
if (bias == Bias::left_b)
{
offset = -1;
if (tl->getChar(col - 1).isLowSurrogate() && tl->getChar(col - 2).isHighSurrogate())
{
offset = -2;
}
}
else
{
offset = 1;
if (tl->getChar(col).isHighSurrogate() && tl->getChar(col + 1).isLowSurrogate())
{
offset = 2;
}
}
KateTextCursor c;
if ( m_view->wrapCursor() ) {
c = WrappingCursor( this, cursor ) += bias;
} else {
c = BoundedCursor( this, cursor ) += bias;
if (m_view->wrapCursor())
{
c = WrappingCursor( this, cursor ) += offset;
} else
{
c = BoundedCursor( this, cursor ) += offset;
}
updateSelection( c, sel );

Loading…
Cancel
Save