1 /*
2 * This file is part of the Code::Blocks IDE and licensed under the GNU Lesser General Public License, version 3
3 * http://www.gnu.org/licenses/lgpl-3.0.html
4 *
5 * $Revision: 11482 $
6 * $Id: editorlexerloader.cpp 11482 2018-09-29 12:20:40Z fuscated $
7 * $HeadURL: svn://svn.code.sf.net/p/codeblocks/code/branches/release-20.xx/src/sdk/editorlexerloader.cpp $
8 */
9
10 #include "sdk_precomp.h"
11
12 #ifndef CB_PRECOMP
13 #include "globals.h"
14 #include "manager.h"
15 #include "logmanager.h"
16 #include <wx/dynarray.h>
17 #include <wx/regex.h>
18 #include <wx/wxscintilla.h>
19 #endif
20
21 #include "editorcolourset.h"
22 #include "editorlexerloader.h"
23 #include "filemanager.h"
24
EditorLexerLoader(EditorColourSet * target)25 EditorLexerLoader::EditorLexerLoader(EditorColourSet* target)
26 : m_pTarget(target)
27 {
28 //ctor
29 }
30
~EditorLexerLoader()31 EditorLexerLoader::~EditorLexerLoader()
32 {
33 //dtor
34 }
35
Load(LoaderBase * loader)36 void EditorLexerLoader::Load(LoaderBase* loader)
37 {
38 Manager::Get()->GetLogManager()->Log(_("Loading ") + wxFileName(loader->FileName()).GetName());
39
40 TiXmlDocument doc;
41 doc.Parse(loader->GetData());
42
43 if (doc.Error())
44 {
45 Manager::Get()->GetLogManager()->Log(_("Failed."));
46 Manager::Get()->GetLogManager()->Log(_("TinyXML error: ") + cbC2U(doc.ErrorDesc()));
47 return;
48 }
49
50 TiXmlElement* root;
51 TiXmlElement* lexer;
52
53 root = doc.FirstChildElement("CodeBlocks_lexer_properties");
54 if (!root)
55 {
56 // old tag
57 root = doc.FirstChildElement("Code::Blocks_lexer_properties");
58 if (!root)
59 {
60 Manager::Get()->GetLogManager()->Log(_("Not a valid Code::Blocks lexer file..."));
61 return;
62 }
63 }
64 lexer = root->FirstChildElement("Lexer");
65 if (!lexer)
66 {
67 Manager::Get()->GetLogManager()->Log(_("No 'Lexer' element in file..."));
68 return;
69 }
70
71 DoLexer(lexer);
72 }
73
DoLexer(TiXmlElement * node)74 void EditorLexerLoader::DoLexer(TiXmlElement* node)
75 {
76 if (!node->Attribute("name") || !node->Attribute("index"))
77 {
78 Manager::Get()->GetLogManager()->Log(_("No name or index..."));
79 return;
80 }
81
82 wxString name = wxString( node->Attribute("name"), wxConvUTF8 );
83 int lexer = atol(node->Attribute("index"));
84 wxString masks = wxString ( node->Attribute("filemasks"), wxConvUTF8 );
85 HighlightLanguage style = m_pTarget->AddHighlightLanguage(lexer, name);
86 if (style == HL_NONE)
87 return; // wasn't added
88 m_pTarget->SetFileMasks(style, masks);
89 // LOGSTREAM << "Found lexer: " << name << " (" << style << ")\n";
90
91 DoStyles(style, node);
92 DoKeywords(style, node);
93 DoSampleCode(style, node);
94 DoLangAttributes(style, node);
95 }
96
DoStyles(HighlightLanguage language,TiXmlElement * node)97 void EditorLexerLoader::DoStyles(HighlightLanguage language, TiXmlElement* node)
98 {
99 bool foundSelection = false, foundActiveLine = false;
100 bool foundMatchBrace = false, foundBraceError = false;
101 bool foundIndentationGuide = false;
102
103 TiXmlElement* style = node->FirstChildElement("Style");
104 while (style)
105 {
106 if (style->Attribute("name") && style->Attribute("index"))
107 {
108 wxString name = wxString ( style->Attribute("name"), wxConvUTF8 );
109 wxString index = wxString ( style->Attribute("index"), wxConvUTF8 ); // comma-separated indices
110 wxString fg = wxString ( style->Attribute("fg"), wxConvUTF8 );
111 wxString bg = wxString ( style->Attribute("bg"), wxConvUTF8 );
112 bool bold = style->Attribute("bold") ? atol(style->Attribute("bold")) != 0 : false;
113 bool italics = style->Attribute("italics") ? atol(style->Attribute("italics")) != 0 : false;
114 bool underlined = style->Attribute("underlined") ? atol(style->Attribute("underlined")) != 0 : false;
115
116 // break-up arrays
117 wxArrayString indices = GetArrayFromString(index, _T(","));
118 wxArrayString fgarray = GetArrayFromString(fg, _T(","));
119 wxArrayString bgarray = GetArrayFromString(bg, _T(","));
120
121 wxColour fgcolour = wxNullColour;
122 if (fgarray.GetCount() == 3)
123 {
124 long R=0, G=0, B=0;
125 fgarray[0].ToLong(&R);
126 fgarray[1].ToLong(&G);
127 fgarray[2].ToLong(&B);
128 fgcolour.Set((unsigned char)R,(unsigned char)G,(unsigned char)B);
129 }
130 wxColour bgcolour = wxNullColour;
131 if (bgarray.GetCount() == 3)
132 {
133 long R=0, G=0, B=0;
134 bgarray[0].ToLong(&R);
135 bgarray[1].ToLong(&G);
136 bgarray[2].ToLong(&B);
137 bgcolour.Set((unsigned char)R,(unsigned char)G,(unsigned char)B);
138 }
139
140 for (size_t i = 0; i < indices.GetCount(); ++i)
141 {
142 if (indices[i].IsEmpty())
143 continue;
144 long value = 0;
145 indices[i].ToLong(&value);
146
147 switch (value)
148 {
149 case cbSELECTION:
150 foundSelection = true;
151 break;
152 case cbHIGHLIGHT_LINE:
153 foundActiveLine = true;
154 break;
155 case wxSCI_STYLE_BRACELIGHT:
156 foundMatchBrace = true;
157 break;
158 case wxSCI_STYLE_BRACEBAD:
159 foundBraceError = true;
160 break;
161 case wxSCI_STYLE_INDENTGUIDE:
162 foundIndentationGuide = true;
163 break;
164 }
165
166 // LOGSTREAM << _("Adding style: ") << name << _T("(") << value << _T(")\n");
167 m_pTarget->AddOption(language, name, value,
168 fgcolour,
169 bgcolour,
170 bold,
171 italics,
172 underlined,
173 value >= 0);
174 }
175 }
176 style = style->NextSiblingElement("Style");
177 }
178
179 if (!foundSelection)
180 {
181 m_pTarget->AddOption(language, wxT("Selection"), cbSELECTION, wxNullColour,
182 wxColour(217, 217, 217), false, false, false, false);
183 }
184 if (!foundActiveLine)
185 {
186 m_pTarget->AddOption(language, wxT("Active line"), cbHIGHLIGHT_LINE, wxNullColour,
187 wxColour(255, 255, 160), false, false, false, false);
188 }
189 if (!foundMatchBrace)
190 {
191 m_pTarget->AddOption(language, wxT("Matching brace highlight"), wxSCI_STYLE_BRACELIGHT,
192 wxColour(0, 0, 0), wxColour(128, 255, 255), true, false, false, true);
193 }
194 if (!foundBraceError)
195 {
196 m_pTarget->AddOption(language, wxT("No matching brace highlight"), wxSCI_STYLE_BRACEBAD,
197 wxColour(255, 255, 255), wxColour(255, 0, 0), true, false, false, true);
198 }
199 if (!foundIndentationGuide)
200 {
201 m_pTarget->AddOption(language, wxT("Indentation guide"), wxSCI_STYLE_INDENTGUIDE,
202 wxColour(55, 55, 55), wxNullColour, false, false, false, true);
203 }
204 }
205
DoKeywords(HighlightLanguage language,TiXmlElement * node)206 void EditorLexerLoader::DoKeywords(HighlightLanguage language, TiXmlElement* node)
207 {
208 TiXmlElement* keywords = node->FirstChildElement("Keywords");
209 if (!keywords)
210 return;
211 DoSingleKeywordNode(language, keywords, _T("Language"));
212 DoSingleKeywordNode(language, keywords, _T("Documentation"));
213 DoSingleKeywordNode(language, keywords, _T("User"));
214 DoSingleKeywordNode(language, keywords, _T("Set"));
215 }
216
DoSingleKeywordNode(HighlightLanguage language,TiXmlElement * node,const wxString & nodename)217 void EditorLexerLoader::DoSingleKeywordNode(HighlightLanguage language, TiXmlElement* node, const wxString& nodename)
218 {
219 TiXmlElement* keywords = node->FirstChildElement(nodename.mb_str());
220 while (keywords)
221 {
222 // LOGSTREAM << "Found " << nodename << '\n';
223 int keyidx = keywords->Attribute("index") ? atol(keywords->Attribute("index")) : -1;
224 // LOGSTREAM << "keyidx=" << keyidx << '\n';
225 if (keyidx != -1)
226 {
227 // the lexer file contains keywords indented - remove the extra spacing and EOLs
228 wxRegEx regex(_T("[[:space:]]+"));
229 wxString value(keywords->Attribute("value"), wxConvUTF8);
230 regex.Replace(&value, _T(" "));
231
232 #if wxCHECK_VERSION(3, 0, 0)
233 m_pTarget->SetKeywords(language, keyidx, value );
234 #else
235 m_pTarget->SetKeywords(language, keyidx, wxString ( value, wxConvUTF8 ) );
236 #endif
237 }
238
239 keywords = keywords->NextSiblingElement(nodename.mb_str());
240 }
241 }
242
DoSampleCode(HighlightLanguage language,TiXmlElement * node)243 void EditorLexerLoader::DoSampleCode(HighlightLanguage language, TiXmlElement* node)
244 {
245 TiXmlElement* sample = node->FirstChildElement("SampleCode");
246 if (!sample)
247 return;
248 wxString code = wxString ( sample->Attribute("value"), wxConvUTF8 );
249 if (code.IsEmpty())
250 return;
251 int breakLine = sample->Attribute("breakpoint_line") ? atol(sample->Attribute("breakpoint_line")) : -1;
252 int debugLine = sample->Attribute("debug_line") ? atol(sample->Attribute("debug_line")) : -1;
253 int errorLine = sample->Attribute("error_line") ? atol(sample->Attribute("error_line")) : -1;
254 m_pTarget->SetSampleCode(language, code, breakLine, debugLine, errorLine);
255 }
256
DoLangAttributes(HighlightLanguage language,TiXmlElement * node)257 void EditorLexerLoader::DoLangAttributes(HighlightLanguage language, TiXmlElement* node)
258 {
259 TiXmlElement* attribs = node->FirstChildElement("LanguageAttributes");
260 if ( !attribs )
261 return;
262
263 bool CaseSensitive = attribs->Attribute("CaseSensitive") ? atol(attribs->Attribute("CaseSensitive")) != 0 : false;
264 m_pTarget->SetCaseSensitivity(language, CaseSensitive);
265
266
267 CommentToken token;
268 token.lineComment = wxString( attribs->Attribute("LineComment"), wxConvUTF8 );
269 token.doxygenLineComment = wxString( attribs->Attribute("DoxygenLineComment"), wxConvUTF8 );
270 token.streamCommentStart = wxString( attribs->Attribute("StreamCommentStart"), wxConvUTF8 );
271 token.streamCommentEnd = wxString( attribs->Attribute("StreamCommentEnd"), wxConvUTF8 );
272 token.doxygenStreamCommentStart = wxString( attribs->Attribute("DoxygenStreamCommentStart"), wxConvUTF8 );
273 token.doxygenStreamCommentEnd = wxString( attribs->Attribute("DoxygenStreamCommentEnd"), wxConvUTF8 );
274 token.boxCommentStart = wxString( attribs->Attribute("BoxCommentStart"), wxConvUTF8 );
275 token.boxCommentMid = wxString( attribs->Attribute("BoxCommentMid"), wxConvUTF8 );
276 token.boxCommentEnd = wxString( attribs->Attribute("BoxCommentEnd"), wxConvUTF8 );
277
278 m_pTarget->SetCommentToken(language, token);
279
280 std::set<int> CommentLexerStyles, CharacterLexerStyles, StringLexerStyles, PreprocessorLexerStyles;
281 bool hasLexerStylesSet = false;
282 hasLexerStylesSet |= DoLangAttributesLexerStyles(attribs, "LexerCommentStyles", CommentLexerStyles);
283 hasLexerStylesSet |= DoLangAttributesLexerStyles(attribs, "LexerCharacterStyles", CharacterLexerStyles);
284 hasLexerStylesSet |= DoLangAttributesLexerStyles(attribs, "LexerStringStyles", StringLexerStyles);
285 hasLexerStylesSet |= DoLangAttributesLexerStyles(attribs, "LexerPreprocessorStyles", PreprocessorLexerStyles);
286
287 // only set styles if configured. Since different languages use the same lexer.
288 // So if any of the languages has these styles configured we use them.
289 // If another language has not configured them the previously defined wont get lost.
290 if ( hasLexerStylesSet )
291 {
292 m_pTarget->SetCommentLexerStyles(language, CommentLexerStyles);
293 m_pTarget->SetStringLexerStyles(language, StringLexerStyles);
294 m_pTarget->SetCharacterLexerStyles(language, CharacterLexerStyles);
295 m_pTarget->SetPreprocessorLexerStyles(language, PreprocessorLexerStyles);
296 }
297 }
298
DoLangAttributesLexerStyles(TiXmlElement * attribs,const char * attributeName,std::set<int> & styles)299 bool EditorLexerLoader::DoLangAttributesLexerStyles(TiXmlElement* attribs, const char *attributeName, std::set<int> &styles)
300 {
301 styles.clear();
302 wxString str = wxString ( attribs->Attribute(attributeName), wxConvUTF8 );
303 wxArrayString strarray = GetArrayFromString(str, _T(","));
304
305 for ( unsigned int i = 0; i < strarray.Count(); ++i )
306 {
307 long style;
308 strarray[i].ToLong(&style);
309 styles.insert((unsigned int)style);
310 }
311
312 return !str.IsEmpty();
313 }
314