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) // read dir config (if possible and wanted)
if (!m_reloading) if (!m_reloading)
readDirConfig (); readDirConfig ();
// do we have success ? // do we have success ?
bool success = m_buffer->openFile (m_file); bool success = m_buffer->openFile (m_file);
@ -3135,15 +3135,27 @@ void KateDocument::backspace( KateView *view, const KateTextCursor& c )
if ((col == 0) && (line == 0)) if ((col == 0) && (line == 0))
return; 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; int complement = 0;
if (col > 0) if (col > 0)
{ {
if (config()->configFlags() & KateDocument::cfAutoBrackets) if (config()->configFlags() & KateDocument::cfAutoBrackets)
{ {
// if inside empty (), {}, [], '', "" delete both // 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); TQChar nextChar = tl->getChar(col);
if ( (prevChar == '"' && nextChar == '"') || if ( (prevChar == '"' && nextChar == '"') ||
@ -3158,8 +3170,7 @@ void KateDocument::backspace( KateView *view, const KateTextCursor& c )
if (!(config()->configFlags() & KateDocument::cfBackspaceIndents)) if (!(config()->configFlags() & KateDocument::cfBackspaceIndents))
{ {
// ordinary backspace // ordinary backspace
//c.cursor.col--; removeText(line, fromCol, line, col+complement);
removeText(line, col-1, line, col+complement);
} }
else else
{ {
@ -3215,9 +3226,23 @@ void KateDocument::del( KateView *view, const KateTextCursor& c )
return; 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() ) else if ( (uint)c.line() < lastLine() )
{ {

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

@ -1091,11 +1091,44 @@ public:
void KateViewInternal::moveChar( Bias bias, bool sel ) 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; KateTextCursor c;
if ( m_view->wrapCursor() ) { if (m_view->wrapCursor())
c = WrappingCursor( this, cursor ) += bias; {
} else { c = WrappingCursor( this, cursor ) += offset;
c = BoundedCursor( this, cursor ) += bias; } else
{
c = BoundedCursor( this, cursor ) += offset;
} }
updateSelection( c, sel ); updateSelection( c, sel );

Loading…
Cancel
Save