diff options
Diffstat (limited to 'src/Editor.cxx')
-rw-r--r-- | src/Editor.cxx | 261 |
1 files changed, 167 insertions, 94 deletions
diff --git a/src/Editor.cxx b/src/Editor.cxx index acb840fdf..acd5b3611 100644 --- a/src/Editor.cxx +++ b/src/Editor.cxx @@ -15,6 +15,9 @@ #include <string> #include <vector> #include <map> +#ifndef SCINTILLA_NO_UNORDERED_MAP +#include <unordered_map> +#endif #include <algorithm> #include <memory> @@ -244,6 +247,47 @@ void Editor::Finalise() { CancelModes(); } +void Editor::SetRepresentations() { + reprs.Clear(); + + // C0 control set + const char *reps[] = { + "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL", + "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI", + "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB", + "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US" + }; + for (size_t j=0; j < (sizeof(reps) / sizeof(reps[0])); j++) { + char c[2] = { static_cast<char>(j), 0 }; + reprs.SetRepresentation(c, reps[j]); + } + + // C1 control set + // As well as Unicode mode, ISO-8859-1 should use these + if (IsUnicodeMode()) { + const char *repsC1[] = { + "PAD", "HOP", "BPH", "NBH", "IND", "NEL", "SSA", "ESA", + "HTS", "HTJ", "VTS", "PLD", "PLU", "RI", "SS2", "SS3", + "DCS", "PU1", "PU2", "STS", "CCH", "MW", "SPA", "EPA", + "SOS", "SGCI", "SCI", "CSI", "ST", "OSC", "PM", "APC" + }; + for (size_t j=0; j < (sizeof(repsC1) / sizeof(repsC1[0])); j++) { + char c1[3] = { '\xc2', static_cast<char>(0x80+j), 0 }; + reprs.SetRepresentation(c1, repsC1[j]); + } + } + + // UTF-8 invalid bytes + if (IsUnicodeMode()) { + for (int k=0x80; k < 0x100; k++) { + char hiByte[2] = { static_cast<char>(k), 0 }; + char hexits[4]; + sprintf(hexits, "x%2X", k); + reprs.SetRepresentation(hiByte, hexits); + } + } +} + void Editor::DropGraphics(bool freeObjects) { if (freeObjects) { delete pixmapLine; @@ -2127,6 +2171,7 @@ LineLayout *Editor::RetrieveLineLayout(int lineNumber) { LinesOnScreen() + 1, pdoc->LinesTotal()); } +/* bool BadUTF(const char *s, int len, int &trailBytes) { // For the rules: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 if (trailBytes) { @@ -2141,6 +2186,7 @@ bool BadUTF(const char *s, int len, int &trailBytes) { return false; } } +*/ /** * Fill in the LineLayout data for the given line. @@ -2250,45 +2296,53 @@ void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayou ll->positions[0] = 0; XYPOSITION tabWidth = vstyle.spaceWidth * pdoc->tabInChars; bool lastSegItalics = false; - Font &ctrlCharsFont = vstyle.styles[STYLE_CONTROLCHAR].font; - - XYPOSITION ctrlCharWidth[32] = {0}; - bool isControlNext = IsControlCharacter(ll->chars[0]); - int trailBytes = 0; - bool isBadUTFNext = IsUnicodeMode() && BadUTF(ll->chars, numCharsInLine, trailBytes); - for (int charInLine = 0; charInLine < numCharsInLine; charInLine++) { - bool isControl = isControlNext; - isControlNext = IsControlCharacter(ll->chars[charInLine + 1]); - bool isBadUTF = isBadUTFNext; - isBadUTFNext = IsUnicodeMode() && BadUTF(ll->chars + charInLine + 1, numCharsInLine - charInLine - 1, trailBytes); + + EncodingFamily encodingFamily = pdoc->CodePageFamily(); + + XYPOSITION positionsRepr[256]; // Should expand when needed + int charWidthNext = 1; + if (encodingFamily == efUnicode) + charWidthNext = UTF8DrawBytes(reinterpret_cast<unsigned char *>(ll->chars), numCharsInLine); + else if (encodingFamily == efDBCS) + charWidthNext = pdoc->IsDBCSLeadByte(ll->chars[0]) ? 2 : 1; + Representation *reprNext = reprs.RepresentationFromCharacter(ll->chars, charWidthNext); + int charWidth = 1; + + for (int charInLine = 0; charInLine < numCharsInLine; charInLine += charWidth) { + + charWidth = charWidthNext; + Representation *repr = reprNext; + + charWidthNext = 1; + if (encodingFamily == efUnicode) + charWidthNext = UTF8DrawBytes(reinterpret_cast<unsigned char *>(ll->chars+charInLine + charWidth), numCharsInLine - charInLine - charWidth); + else if (encodingFamily == efDBCS) + charWidthNext = pdoc->IsDBCSLeadByte(ll->chars[charInLine + charWidth]) ? 2 : 1; + reprNext = reprs.RepresentationFromCharacter(ll->chars+charInLine + charWidth, charWidthNext); + if ((ll->styles[charInLine] != ll->styles[charInLine + 1]) || - isControl || isControlNext || isBadUTF || isBadUTFNext || ((charInLine+1) >= numCharsBeforeEOL)) { + repr || reprNext || ((charInLine+charWidth) >= numCharsBeforeEOL)) { ll->positions[startseg] = 0; if (vstyle.styles[ll->styles[charInLine]].visible) { - if (isControl) { + if (repr) { if (ll->chars[charInLine] == '\t') { + // Tab is a special case of repr, taking a variable amount of space ll->positions[charInLine + 1] = ((static_cast<int>((startsegx + 2) / tabWidth) + 1) * tabWidth) - startsegx; } else if (controlCharSymbol < 32) { - if (ctrlCharWidth[ll->chars[charInLine]] == 0) { - const char *ctrlChar = ControlCharacterString(ll->chars[charInLine]); - ctrlCharWidth[ll->chars[charInLine]] = - surface->WidthText(ctrlCharsFont, ctrlChar, istrlen(ctrlChar)) + ctrlCharPadding; - } - ll->positions[charInLine + 1] = ctrlCharWidth[ll->chars[charInLine]]; + posCache.MeasureWidths(surface, vstyle, STYLE_CONTROLCHAR, repr->stringRep.c_str(), + static_cast<unsigned int>(repr->stringRep.length()), positionsRepr, pdoc); + XYPOSITION endRepr = positionsRepr[repr->stringRep.length()-1] + 3; + for (int ii=0; ii < charWidth; ii++) + ll->positions[startseg + 1 + ii] = endRepr; } else { char cc[2] = { static_cast<char>(controlCharSymbol), '\0' }; - surface->MeasureWidths(ctrlCharsFont, cc, 1, + surface->MeasureWidths(vstyle.styles[STYLE_CONTROLCHAR].font, cc, 1, ll->positions + startseg + 1); - } + } lastSegItalics = false; - } else if ((isBadUTF) || (charInLine >= numCharsBeforeEOL)) { - char hexits[4]; - sprintf(hexits, "x%2X", ll->chars[charInLine] & 0xff); - ll->positions[charInLine + 1] = - surface->WidthText(ctrlCharsFont, hexits, istrlen(hexits)) + 3; - } else { // Regular character - int lenSeg = charInLine - startseg + 1; + } else { + int lenSeg = charInLine - startseg + charWidth; if ((lenSeg == 1) && (' ' == ll->chars[startseg])) { lastSegItalics = false; // Over half the segments are single characters and of these about half are space characters. @@ -2300,15 +2354,15 @@ void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayou } } } else { // invisible - for (int posToZero = startseg; posToZero <= (charInLine + 1); posToZero++) { + for (int posToZero = startseg; posToZero <= (charInLine + charWidth); posToZero++) { ll->positions[posToZero] = 0; } } - for (int posToIncrease = startseg; posToIncrease <= (charInLine + 1); posToIncrease++) { + for (int posToIncrease = startseg; posToIncrease <= (charInLine + charWidth); posToIncrease++) { ll->positions[posToIncrease] += startsegx; } - startsegx = ll->positions[charInLine + 1]; - startseg = charInLine + 1; + startsegx = ll->positions[charInLine + charWidth]; + startseg = charInLine + charWidth; } } // Small hack to make lines that end with italics not cut off the edge of the last character @@ -2933,7 +2987,7 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis ll->psel = &sel; - BreakFinder bfBack(ll, lineStart, lineEnd, posLineStart, xStartVisible, selBackDrawn, pdoc); + BreakFinder bfBack(ll, lineStart, lineEnd, posLineStart, xStartVisible, selBackDrawn, pdoc, &reprs); int next = bfBack.First(); // Background drawing loop @@ -3028,7 +3082,7 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis inIndentation = subLine == 0; // Do not handle indentation except on first subline. // Foreground drawing loop BreakFinder bfFore(ll, lineStart, lineEnd, posLineStart, xStartVisible, - ((!twoPhaseDraw && selBackDrawn) || vsDraw.selforeset), pdoc); + ((!twoPhaseDraw && selBackDrawn) || vsDraw.selforeset), pdoc, &reprs); next = bfFore.First(); while (next < lineEnd) { @@ -3087,74 +3141,71 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis DrawTabArrow(surface, rcTab, rcSegment.top + vsDraw.lineHeight / 2); } } - } else if (IsControlCharacter(ll->chars[i])) { - // Control character display - inIndentation = false; - if (controlCharSymbol < 32) { - // Draw the character - const char *ctrlChar = ControlCharacterString(ll->chars[i]); - DrawTextBlob(surface, vsDraw, rcSegment, ctrlChar, textBack, textFore, twoPhaseDraw); - } else { - char cc[2] = { static_cast<char>(controlCharSymbol), '\0' }; - surface->DrawTextNoClip(rcSegment, ctrlCharsFont, - rcSegment.top + vsDraw.maxAscent, - cc, 1, textBack, textFore); - } - } else if ((i == startseg) && (static_cast<unsigned char>(ll->chars[i]) >= 0x80) && IsUnicodeMode()) { - // A single byte >= 0x80 in UTF-8 is a bad byte and is displayed as its hex value - char hexits[4]; - sprintf(hexits, "x%2X", ll->chars[i] & 0xff); - DrawTextBlob(surface, vsDraw, rcSegment, hexits, textBack, textFore, twoPhaseDraw); } else { - // Normal text display - if (vsDraw.styles[styleMain].visible) { - if (twoPhaseDraw) { - surface->DrawTextTransparent(rcSegment, textFont, - rcSegment.top + vsDraw.maxAscent, ll->chars + startseg, - i - startseg + 1, textFore); + Representation *repr = 0; + if ((i - startseg + 1) <= 4) + repr = reprs.RepresentationFromCharacter(ll->chars + startseg, i - startseg + 1); + if (repr) { + inIndentation = false; // May need to special case ' '. + if (controlCharSymbol < 32) { + DrawTextBlob(surface, vsDraw, rcSegment, repr->stringRep.c_str(), textBack, textFore, twoPhaseDraw); } else { - surface->DrawTextNoClip(rcSegment, textFont, - rcSegment.top + vsDraw.maxAscent, ll->chars + startseg, - i - startseg + 1, textFore, textBack); + char cc[2] = { static_cast<char>(controlCharSymbol), '\0' }; + surface->DrawTextNoClip(rcSegment, ctrlCharsFont, + rcSegment.top + vsDraw.maxAscent, + cc, 1, textBack, textFore); } - } - if (vsDraw.viewWhitespace != wsInvisible || - (inIndentation && vsDraw.viewIndentationGuides != ivNone)) { - for (int cpos = 0; cpos <= i - startseg; cpos++) { - if (ll->chars[cpos + startseg] == ' ') { - if (vsDraw.viewWhitespace != wsInvisible) { - if (vsDraw.whitespaceForegroundSet) - textFore = vsDraw.whitespaceForeground; - if (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways) { - XYPOSITION xmid = (ll->positions[cpos + startseg] + ll->positions[cpos + startseg + 1]) / 2; - if (!twoPhaseDraw && drawWhitespaceBackground && - (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) { - textBack = vsDraw.whitespaceBackground; - PRectangle rcSpace(ll->positions[cpos + startseg] + xStart - subLineStart, - rcSegment.top, - ll->positions[cpos + startseg + 1] + xStart - subLineStart, - rcSegment.bottom); - surface->FillRectangle(rcSpace, textBack); + } else { + // Normal text display + if (vsDraw.styles[styleMain].visible) { + if (twoPhaseDraw) { + surface->DrawTextTransparent(rcSegment, textFont, + rcSegment.top + vsDraw.maxAscent, ll->chars + startseg, + i - startseg + 1, textFore); + } else { + surface->DrawTextNoClip(rcSegment, textFont, + rcSegment.top + vsDraw.maxAscent, ll->chars + startseg, + i - startseg + 1, textFore, textBack); + } + } + if (vsDraw.viewWhitespace != wsInvisible || + (inIndentation && vsDraw.viewIndentationGuides != ivNone)) { + for (int cpos = 0; cpos <= i - startseg; cpos++) { + if (ll->chars[cpos + startseg] == ' ') { + if (vsDraw.viewWhitespace != wsInvisible) { + if (vsDraw.whitespaceForegroundSet) + textFore = vsDraw.whitespaceForeground; + if (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways) { + XYPOSITION xmid = (ll->positions[cpos + startseg] + ll->positions[cpos + startseg + 1]) / 2; + if (!twoPhaseDraw && drawWhitespaceBackground && + (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) { + textBack = vsDraw.whitespaceBackground; + PRectangle rcSpace(ll->positions[cpos + startseg] + xStart - subLineStart, + rcSegment.top, + ll->positions[cpos + startseg + 1] + xStart - subLineStart, + rcSegment.bottom); + surface->FillRectangle(rcSpace, textBack); + } + PRectangle rcDot(xmid + xStart - subLineStart, rcSegment.top + vsDraw.lineHeight / 2, 0, 0); + rcDot.right = rcDot.left + vs.whitespaceSize; + rcDot.bottom = rcDot.top + vs.whitespaceSize; + surface->FillRectangle(rcDot, textFore); } - PRectangle rcDot(xmid + xStart - subLineStart, rcSegment.top + vsDraw.lineHeight / 2, 0, 0); - rcDot.right = rcDot.left + vs.whitespaceSize; - rcDot.bottom = rcDot.top + vs.whitespaceSize; - surface->FillRectangle(rcDot, textFore); } - } - if (inIndentation && vsDraw.viewIndentationGuides == ivReal) { - for (int indentCount = (ll->positions[cpos + startseg] + epsilon) / indentWidth; - indentCount <= (ll->positions[cpos + startseg + 1] - epsilon) / indentWidth; - indentCount++) { - if (indentCount > 0) { - int xIndent = indentCount * indentWidth; - DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIndent + xStart, rcSegment, - (ll->xHighlightGuide == xIndent)); + if (inIndentation && vsDraw.viewIndentationGuides == ivReal) { + for (int indentCount = (ll->positions[cpos + startseg] + epsilon) / indentWidth; + indentCount <= (ll->positions[cpos + startseg + 1] - epsilon) / indentWidth; + indentCount++) { + if (indentCount > 0) { + int xIndent = indentCount * indentWidth; + DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIndent + xStart, rcSegment, + (ll->xHighlightGuide == xIndent)); + } } } + } else { + inIndentation = false; } - } else { - inIndentation = false; } } } @@ -6902,6 +6953,8 @@ void Editor::SetDocPointer(Document *document) { vs.ReleaseAllExtendedStyles(); + SetRepresentations(); + // Reset the contraction state to fully shown. cs.Clear(); cs.InsertLines(0, pdoc->LinesTotal() - 1); @@ -8296,6 +8349,7 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { cs.InsertLines(0, pdoc->LinesTotal() - 1); SetAnnotationHeights(0, pdoc->LinesTotal()); InvalidateStyleRedraw(); + SetRepresentations(); } } break; @@ -9170,6 +9224,25 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { case SCI_GETCONTROLCHARSYMBOL: return controlCharSymbol; + case SCI_SETREPRESENTATION: + reprs.SetRepresentation(reinterpret_cast<const char *>(wParam), CharPtrFromSPtr(lParam)); + break; + + case SCI_GETREPRESENTATION: { + Representation *repr = reprs.RepresentationFromCharacter( + reinterpret_cast<const char *>(wParam), UTF8MaxBytes); + if (repr) { + if (lParam != 0) + strcpy(CharPtrFromSPtr(lParam), repr->stringRep.c_str()); + return repr->stringRep.size(); + } + return 0; + } + + case SCI_CLEARREPRESENTATION: + reprs.ClearRepresentation(reinterpret_cast<const char *>(wParam)); + break; + case SCI_STARTRECORD: recordingMacro = true; return 0; |