|
@@ -41,7 +41,8 @@ public: |
|
|
|
|
|
|
|
|
if (tokeniser == nullptr)
|
|
|
if (tokeniser == nullptr)
|
|
|
{
|
|
|
{
|
|
|
newTokens.add (SyntaxToken (document.getLine (lineNum), -1));
|
|
|
|
|
|
|
|
|
const String line (document.getLine (lineNum));
|
|
|
|
|
|
addToken (newTokens, line, line.length(), -1);
|
|
|
}
|
|
|
}
|
|
|
else if (lineNum < document.getNumLines())
|
|
|
else if (lineNum < document.getNumLines())
|
|
|
{
|
|
|
{
|
|
@@ -81,22 +82,29 @@ public: |
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
void draw (CodeEditorComponent& owner, Graphics& g, const Font& font,
|
|
|
void draw (CodeEditorComponent& owner, Graphics& g, const Font& font,
|
|
|
float x, const float rightEdge, const int y, const int baselineOffset, const int lineHeight,
|
|
|
|
|
|
|
|
|
const float leftClip, const float rightClip,
|
|
|
|
|
|
const float xOffset, const int y, const int baselineOffset,
|
|
|
|
|
|
const int lineHeight, const float charWidth,
|
|
|
const Colour& highlightColour) const
|
|
|
const Colour& highlightColour) const
|
|
|
{
|
|
|
{
|
|
|
if (highlightColumnStart < highlightColumnEnd)
|
|
|
if (highlightColumnStart < highlightColumnEnd)
|
|
|
{
|
|
|
{
|
|
|
g.setColour (highlightColour);
|
|
|
g.setColour (highlightColour);
|
|
|
g.fillRect (roundToInt (x + highlightColumnStart * owner.getCharWidth()), y,
|
|
|
|
|
|
|
|
|
g.fillRect (roundToInt (xOffset + highlightColumnStart * owner.getCharWidth()), y,
|
|
|
roundToInt ((highlightColumnEnd - highlightColumnStart) * owner.getCharWidth()), lineHeight);
|
|
|
roundToInt ((highlightColumnEnd - highlightColumnStart) * owner.getCharWidth()), lineHeight);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
const float baselineY = (float) (y + baselineOffset);
|
|
|
const float baselineY = (float) (y + baselineOffset);
|
|
|
Colour lastColour (0x00000001);
|
|
|
Colour lastColour (0x00000001);
|
|
|
GlyphArrangement ga;
|
|
|
GlyphArrangement ga;
|
|
|
|
|
|
int column = 0;
|
|
|
|
|
|
|
|
|
for (int i = 0; i < tokens.size(); ++i)
|
|
|
for (int i = 0; i < tokens.size(); ++i)
|
|
|
{
|
|
|
{
|
|
|
|
|
|
const float tokenX = xOffset + column * charWidth;
|
|
|
|
|
|
if (tokenX > rightClip)
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
SyntaxToken& token = tokens.getReference(i);
|
|
|
SyntaxToken& token = tokens.getReference(i);
|
|
|
|
|
|
|
|
|
const Colour newColour (owner.getColourForTokenType (token.tokenType));
|
|
|
const Colour newColour (owner.getColourForTokenType (token.tokenType));
|
|
@@ -109,18 +117,11 @@ public: |
|
|
g.setColour (newColour);
|
|
|
g.setColour (newColour);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
ga.addCurtailedLineOfText (font, token.text, x, baselineY, rightEdge - x, false);
|
|
|
|
|
|
|
|
|
|
|
|
if (i < tokens.size() - 1)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (token.width < 0)
|
|
|
|
|
|
token.width = font.getStringWidthFloat (token.text);
|
|
|
|
|
|
|
|
|
|
|
|
x += token.width;
|
|
|
|
|
|
|
|
|
column += token.length;
|
|
|
|
|
|
|
|
|
if (x > rightEdge)
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
if (xOffset + column * charWidth >= leftClip)
|
|
|
|
|
|
ga.addCurtailedLineOfText (font, token.text, tokenX, baselineY,
|
|
|
|
|
|
(rightClip - tokenX) + charWidth, false);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
ga.draw (g);
|
|
|
ga.draw (g);
|
|
@@ -129,19 +130,21 @@ public: |
|
|
private:
|
|
|
private:
|
|
|
struct SyntaxToken
|
|
|
struct SyntaxToken
|
|
|
{
|
|
|
{
|
|
|
SyntaxToken (const String& t, const int type) noexcept
|
|
|
|
|
|
: text (t), tokenType (type), width (-1.0f)
|
|
|
|
|
|
|
|
|
SyntaxToken (const String& t, const int len, const int type) noexcept
|
|
|
|
|
|
: text (t), length (len), tokenType (type)
|
|
|
{
|
|
|
{
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
bool operator== (const SyntaxToken& other) const noexcept
|
|
|
bool operator== (const SyntaxToken& other) const noexcept
|
|
|
{
|
|
|
{
|
|
|
return tokenType == other.tokenType && text == other.text;
|
|
|
|
|
|
|
|
|
return tokenType == other.tokenType
|
|
|
|
|
|
&& length == other.length
|
|
|
|
|
|
&& text == other.text;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
String text;
|
|
|
String text;
|
|
|
|
|
|
int length;
|
|
|
int tokenType;
|
|
|
int tokenType;
|
|
|
float width;
|
|
|
|
|
|
};
|
|
|
};
|
|
|
|
|
|
|
|
|
Array <SyntaxToken> tokens;
|
|
|
Array <SyntaxToken> tokens;
|
|
@@ -169,8 +172,9 @@ private: |
|
|
if (tokenEnd > 0)
|
|
|
if (tokenEnd > 0)
|
|
|
{
|
|
|
{
|
|
|
tokenStart -= startPosition;
|
|
|
tokenStart -= startPosition;
|
|
|
newTokens.add (SyntaxToken (lineText.substring (jmax (0, tokenStart), tokenEnd),
|
|
|
|
|
|
tokenType));
|
|
|
|
|
|
|
|
|
const int start = jmax (0, tokenStart);
|
|
|
|
|
|
addToken (newTokens, lineText.substring (start, tokenEnd),
|
|
|
|
|
|
tokenEnd - start, tokenType);
|
|
|
|
|
|
|
|
|
if (tokenEnd >= lineLength)
|
|
|
if (tokenEnd >= lineLength)
|
|
|
break;
|
|
|
break;
|
|
@@ -219,6 +223,21 @@ private: |
|
|
|
|
|
|
|
|
return col;
|
|
|
return col;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void addToken (Array<SyntaxToken>& dest, const String& text,
|
|
|
|
|
|
const int length, const int type)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (length > 1000)
|
|
|
|
|
|
{
|
|
|
|
|
|
// subdivide very long tokens to avoid unwieldy glyph sequences
|
|
|
|
|
|
addToken (dest, text.substring (0, length / 2), length / 2, type);
|
|
|
|
|
|
addToken (dest, text.substring (length / 2), length - length / 2, type);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
dest.add (SyntaxToken (text, length, type));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
};
|
|
|
};
|
|
|
|
|
|
|
|
|
namespace CodeEditorHelpers
|
|
|
namespace CodeEditorHelpers
|
|
@@ -451,11 +470,13 @@ void CodeEditorComponent::paint (Graphics& g) |
|
|
const int firstLineToDraw = jmax (0, clip.getY() / lineHeight);
|
|
|
const int firstLineToDraw = jmax (0, clip.getY() / lineHeight);
|
|
|
const int lastLineToDraw = jmin (lines.size(), clip.getBottom() / lineHeight + 1);
|
|
|
const int lastLineToDraw = jmin (lines.size(), clip.getBottom() / lineHeight + 1);
|
|
|
const float x = (float) (gutter - xOffset * charWidth);
|
|
|
const float x = (float) (gutter - xOffset * charWidth);
|
|
|
const float rightEdge = (float) getWidth();
|
|
|
|
|
|
|
|
|
const float leftClip = (float) clip.getX();
|
|
|
|
|
|
const float rightClip = (float) clip.getRight();
|
|
|
|
|
|
|
|
|
for (int i = firstLineToDraw; i < lastLineToDraw; ++i)
|
|
|
for (int i = firstLineToDraw; i < lastLineToDraw; ++i)
|
|
|
lines.getUnchecked(i)->draw (*this, g, font, x, rightEdge, lineHeight * i,
|
|
|
|
|
|
baselineOffset, lineHeight, highlightColour);
|
|
|
|
|
|
|
|
|
lines.getUnchecked(i)->draw (*this, g, font, leftClip, rightClip,
|
|
|
|
|
|
x, lineHeight * i, baselineOffset,
|
|
|
|
|
|
lineHeight, charWidth, highlightColour);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
void CodeEditorComponent::setScrollbarThickness (const int thickness)
|
|
|
void CodeEditorComponent::setScrollbarThickness (const int thickness)
|
|
|