Add syntax highlighting for drawings and vector clips
The highlighting distinguishes drawing commands from coordinates, and colors x and y coordinates in different colors to make coordinates easier to visually parse. Furthermore, in cubic Bezier curves, it underlines the coordinates which corresponds to endpoints of the curves.
This commit is contained in:
parent
c7c874acc4
commit
7ddfef7517
8 changed files with 201 additions and 19 deletions
|
@ -60,7 +60,11 @@ public:
|
|||
case dt::ERROR: SetStyling(tok.length, ss::ERROR); break;
|
||||
case dt::ARG: SetStyling(tok.length, ss::PARAMETER); break;
|
||||
case dt::COMMENT: SetStyling(tok.length, ss::COMMENT); break;
|
||||
case dt::DRAWING: SetStyling(tok.length, ss::DRAWING); break;
|
||||
case dt::DRAWING_CMD:SetStyling(tok.length, ss::DRAWING_CMD);break;
|
||||
case dt::DRAWING_X: SetStyling(tok.length, ss::DRAWING_X); break;
|
||||
case dt::DRAWING_Y: SetStyling(tok.length, ss::DRAWING_Y); break;
|
||||
case dt::DRAWING_ENDPOINT_X: SetStyling(tok.length, ss::DRAWING_ENDPOINT_X); break;
|
||||
case dt::DRAWING_ENDPOINT_Y: SetStyling(tok.length, ss::DRAWING_ENDPOINT_Y); break;
|
||||
case dt::TEXT: SetStyling(tok.length, ss::NORMAL); break;
|
||||
case dt::TAG_NAME: SetStyling(tok.length, ss::TAG); break;
|
||||
case dt::OPEN_PAREN: case dt::CLOSE_PAREN: case dt::ARG_SEP: case dt::TAG_START:
|
||||
|
@ -72,6 +76,8 @@ public:
|
|||
case dt::WHITESPACE:
|
||||
if (ranges.size() && ranges.back().type == ss::PARAMETER)
|
||||
SetStyling(tok.length, ss::PARAMETER);
|
||||
else if (ranges.size() && ranges.back().type == ss::DRAWING_ENDPOINT_X)
|
||||
SetStyling(tok.length, ss::DRAWING_ENDPOINT_X); // connect the underline between x and y of endpoints
|
||||
else
|
||||
SetStyling(tok.length, ss::NORMAL);
|
||||
break;
|
||||
|
@ -118,6 +124,64 @@ class WordSplitter {
|
|||
}
|
||||
}
|
||||
|
||||
void SplitDrawing(size_t &i) {
|
||||
size_t starti = i;
|
||||
|
||||
// First, split into words
|
||||
size_t dpos = pos;
|
||||
size_t tlen = 0;
|
||||
bool tokentype = text[pos] == ' ' || text[pos] == '\t';
|
||||
while (tlen < tokens[i].length) {
|
||||
bool newtype = text[dpos] == ' ' || text[dpos] == '\t';
|
||||
if (newtype != tokentype) {
|
||||
tokentype = newtype;
|
||||
SwitchTo(i, tokentype ? dt::DRAWING_FULL : dt::WHITESPACE, tlen);
|
||||
tokens[i].type = tokentype ? dt::WHITESPACE : dt::DRAWING_FULL;
|
||||
tlen = 0;
|
||||
}
|
||||
++tlen;
|
||||
++dpos;
|
||||
}
|
||||
|
||||
// Then, label all the tokens
|
||||
dpos = pos;
|
||||
int num_coord = 0;
|
||||
char lastcmd = ' ';
|
||||
|
||||
for (size_t j = starti; j <= i; j++) {
|
||||
char c = text[dpos];
|
||||
if (tokens[j].type == dt::WHITESPACE) {
|
||||
} else if (c == 'm' || c == 'n' || c == 'l' || c == 's' || c == 'b' || c == 'p' || c == 'c') {
|
||||
tokens[j].type = dt::DRAWING_CMD;
|
||||
|
||||
if (tokens[j].length != 1)
|
||||
tokens[j].type = dt::ERROR;
|
||||
if (num_coord % 2 != 0)
|
||||
tokens[j].type = dt::ERROR;
|
||||
|
||||
lastcmd = c;
|
||||
num_coord = 0;
|
||||
} else {
|
||||
bool valid = true;
|
||||
for (size_t k = 0; k < tokens[j].length; k++) {
|
||||
char c = text[dpos + k];
|
||||
if (!((c >= '0' && c <= '9') || c == '.' || c == '-' || c == 'e')) {
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
if (!valid)
|
||||
tokens[j].type = dt::ERROR;
|
||||
else if (lastcmd == 'b' && num_coord % 6 >= 4)
|
||||
tokens[j].type = num_coord % 2 == 0 ? dt::DRAWING_ENDPOINT_X : dt::DRAWING_ENDPOINT_Y;
|
||||
else
|
||||
tokens[j].type = num_coord % 2 == 0 ? dt::DRAWING_X : dt::DRAWING_Y;
|
||||
++num_coord;
|
||||
}
|
||||
|
||||
dpos += tokens[j].length;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
WordSplitter(std::string const& text, std::vector<DialogueToken> &tokens)
|
||||
: text(text)
|
||||
|
@ -131,6 +195,9 @@ public:
|
|||
size_t len = tokens[i].length;
|
||||
if (tokens[i].type == dt::TEXT)
|
||||
SplitText(i);
|
||||
else if (tokens[i].type == dt::DRAWING_FULL) {
|
||||
SplitDrawing(i);
|
||||
}
|
||||
pos += len;
|
||||
}
|
||||
}
|
||||
|
@ -163,9 +230,51 @@ void MarkDrawings(std::string const& str, std::vector<DialogueToken> &tokens) {
|
|||
switch (tokens[i].type) {
|
||||
case dt::TEXT:
|
||||
if (in_drawing)
|
||||
tokens[i].type = dt::DRAWING;
|
||||
tokens[i].type = dt::DRAWING_FULL;
|
||||
break;
|
||||
case dt::TAG_NAME:
|
||||
if (i + 3 < tokens.size() && (len == 4 || len == 5) && !strncmp(str.c_str() + pos + len - 4, "clip", 4)) {
|
||||
if (tokens[i + 1].type != dt::OPEN_PAREN)
|
||||
goto tag_p;
|
||||
|
||||
size_t drawing_start = 0;
|
||||
size_t drawing_end = 0;
|
||||
|
||||
// Try to find a vector clip
|
||||
for (size_t j = i + 2; j < tokens.size(); j++) {
|
||||
if (tokens[j].type == dt::ARG_SEP) {
|
||||
if (drawing_start) {
|
||||
break; // More than two arguents - this is a rectangular clip
|
||||
}
|
||||
drawing_start = j + 1;
|
||||
} else if (tokens[j].type == dt::CLOSE_PAREN) {
|
||||
drawing_end = j;
|
||||
break;
|
||||
} else if (tokens[j].type != dt::WHITESPACE && tokens[j].type != dt::ARG) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!drawing_end)
|
||||
goto tag_p;
|
||||
if (!drawing_start)
|
||||
drawing_start = i + 2;
|
||||
if (drawing_end == drawing_start + 1)
|
||||
goto tag_p;
|
||||
|
||||
// We found a clip between drawing_start and drawing_end. Now, join
|
||||
// all the tokens into one and label it as a drawing.
|
||||
size_t tokenlen = 0;
|
||||
for (size_t j = drawing_start; j < drawing_end; j++) {
|
||||
tokenlen += tokens[j].length;
|
||||
}
|
||||
|
||||
tokens[drawing_start].length = tokenlen;
|
||||
tokens[drawing_start].type = dt::DRAWING_FULL;
|
||||
tokens.erase(tokens.begin() + drawing_start + 1, tokens.begin() + drawing_end);
|
||||
last_ovr_end -= drawing_end - drawing_start - 1;
|
||||
}
|
||||
tag_p:
|
||||
if (len != 1 || i + 1 >= tokens.size() || str[pos] != 'p')
|
||||
break;
|
||||
|
||||
|
@ -199,7 +308,7 @@ void MarkDrawings(std::string const& str, std::vector<DialogueToken> &tokens) {
|
|||
case dt::KARAOKE_VARIABLE: break;
|
||||
case dt::LINE_BREAK: break;
|
||||
default:
|
||||
tokens[i].type = in_drawing ? dt::DRAWING : dt::TEXT;
|
||||
tokens[i].type = in_drawing ? dt::DRAWING_FULL : dt::TEXT;
|
||||
if (i > 0 && tokens[i - 1].type == tokens[i].type) {
|
||||
tokens[i - 1].length += tokens[i].length;
|
||||
tokens.erase(tokens.begin() + i);
|
||||
|
|
|
@ -39,7 +39,12 @@ namespace agi {
|
|||
ERROR,
|
||||
COMMENT,
|
||||
WHITESPACE,
|
||||
DRAWING,
|
||||
DRAWING_FULL,
|
||||
DRAWING_CMD,
|
||||
DRAWING_X,
|
||||
DRAWING_Y,
|
||||
DRAWING_ENDPOINT_X,
|
||||
DRAWING_ENDPOINT_Y,
|
||||
KARAOKE_TEMPLATE,
|
||||
KARAOKE_VARIABLE
|
||||
};
|
||||
|
@ -49,7 +54,11 @@ namespace agi {
|
|||
enum {
|
||||
NORMAL = 0,
|
||||
COMMENT,
|
||||
DRAWING,
|
||||
DRAWING_CMD,
|
||||
DRAWING_X,
|
||||
DRAWING_Y,
|
||||
DRAWING_ENDPOINT_X,
|
||||
DRAWING_ENDPOINT_Y,
|
||||
OVERRIDE,
|
||||
PUNCTUATION,
|
||||
TAG,
|
||||
|
|
|
@ -228,7 +228,9 @@
|
|||
"Background" : {
|
||||
"Brackets" : "",
|
||||
"Comment" : "",
|
||||
"Drawing" : "",
|
||||
"Drawing Command" : "",
|
||||
"Drawing X" : "",
|
||||
"Drawing Y" : "",
|
||||
"Error" : "rgb(255, 200, 200)",
|
||||
"Karaoke Template" : "",
|
||||
"Karaoke Variable" : "",
|
||||
|
@ -241,7 +243,9 @@
|
|||
"Bold" : {
|
||||
"Brackets" : false,
|
||||
"Comment" : true,
|
||||
"Drawing" : true,
|
||||
"Drawing Command" : true,
|
||||
"Drawing X" : false,
|
||||
"Drawing Y" : false,
|
||||
"Error" : false,
|
||||
"Karaoke Template" : true,
|
||||
"Karaoke Variable" : true,
|
||||
|
@ -251,9 +255,14 @@
|
|||
"Slashes" : false,
|
||||
"Tags" : true
|
||||
},
|
||||
"Underline": {
|
||||
"Drawing Endpoint": true
|
||||
},
|
||||
"Brackets" : "rgb(20, 50, 255)",
|
||||
"Comment" : "rgb(0,0,0)",
|
||||
"Drawing" : "rgb(0,0,0)",
|
||||
"Drawing Command" : "rgb(0,0,0)",
|
||||
"Drawing X" : "rgb(90,40,40)",
|
||||
"Drawing Y" : "rgb(40,90,40)",
|
||||
"Error" : "rgb(200, 0, 0)",
|
||||
"Karaoke Template" : "rgb(128, 0, 192)",
|
||||
"Karaoke Variable" : "rgb(128, 0, 192)",
|
||||
|
|
|
@ -228,7 +228,9 @@
|
|||
"Background" : {
|
||||
"Brackets" : "",
|
||||
"Comment" : "",
|
||||
"Drawing" : "",
|
||||
"Drawing Command" : "",
|
||||
"Drawing X" : "",
|
||||
"Drawing Y" : "",
|
||||
"Error" : "rgb(255, 200, 200)",
|
||||
"Karaoke Template" : "",
|
||||
"Karaoke Variable" : "",
|
||||
|
@ -241,7 +243,9 @@
|
|||
"Bold" : {
|
||||
"Brackets" : false,
|
||||
"Comment" : true,
|
||||
"Drawing" : true,
|
||||
"Drawing Command" : true,
|
||||
"Drawing X" : false,
|
||||
"Drawing Y" : false,
|
||||
"Error" : false,
|
||||
"Karaoke Template" : true,
|
||||
"Karaoke Variable" : true,
|
||||
|
@ -251,9 +255,14 @@
|
|||
"Slashes" : false,
|
||||
"Tags" : true
|
||||
},
|
||||
"Underline": {
|
||||
"Drawing Endpoint": true
|
||||
},
|
||||
"Brackets" : "rgb(20, 50, 255)",
|
||||
"Comment" : "rgb(0,0,0)",
|
||||
"Drawing" : "rgb(0,0,0)",
|
||||
"Drawing Command" : "rgb(0,0,0)",
|
||||
"Drawing X" : "rgb(90,40,40)",
|
||||
"Drawing Y" : "rgb(40,90,40)",
|
||||
"Error" : "rgb(200, 0, 0)",
|
||||
"Karaoke Template" : "rgb(128, 0, 192)",
|
||||
"Karaoke Variable" : "rgb(128, 0, 192)",
|
||||
|
|
|
@ -253,7 +253,11 @@ void Interface_Colours(wxTreebook *book, Preferences *parent) {
|
|||
p->OptionAdd(syntax, _("Background"), "Colour/Subtitle/Background");
|
||||
p->OptionAdd(syntax, _("Normal"), "Colour/Subtitle/Syntax/Normal");
|
||||
p->OptionAdd(syntax, _("Comments"), "Colour/Subtitle/Syntax/Comment");
|
||||
p->OptionAdd(syntax, _("Drawings"), "Colour/Subtitle/Syntax/Drawing");
|
||||
p->OptionAdd(syntax, _("Drawing Commands"), "Colour/Subtitle/Syntax/Drawing Command");
|
||||
p->OptionAdd(syntax, _("Drawing X Coords"), "Colour/Subtitle/Syntax/Drawing X");
|
||||
p->OptionAdd(syntax, _("Drawing Y Coords"), "Colour/Subtitle/Syntax/Drawing Y");
|
||||
p->OptionAdd(syntax, _("Underline Spline Endpoints"), "Colour/Subtitle/Syntax/Underline/Drawing Endpoint");
|
||||
p->CellSkip(syntax);
|
||||
p->OptionAdd(syntax, _("Brackets"), "Colour/Subtitle/Syntax/Brackets");
|
||||
p->OptionAdd(syntax, _("Slashes and Parentheses"), "Colour/Subtitle/Syntax/Slashes");
|
||||
p->OptionAdd(syntax, _("Tags"), "Colour/Subtitle/Syntax/Tags");
|
||||
|
|
|
@ -138,7 +138,10 @@ SubsTextEditCtrl::SubsTextEditCtrl(wxWindow* parent, wxSize wsize, long style, a
|
|||
OPT_SUB("Subtitle/Edit Box/Font Size", &SubsTextEditCtrl::SetStyles, this);
|
||||
Subscribe("Normal");
|
||||
Subscribe("Comment");
|
||||
Subscribe("Drawing");
|
||||
Subscribe("Drawing Command");
|
||||
Subscribe("Drawing X");
|
||||
Subscribe("Drawing Y");
|
||||
OPT_SUB("Colour/Subtitle/Syntax/Underline/Drawing Endpoint", &SubsTextEditCtrl::SetStyles, this);
|
||||
Subscribe("Brackets");
|
||||
Subscribe("Slashes");
|
||||
Subscribe("Tags");
|
||||
|
@ -230,7 +233,13 @@ void SubsTextEditCtrl::SetStyles() {
|
|||
namespace ss = agi::ass::SyntaxStyle;
|
||||
SetSyntaxStyle(ss::NORMAL, font, "Normal", default_background);
|
||||
SetSyntaxStyle(ss::COMMENT, font, "Comment", default_background);
|
||||
SetSyntaxStyle(ss::DRAWING, font, "Drawing", default_background);
|
||||
SetSyntaxStyle(ss::DRAWING_CMD, font, "Drawing Command", default_background);
|
||||
SetSyntaxStyle(ss::DRAWING_X, font, "Drawing X", default_background);
|
||||
SetSyntaxStyle(ss::DRAWING_Y, font, "Drawing Y", default_background);
|
||||
SetSyntaxStyle(ss::DRAWING_ENDPOINT_X, font, "Drawing X", default_background);
|
||||
SetSyntaxStyle(ss::DRAWING_ENDPOINT_Y, font, "Drawing Y", default_background);
|
||||
StyleSetUnderline(ss::DRAWING_ENDPOINT_X, OPT_GET("Colour/Subtitle/Syntax/Underline/Drawing Endpoint")->GetBool());
|
||||
StyleSetUnderline(ss::DRAWING_ENDPOINT_Y, OPT_GET("Colour/Subtitle/Syntax/Underline/Drawing Endpoint")->GetBool());
|
||||
SetSyntaxStyle(ss::OVERRIDE, font, "Brackets", default_background);
|
||||
SetSyntaxStyle(ss::PUNCTUATION, font, "Slashes", default_background);
|
||||
SetSyntaxStyle(ss::TAG, font, "Tags", default_background);
|
||||
|
|
|
@ -74,14 +74,47 @@ TEST(lagi_syntax, spellcheck) {
|
|||
}
|
||||
|
||||
TEST(lagi_syntax, drawing) {
|
||||
tok_str("incorrect{\\p1}m 10 10{\\p}correct", false,
|
||||
tok_str("incorrect{\\clip(m 10 10 l 20 20 c)\\p1}m 10 10 b 0 0 0 100 100 0{\\p}correct", false,
|
||||
expect_style(ss::SPELLING, 9u);
|
||||
expect_style(ss::OVERRIDE, 1u);
|
||||
expect_style(ss::PUNCTUATION, 1u);
|
||||
expect_style(ss::TAG, 4u);
|
||||
expect_style(ss::PUNCTUATION, 1u);
|
||||
expect_style(ss::DRAWING_CMD, 1u);
|
||||
expect_style(ss::NORMAL, 1u);
|
||||
expect_style(ss::DRAWING_X, 2u);
|
||||
expect_style(ss::NORMAL, 1u);
|
||||
expect_style(ss::DRAWING_Y, 2u);
|
||||
expect_style(ss::NORMAL, 1u);
|
||||
expect_style(ss::DRAWING_CMD, 1u);
|
||||
expect_style(ss::NORMAL, 1u);
|
||||
expect_style(ss::DRAWING_X, 2u);
|
||||
expect_style(ss::NORMAL, 1u);
|
||||
expect_style(ss::DRAWING_Y, 2u);
|
||||
expect_style(ss::NORMAL, 1u);
|
||||
expect_style(ss::DRAWING_CMD, 1u);
|
||||
expect_style(ss::PUNCTUATION, 2u);
|
||||
expect_style(ss::TAG, 1u);
|
||||
expect_style(ss::PARAMETER, 1u);
|
||||
expect_style(ss::OVERRIDE, 1u);
|
||||
expect_style(ss::DRAWING, 7u);
|
||||
expect_style(ss::DRAWING_CMD, 1u);
|
||||
expect_style(ss::NORMAL, 1u);
|
||||
expect_style(ss::DRAWING_X, 2u);
|
||||
expect_style(ss::NORMAL, 1u);
|
||||
expect_style(ss::DRAWING_Y, 2u);
|
||||
expect_style(ss::NORMAL, 1u);
|
||||
expect_style(ss::DRAWING_CMD, 1u);
|
||||
expect_style(ss::NORMAL, 1u);
|
||||
expect_style(ss::DRAWING_X, 1u);
|
||||
expect_style(ss::NORMAL, 1u);
|
||||
expect_style(ss::DRAWING_Y, 1u);
|
||||
expect_style(ss::NORMAL, 1u);
|
||||
expect_style(ss::DRAWING_X, 1u);
|
||||
expect_style(ss::NORMAL, 1u);
|
||||
expect_style(ss::DRAWING_Y, 3u);
|
||||
expect_style(ss::NORMAL, 1u);
|
||||
expect_style(ss::DRAWING_ENDPOINT_X, 4u);
|
||||
expect_style(ss::DRAWING_ENDPOINT_Y, 1u);
|
||||
expect_style(ss::OVERRIDE, 1u);
|
||||
expect_style(ss::PUNCTUATION, 1u);
|
||||
expect_style(ss::TAG, 1u);
|
||||
|
|
|
@ -108,12 +108,12 @@ TEST(lagi_word_split, drawing) {
|
|||
|
||||
SplitWords(text, tokens);
|
||||
|
||||
ASSERT_EQ(15u, tokens.size());
|
||||
ASSERT_EQ(17u, tokens.size());
|
||||
EXPECT_EQ(dt::WORD, tokens[0].type);
|
||||
EXPECT_EQ(dt::WORD, tokens[2].type);
|
||||
EXPECT_EQ(dt::WORD, tokens[14].type);
|
||||
EXPECT_EQ(dt::WORD, tokens[16].type);
|
||||
|
||||
EXPECT_EQ(dt::DRAWING, tokens[8].type);
|
||||
EXPECT_EQ(dt::DRAWING_CMD, tokens[8].type);
|
||||
}
|
||||
|
||||
TEST(lagi_word_split, unclosed_ovr) {
|
||||
|
|
Loading…
Reference in a new issue