1 #include "scripthighlighter.hpp"
2
3 #include <sstream>
4
5 #include <components/compiler/scanner.hpp>
6 #include <components/compiler/extensions0.hpp>
7
8 #include "../../model/prefs/setting.hpp"
9 #include "../../model/prefs/category.hpp"
10
parseInt(int value,const Compiler::TokenLoc & loc,Compiler::Scanner & scanner)11 bool CSVWorld::ScriptHighlighter::parseInt (int value, const Compiler::TokenLoc& loc,
12 Compiler::Scanner& scanner)
13 {
14 highlight (loc, Type_Int);
15 return true;
16 }
17
parseFloat(float value,const Compiler::TokenLoc & loc,Compiler::Scanner & scanner)18 bool CSVWorld::ScriptHighlighter::parseFloat (float value, const Compiler::TokenLoc& loc,
19 Compiler::Scanner& scanner)
20 {
21 highlight (loc, Type_Float);
22 return true;
23 }
24
parseName(const std::string & name,const Compiler::TokenLoc & loc,Compiler::Scanner & scanner)25 bool CSVWorld::ScriptHighlighter::parseName (const std::string& name, const Compiler::TokenLoc& loc,
26 Compiler::Scanner& scanner)
27 {
28 highlight (loc, mContext.isId (name) ? Type_Id : Type_Name);
29 return true;
30 }
31
parseKeyword(int keyword,const Compiler::TokenLoc & loc,Compiler::Scanner & scanner)32 bool CSVWorld::ScriptHighlighter::parseKeyword (int keyword, const Compiler::TokenLoc& loc,
33 Compiler::Scanner& scanner)
34 {
35 if (((mMode==Mode_Console || mMode==Mode_Dialogue) &&
36 (keyword==Compiler::Scanner::K_begin || keyword==Compiler::Scanner::K_end ||
37 keyword==Compiler::Scanner::K_short || keyword==Compiler::Scanner::K_long ||
38 keyword==Compiler::Scanner::K_float))
39 || (mMode==Mode_Console && (keyword==Compiler::Scanner::K_if ||
40 keyword==Compiler::Scanner::K_endif || keyword==Compiler::Scanner::K_else ||
41 keyword==Compiler::Scanner::K_elseif || keyword==Compiler::Scanner::K_while ||
42 keyword==Compiler::Scanner::K_endwhile)))
43 return parseName (loc.mLiteral, loc, scanner);
44
45 highlight (loc, Type_Keyword);
46 return true;
47 }
48
parseSpecial(int code,const Compiler::TokenLoc & loc,Compiler::Scanner & scanner)49 bool CSVWorld::ScriptHighlighter::parseSpecial (int code, const Compiler::TokenLoc& loc,
50 Compiler::Scanner& scanner)
51 {
52 highlight (loc, Type_Special);
53 return true;
54 }
55
parseComment(const std::string & comment,const Compiler::TokenLoc & loc,Compiler::Scanner & scanner)56 bool CSVWorld::ScriptHighlighter::parseComment (const std::string& comment,
57 const Compiler::TokenLoc& loc, Compiler::Scanner& scanner)
58 {
59 highlight (loc, Type_Comment);
60 return true;
61 }
62
parseEOF(Compiler::Scanner & scanner)63 void CSVWorld::ScriptHighlighter::parseEOF (Compiler::Scanner& scanner)
64 {}
65
highlight(const Compiler::TokenLoc & loc,Type type)66 void CSVWorld::ScriptHighlighter::highlight (const Compiler::TokenLoc& loc, Type type)
67 {
68 // We should take in account multibyte characters
69 int length = 0;
70 const char* token = loc.mLiteral.c_str();
71 while (*token) length += (*token++ & 0xc0) != 0x80;
72
73 int index = loc.mColumn;
74
75 // compensate for bug in Compiler::Scanner (position of token is the character after the token)
76 index -= length;
77
78 QTextCharFormat scheme = mScheme[type];
79 if (mMarkOccurrences && type == Type_Name && loc.mLiteral == mMarkedWord)
80 scheme.merge(mScheme[Type_Highlight]);
81
82 setFormat (index, length, scheme);
83 }
84
ScriptHighlighter(const CSMWorld::Data & data,Mode mode,QTextDocument * parent)85 CSVWorld::ScriptHighlighter::ScriptHighlighter (const CSMWorld::Data& data, Mode mode,
86 QTextDocument *parent)
87 : QSyntaxHighlighter (parent)
88 , Compiler::Parser (mErrorHandler, mContext)
89 , mContext (data)
90 , mMode (mode)
91 , mMarkOccurrences (false)
92 {
93 QColor color ("black");
94 QTextCharFormat format;
95 format.setForeground (color);
96
97 for (int i=0; i<=Type_Id; ++i)
98 mScheme.insert (std::make_pair (static_cast<Type> (i), format));
99
100 // configure compiler
101 Compiler::registerExtensions (mExtensions);
102 mContext.setExtensions (&mExtensions);
103 }
104
highlightBlock(const QString & text)105 void CSVWorld::ScriptHighlighter::highlightBlock (const QString& text)
106 {
107 std::istringstream stream (text.toUtf8().constData());
108
109 Compiler::Scanner scanner (mErrorHandler, stream, mContext.getExtensions());
110
111 try
112 {
113 scanner.scan (*this);
114 }
115 catch (...) {} // ignore syntax errors
116 }
117
setMarkOccurrences(bool flag)118 void CSVWorld::ScriptHighlighter::setMarkOccurrences(bool flag)
119 {
120 mMarkOccurrences = flag;
121 }
122
setMarkedWord(const std::string & name)123 void CSVWorld::ScriptHighlighter::setMarkedWord(const std::string& name)
124 {
125 mMarkedWord = name;
126 }
127
invalidateIds()128 void CSVWorld::ScriptHighlighter::invalidateIds()
129 {
130 mContext.invalidateIds();
131 }
132
settingChanged(const CSMPrefs::Setting * setting)133 bool CSVWorld::ScriptHighlighter::settingChanged (const CSMPrefs::Setting *setting)
134 {
135 if (setting->getParent()->getKey()=="Scripts")
136 {
137 static const char *const colours[Type_Id+2] =
138 {
139 "colour-int", "colour-float", "colour-name", "colour-keyword",
140 "colour-special", "colour-comment", "colour-highlight", "colour-id",
141 0
142 };
143
144 for (int i=0; colours[i]; ++i)
145 if (setting->getKey()==colours[i])
146 {
147 QTextCharFormat format;
148 if (i == Type_Highlight)
149 format.setBackground (setting->toColor());
150 else
151 format.setForeground (setting->toColor());
152 mScheme[static_cast<Type> (i)] = format;
153 return true;
154 }
155 }
156
157 return false;
158 }
159