1 // SciTE - Scintilla based Text Editor
2 /** @file SciTEProps.cxx
3 ** Properties management.
4 **/
5 // Copyright 1998-2011 by Neil Hodgson <neilh@scintilla.org>
6 // The License.txt file describes the conditions under which this software may be distributed.
7
8 #include <cstddef>
9 #include <cstdlib>
10 #include <cstdint>
11 #include <cstring>
12 #include <cstdio>
13 #include <ctime>
14 #include <clocale>
15
16 #include <string>
17 #include <string_view>
18 #include <vector>
19 #include <map>
20 #include <set>
21 #include <algorithm>
22 #include <memory>
23 #include <chrono>
24 #include <atomic>
25 #include <mutex>
26
27 #include <fcntl.h>
28
29 #include "ILexer.h"
30
31 #include "ScintillaTypes.h"
32 #include "ScintillaMessages.h"
33 #include "ScintillaCall.h"
34
35 #include "Scintilla.h"
36 #include "SciLexer.h"
37
38 #include "GUI.h"
39 #include "ScintillaWindow.h"
40
41 #if defined(__unix__) || defined(__APPLE__)
42
43 const GUI::gui_char menuAccessIndicator[] = GUI_TEXT("_");
44
45 #else
46
47 const GUI::gui_char menuAccessIndicator[] = GUI_TEXT("&");
48
49 #endif
50
51 #include "StringList.h"
52 #include "StringHelpers.h"
53 #include "FilePath.h"
54 #include "LexillaLibrary.h"
55 #include "StyleDefinition.h"
56 #include "PropSetFile.h"
57 #include "StyleWriter.h"
58 #include "Extender.h"
59 #include "SciTE.h"
60 #include "JobQueue.h"
61 #include "Cookie.h"
62 #include "Worker.h"
63 #include "MatchMarker.h"
64 #include "EditorConfig.h"
65 #include "SciTEBase.h"
66 #include "IFaceTable.h"
67
SetImportMenu()68 void SciTEBase::SetImportMenu() {
69 for (int i = 0; i < importMax; i++) {
70 DestroyMenuItem(menuOptions, importCmdID + i);
71 }
72 if (!importFiles.empty()) {
73 for (int stackPos = 0; stackPos < static_cast<int>(importFiles.size()) && stackPos < importMax; stackPos++) {
74 const int itemID = importCmdID + stackPos;
75 if (importFiles[stackPos].IsSet()) {
76 GUI::gui_string entry = localiser.Text("Open");
77 entry += GUI_TEXT(" ");
78 entry += importFiles[stackPos].Name().AsInternal();
79 SetMenuItem(menuOptions, IMPORT_START + stackPos, itemID, entry.c_str());
80 }
81 }
82 }
83 }
84
ImportMenu(int pos)85 void SciTEBase::ImportMenu(int pos) {
86 if (pos >= 0) {
87 if (importFiles[pos].IsSet()) {
88 Open(importFiles[pos]);
89 }
90 }
91 }
92
SetLanguageMenu()93 void SciTEBase::SetLanguageMenu() {
94 for (int i = 0; i < 100; i++) {
95 DestroyMenuItem(menuLanguage, languageCmdID + i);
96 }
97 for (unsigned int item = 0; item < languageMenu.size(); item++) {
98 const int itemID = languageCmdID + item;
99 GUI::gui_string entry = localiser.Text(languageMenu[item].menuItem.c_str());
100 if (languageMenu[item].menuKey.length()) {
101 #if defined(GTK)
102 entry += GUI_TEXT(" ");
103 #else
104 entry += GUI_TEXT("\t");
105 #endif
106 entry += GUI::StringFromUTF8(languageMenu[item].menuKey);
107 }
108 if (entry.size() && entry[0] != '#') {
109 SetMenuItem(menuLanguage, item, itemID, entry.c_str());
110 }
111 }
112 }
113
114 // Null except on Windows where it may be overridden
ReadEmbeddedProperties()115 void SciTEBase::ReadEmbeddedProperties() {
116 }
117
118 const GUI::gui_char propLocalFileName[] = GUI_TEXT("SciTE.properties");
119 const GUI::gui_char propDirectoryFileName[] = GUI_TEXT("SciTEDirectory.properties");
120
ReadEnvironment()121 void SciTEBase::ReadEnvironment() {
122 #if defined(__unix__) || defined(__APPLE__)
123 extern char **environ;
124 char **e = environ;
125 #else
126 char **e = _environ;
127 #endif
128 for (; e && *e; e++) {
129 char key[1024] = "";
130 char *k = *e;
131 char *v = strchr(k, '=');
132 if (v && (static_cast<size_t>(v - k) < sizeof(key))) {
133 memcpy(key, k, v - k);
134 key[v - k] = '\0';
135 propsPlatform.Set(key, v + 1);
136 }
137 }
138 }
139
140 /**
141 Read global and user properties files.
142 */
ReadGlobalPropFile()143 void SciTEBase::ReadGlobalPropFile() {
144 // Appearance and Contrast may be read in embedded or global properties
145 // so set them in deepest property set propsPlatform.
146 propsPlatform.Set("Appearance", StdStringFromInteger(appearance.dark));
147 propsPlatform.Set("Contrast", StdStringFromInteger(appearance.highContrast));
148
149 std::string excludes;
150 std::string includes;
151
152 // Want to apply imports.exclude and imports.include but these may well be in
153 // user properties.
154
155 for (int attempt=0; attempt<2; attempt++) {
156
157 std::string excludesRead = props.GetString("imports.exclude");
158 std::string includesRead = props.GetString("imports.include");
159 if ((attempt > 0) && ((excludesRead == excludes) && (includesRead == includes)))
160 break;
161
162 excludes = excludesRead;
163 includes = includesRead;
164
165 filter.SetFilter(excludes.c_str(), includes.c_str());
166
167 importFiles.clear();
168
169 ReadEmbeddedProperties();
170
171 propsBase.Clear();
172 FilePath propfileBase = GetDefaultPropertiesFileName();
173 propsBase.Read(propfileBase, propfileBase.Directory(), filter, &importFiles, 0);
174
175 propsUser.Clear();
176 FilePath propfileUser = GetUserPropertiesFileName();
177 propsUser.Read(propfileUser, propfileUser.Directory(), filter, &importFiles, 0);
178 }
179
180 if (!localiser.read) {
181 ReadLocalization();
182 }
183 }
184
ReadAbbrevPropFile()185 void SciTEBase::ReadAbbrevPropFile() {
186 propsAbbrev.Clear();
187 propsAbbrev.Read(pathAbbreviations, pathAbbreviations.Directory(), filter, &importFiles, 0);
188 }
189
190 /**
191 Reads the directory properties file depending on the variable
192 "properties.directory.enable". Also sets the variable $(SciteDirectoryHome) to the path
193 where this property file is found. If it is not found $(SciteDirectoryHome) will
194 be set to $(FilePath).
195 */
ReadDirectoryPropFile()196 void SciTEBase::ReadDirectoryPropFile() {
197 propsDirectory.Clear();
198
199 if (props.GetInt("properties.directory.enable") != 0) {
200 FilePath propfile = GetDirectoryPropertiesFileName();
201 props.Set("SciteDirectoryHome", propfile.Directory().AsUTF8().c_str());
202
203 propsDirectory.Read(propfile, propfile.Directory(), filter, nullptr, 0);
204 }
205 }
206
207 /**
208 Read local and directory properties file.
209 */
ReadLocalPropFile()210 void SciTEBase::ReadLocalPropFile() {
211 // The directory properties acts like a base local properties file.
212 // Therefore it must be read always before reading the local prop file.
213 ReadDirectoryPropFile();
214
215 FilePath propfile = GetLocalPropertiesFileName();
216
217 propsLocal.Clear();
218 propsLocal.Read(propfile, propfile.Directory(), filter, nullptr, 0);
219
220 props.Set("Chrome", "#C0C0C0");
221 props.Set("ChromeHighlight", "#FFFFFF");
222
223 FilePath fileDirectory = filePath.Directory();
224 editorConfig->Clear();
225 if (props.GetInt("editor.config.enable", 0)) {
226 editorConfig->ReadFromDirectory(fileDirectory);
227 }
228 }
229
ColourOfProperty(const PropSetFile & props,const char * key,SA::Colour colourDefault)230 SA::Colour ColourOfProperty(const PropSetFile &props, const char *key, SA::Colour colourDefault) {
231 std::string colour = props.GetExpandedString(key);
232 if (colour.length()) {
233 return ColourFromString(colour);
234 }
235 return colourDefault;
236 }
237
238 /**
239 * Put the next property item from the given property string
240 * into the buffer pointed by @a pPropItem.
241 * @return NULL if the end of the list is met, else, it points to the next item.
242 */
GetNextPropItem(const char * pStart,char * pPropItem,int maxLen)243 const char *SciTEBase::GetNextPropItem(
244 const char *pStart, /**< the property string to parse for the first call,
245 * pointer returned by the previous call for the following. */
246 char *pPropItem, ///< pointer on a buffer receiving the requested prop item
247 int maxLen) { ///< size of the above buffer
248 ptrdiff_t size = maxLen - 1;
249
250 *pPropItem = '\0';
251 if (!pStart) {
252 return nullptr;
253 }
254 const char *pNext = strchr(pStart, ',');
255 if (pNext) { // Separator is found
256 if (size > pNext - pStart) {
257 // Found string fits in buffer
258 size = pNext - pStart;
259 }
260 pNext++;
261 }
262 strncpy(pPropItem, pStart, size);
263 pPropItem[size] = '\0';
264 return pNext;
265 }
266
StyleString(const char * lang,int style) const267 std::string SciTEBase::StyleString(const char *lang, int style) const {
268 char key[200];
269 sprintf(key, "style.%s.%0d", lang, style);
270 return props.GetExpandedString(key);
271 }
272
StyleDefinitionFor(int style)273 StyleDefinition SciTEBase::StyleDefinitionFor(int style) {
274 const std::string languageName = !StartsWith(language, "lpeg_") ? language : "lpeg";
275
276 const std::string ssDefault = StyleString("*", style);
277 std::string ss = StyleString(languageName.c_str(), style);
278
279 if (!subStyleBases.empty()) {
280 const int baseStyle = wEditor.StyleFromSubStyle(style);
281 if (baseStyle != style) {
282 const int primaryStyle = wEditor.PrimaryStyleFromStyle(style);
283 const int distanceSecondary = (style == primaryStyle) ? 0 : wEditor.DistanceToSecondaryStyles();
284 const int primaryBase = baseStyle - distanceSecondary;
285 const int subStylesStart = wEditor.SubStylesStart(primaryBase);
286 const int subStylesLength = wEditor.SubStylesLength(primaryBase);
287 const int subStyle = style - (subStylesStart + distanceSecondary);
288 if (subStyle < subStylesLength) {
289 char key[200];
290 sprintf(key, "style.%s.%0d.%0d", languageName.c_str(), baseStyle, subStyle + 1);
291 ss = props.GetNewExpandString(key);
292 }
293 }
294 }
295
296 StyleDefinition sd(ssDefault);
297 sd.ParseStyleDefinition(ss);
298 return sd;
299 }
300
SetOneStyle(GUI::ScintillaWindow & win,int style,const StyleDefinition & sd)301 void SciTEBase::SetOneStyle(GUI::ScintillaWindow &win, int style, const StyleDefinition &sd) {
302 if (sd.specified & StyleDefinition::sdItalics)
303 win.StyleSetItalic(style, sd.italics);
304 if (sd.specified & StyleDefinition::sdWeight)
305 win.StyleSetWeight(style, sd.weight);
306 if (sd.specified & StyleDefinition::sdFont)
307 win.StyleSetFont(style, sd.font.c_str());
308 if (sd.specified & StyleDefinition::sdFore)
309 win.StyleSetFore(style, sd.Fore());
310 if (sd.specified & StyleDefinition::sdBack)
311 win.StyleSetBack(style, sd.Back());
312 if (sd.specified & StyleDefinition::sdSize)
313 win.StyleSetSizeFractional(style, sd.FractionalSize());
314 if (sd.specified & StyleDefinition::sdEOLFilled)
315 win.StyleSetEOLFilled(style, sd.eolfilled);
316 if (sd.specified & StyleDefinition::sdUnderlined)
317 win.StyleSetUnderline(style, sd.underlined);
318 if (sd.specified & StyleDefinition::sdCaseForce)
319 win.StyleSetCase(style, sd.caseForce);
320 if (sd.specified & StyleDefinition::sdVisible)
321 win.StyleSetVisible(style, sd.visible);
322 if (sd.specified & StyleDefinition::sdChangeable)
323 win.StyleSetChangeable(style, sd.changeable);
324 win.StyleSetCharacterSet(style, characterSet);
325 }
326
SetStyleBlock(GUI::ScintillaWindow & win,const char * lang,int start,int last)327 void SciTEBase::SetStyleBlock(GUI::ScintillaWindow &win, const char *lang, int start, int last) {
328 for (int style = start; style <= last; style++) {
329 if (style != StyleDefault) {
330 char key[200];
331 sprintf(key, "style.%s.%0d", lang, style-start);
332 std::string sval = props.GetExpandedString(key);
333 if (sval.length()) {
334 SetOneStyle(win, style, StyleDefinition(sval));
335 }
336 }
337 }
338 }
339
SetStyleFor(GUI::ScintillaWindow & win,const char * lang)340 void SciTEBase::SetStyleFor(GUI::ScintillaWindow &win, const char *lang) {
341 SetStyleBlock(win, lang, 0, StyleMax);
342 }
343
SetOneIndicator(GUI::ScintillaWindow & win,int indicator,const IndicatorDefinition & ind)344 void SciTEBase::SetOneIndicator(GUI::ScintillaWindow &win, int indicator, const IndicatorDefinition &ind) {
345 win.IndicSetStyle(indicator, ind.style);
346 win.IndicSetFore(indicator, ind.colour);
347 win.IndicSetAlpha(indicator, ind.fillAlpha);
348 win.IndicSetOutlineAlpha(indicator, ind.outlineAlpha);
349 win.IndicSetUnder(indicator, ind.under);
350 }
351
ExtensionFileName() const352 std::string SciTEBase::ExtensionFileName() const {
353 if (CurrentBufferConst()->overrideExtension.length()) {
354 return CurrentBufferConst()->overrideExtension;
355 } else {
356 FilePath name = FileNameExt();
357 if (name.IsSet()) {
358 #if !defined(GTK)
359 // Force extension to lower case
360 std::string extension = name.Extension().AsUTF8();
361 if (extension.empty()) {
362 return name.AsUTF8();
363 } else {
364 LowerCaseAZ(extension);
365 return name.BaseName().AsUTF8() + "." + extension;
366 }
367 #else
368 return name.AsUTF8();
369 #endif
370 } else {
371 return props.GetString("default.file.ext");
372 }
373 }
374 }
375
ForwardPropertyToEditor(const char * key)376 void SciTEBase::ForwardPropertyToEditor(const char *key) {
377 if (props.Exists(key)) {
378 std::string value = props.GetExpandedString(key);
379 wEditor.SetProperty(key, value.c_str());
380 wOutput.SetProperty(key, value.c_str());
381 }
382 }
383
DefineMarker(SA::MarkerOutline marker,SA::MarkerSymbol markerType,SA::Colour fore,SA::Colour back,SA::Colour backSelected)384 void SciTEBase::DefineMarker(SA::MarkerOutline marker, SA::MarkerSymbol markerType, SA::Colour fore, SA::Colour back, SA::Colour backSelected) {
385 const int markerNumber = static_cast<int>(marker);
386 wEditor.MarkerDefine(markerNumber, markerType);
387 wEditor.MarkerSetFore(markerNumber, fore);
388 wEditor.MarkerSetBack(markerNumber, back);
389 wEditor.MarkerSetBackSelected(markerNumber, backSelected);
390 }
391
ReadAPI(const std::string & fileNameForExtension)392 void SciTEBase::ReadAPI(const std::string &fileNameForExtension) {
393 std::string sApiFileNames = props.GetNewExpandString("api.",
394 fileNameForExtension.c_str());
395 if (sApiFileNames.length() > 0) {
396 std::vector<std::string> vApiFileNames = StringSplit(sApiFileNames, ';');
397 std::vector<char> data;
398
399 // Load files into data
400 for (const std::string &vApiFileName : vApiFileNames) {
401 std::string contents = FilePath(GUI::StringFromUTF8(vApiFileName)).Read();
402 data.insert(data.end(), contents.begin(), contents.end());
403 }
404
405 // Initialise apis
406 if (data.size() > 0) {
407 apis.Set(data);
408 }
409 }
410 }
411
FindLanguageProperty(const char * pattern,const char * defaultValue)412 std::string SciTEBase::FindLanguageProperty(const char *pattern, const char *defaultValue) {
413 std::string key = pattern;
414 Substitute(key, "*", language.c_str());
415 std::string ret = props.GetExpandedString(key.c_str());
416 if (ret == "")
417 ret = props.GetExpandedString(pattern);
418 if (ret == "")
419 ret = defaultValue;
420 return ret;
421 }
422
423 /**
424 * A list of all the properties that should be forwarded to Scintilla lexers.
425 */
426 static const char *propertiesToForward[] = {
427 "fold.lpeg.by.indentation",
428 "lexer.lpeg.color.theme",
429 "lexer.lpeg.home",
430 "lexer.lpeg.script",
431 //++Autogenerated -- run ../scripts/RegenerateSource.py to regenerate
432 //**\(\t"\*",\n\)
433 "asp.default.language",
434 "fold",
435 "fold.abl.comment.multiline",
436 "fold.abl.syntax.based",
437 "fold.asm.comment.explicit",
438 "fold.asm.comment.multiline",
439 "fold.asm.explicit.anywhere",
440 "fold.asm.explicit.end",
441 "fold.asm.explicit.start",
442 "fold.asm.syntax.based",
443 "fold.at.else",
444 "fold.baan.inner.level",
445 "fold.baan.keywords.based",
446 "fold.baan.sections",
447 "fold.baan.syntax.based",
448 "fold.basic.comment.explicit",
449 "fold.basic.explicit.anywhere",
450 "fold.basic.explicit.end",
451 "fold.basic.explicit.start",
452 "fold.basic.syntax.based",
453 "fold.cil.comment.multiline",
454 "fold.coffeescript.comment",
455 "fold.comment",
456 "fold.comment.nimrod",
457 "fold.comment.yaml",
458 "fold.compact",
459 "fold.cpp.comment.explicit",
460 "fold.cpp.comment.multiline",
461 "fold.cpp.explicit.anywhere",
462 "fold.cpp.explicit.end",
463 "fold.cpp.explicit.start",
464 "fold.cpp.preprocessor.at.else",
465 "fold.cpp.syntax.based",
466 "fold.d.comment.explicit",
467 "fold.d.comment.multiline",
468 "fold.d.explicit.anywhere",
469 "fold.d.explicit.end",
470 "fold.d.explicit.start",
471 "fold.d.syntax.based",
472 "fold.dataflex.compilerlist",
473 "fold.directive",
474 "fold.haskell.imports",
475 "fold.html",
476 "fold.html.preprocessor",
477 "fold.hypertext.comment",
478 "fold.hypertext.heredoc",
479 "fold.perl.at.else",
480 "fold.perl.comment.explicit",
481 "fold.perl.package",
482 "fold.perl.pod",
483 "fold.preprocessor",
484 "fold.quotes.nimrod",
485 "fold.quotes.python",
486 "fold.raku.comment.multiline",
487 "fold.raku.comment.pod",
488 "fold.rust.comment.explicit",
489 "fold.rust.comment.multiline",
490 "fold.rust.explicit.anywhere",
491 "fold.rust.explicit.end",
492 "fold.rust.explicit.start",
493 "fold.rust.syntax.based",
494 "fold.sql.at.else",
495 "fold.sql.only.begin",
496 "fold.verilog.flags",
497 "fold.xml.at.tag.open",
498 "html.tags.case.sensitive",
499 "lexer.as.comment.character",
500 "lexer.asm.comment.delimiter",
501 "lexer.baan.styling.within.preprocessor",
502 "lexer.caml.magic",
503 "lexer.cpp.allow.dollars",
504 "lexer.cpp.backquoted.strings",
505 "lexer.cpp.escape.sequence",
506 "lexer.cpp.hashquoted.strings",
507 "lexer.cpp.track.preprocessor",
508 "lexer.cpp.triplequoted.strings",
509 "lexer.cpp.update.preprocessor",
510 "lexer.cpp.verbatim.strings.allow.escapes",
511 "lexer.css.hss.language",
512 "lexer.css.less.language",
513 "lexer.css.scss.language",
514 "lexer.d.fold.at.else",
515 "lexer.edifact.highlight.un.all",
516 "lexer.errorlist.escape.sequences",
517 "lexer.errorlist.value.separate",
518 "lexer.flagship.styling.within.preprocessor",
519 "lexer.haskell.allow.hash",
520 "lexer.haskell.allow.questionmark",
521 "lexer.haskell.allow.quotes",
522 "lexer.haskell.cpp",
523 "lexer.haskell.import.safe",
524 "lexer.html.django",
525 "lexer.html.mako",
526 "lexer.json.allow.comments",
527 "lexer.json.escape.sequence",
528 "lexer.metapost.comment.process",
529 "lexer.metapost.interface.default",
530 "lexer.nim.raw.strings.highlight.ident",
531 "lexer.pascal.smart.highlighting",
532 "lexer.props.allow.initial.spaces",
533 "lexer.python.keywords2.no.sub.identifiers",
534 "lexer.python.literals.binary",
535 "lexer.python.strings.b",
536 "lexer.python.strings.f",
537 "lexer.python.strings.over.newline",
538 "lexer.python.strings.u",
539 "lexer.python.unicode.identifiers",
540 "lexer.rust.fold.at.else",
541 "lexer.sql.allow.dotted.word",
542 "lexer.sql.backticks.identifier",
543 "lexer.sql.numbersign.comment",
544 "lexer.tex.auto.if",
545 "lexer.tex.comment.process",
546 "lexer.tex.interface.default",
547 "lexer.tex.use.keywords",
548 "lexer.verilog.allupperkeywords",
549 "lexer.verilog.fold.preprocessor.else",
550 "lexer.verilog.portstyling",
551 "lexer.verilog.track.preprocessor",
552 "lexer.verilog.update.preprocessor",
553 "lexer.xml.allow.scripts",
554 "nsis.ignorecase",
555 "nsis.uservars",
556 "ps.level",
557 "sql.backslash.escapes",
558 "styling.within.preprocessor",
559 "tab.timmy.whinge.level",
560
561 //--Autogenerated -- end of automatically generated section
562
563 nullptr,
564 };
565
566 /* XPM */
567 static const char *bookmarkBluegem[] = {
568 /* width height num_colors chars_per_pixel */
569 " 15 15 64 1",
570 /* colors */
571 " c none",
572 ". c #0c0630",
573 "# c #8c8a8c",
574 "a c #244a84",
575 "b c #545254",
576 "c c #cccecc",
577 "d c #949594",
578 "e c #346ab4",
579 "f c #242644",
580 "g c #3c3e3c",
581 "h c #6ca6fc",
582 "i c #143789",
583 "j c #204990",
584 "k c #5c8dec",
585 "l c #707070",
586 "m c #3c82dc",
587 "n c #345db4",
588 "o c #619df7",
589 "p c #acacac",
590 "q c #346ad4",
591 "r c #1c3264",
592 "s c #174091",
593 "t c #5482df",
594 "u c #4470c4",
595 "v c #2450a0",
596 "w c #14162c",
597 "x c #5c94f6",
598 "y c #b7b8b7",
599 "z c #646464",
600 "A c #3c68b8",
601 "B c #7cb8fc",
602 "C c #7c7a7c",
603 "D c #3462b9",
604 "E c #7c7eac",
605 "F c #44464c",
606 "G c #a4a4a4",
607 "H c #24224c",
608 "I c #282668",
609 "J c #5c5a8c",
610 "K c #7c8ebc",
611 "L c #dcd7e4",
612 "M c #141244",
613 "N c #1c2e5c",
614 "O c #24327c",
615 "P c #4472cc",
616 "Q c #6ca2fc",
617 "R c #74b2fc",
618 "S c #24367c",
619 "T c #b4b2c4",
620 "U c #403e58",
621 "V c #4c7fd6",
622 "W c #24428c",
623 "X c #747284",
624 "Y c #142e7c",
625 "Z c #64a2fc",
626 "0 c #3c72dc",
627 "1 c #bcbebc",
628 "2 c #6c6a6c",
629 "3 c #848284",
630 "4 c #2c5098",
631 "5 c #1c1a1c",
632 "6 c #243250",
633 "7 c #7cbefc",
634 "8 c #d4d2d4",
635 /* pixels */
636 " yCbgbCy ",
637 " #zGGyGGz# ",
638 " #zXTLLLTXz# ",
639 " p5UJEKKKEJU5p ",
640 " lfISa444aSIfl ",
641 " wIYij444jsYIw ",
642 " .OsvnAAAnvsO. ",
643 " MWvDuVVVPDvWM ",
644 " HsDPVkxxtPDsH ",
645 " UiAtxohZxtuiU ",
646 " pNnkQRBRhkDNp ",
647 " 1FrqoR7Bo0rF1 ",
648 " 8GC6aemea6CG8 ",
649 " cG3l2z2l3Gc ",
650 " 1GdddG1 "
651 };
652
GetFileNameProperty(const char * name)653 std::string SciTEBase::GetFileNameProperty(const char *name) {
654 std::string namePlusDot = name;
655 namePlusDot.append(".");
656 std::string valueForFileName = props.GetNewExpandString(namePlusDot.c_str(),
657 ExtensionFileName().c_str());
658 if (valueForFileName.length() != 0) {
659 return valueForFileName;
660 } else {
661 return props.GetString(name);
662 }
663 }
664
ReadProperties()665 void SciTEBase::ReadProperties() {
666 if (extender)
667 extender->Clear();
668
669 const std::string lexillaPath = props.GetExpandedString("lexilla.path");
670 LexillaLoad(lexillaPath.empty() ? "." : lexillaPath);
671
672 std::vector<std::string> libraryProperties = LexillaLibraryProperties();
673 for (std::string property : libraryProperties) {
674 std::string key("lexilla.context.");
675 key += property;
676 std::string value = props.GetExpandedString(key.c_str());
677 LexillaSetProperty(property.c_str(), value.c_str());
678 }
679
680 const std::string fileNameForExtension = ExtensionFileName();
681
682 std::string modulePath = props.GetNewExpandString("lexerpath.",
683 fileNameForExtension.c_str());
684 if (modulePath.length())
685 wEditor.LoadLexerLibrary(modulePath.c_str());
686 language = props.GetNewExpandString("lexer.", fileNameForExtension.c_str());
687 if (static_cast<int>(wEditor.DocumentOptions()) & static_cast<int>(SA::DocumentOption::StylesNone)) {
688 language = "";
689 }
690 if (language.length()) {
691 if (StartsWith(language, "script_")) {
692 wEditor.SetLexer(SCLEX_CONTAINER);
693 } else {
694 std::string languageCurrent = wEditor.LexerLanguage();
695 if (language != languageCurrent) {
696 Scintilla::ILexer5 *plexer = LexillaCreateLexer(language);
697 if (plexer) {
698 wEditor.SetILexer(plexer);
699 } else {
700 wEditor.SetLexerLanguage(language.c_str());
701 }
702 }
703 }
704 } else {
705 wEditor.SetLexer(SCLEX_NULL);
706 }
707
708 props.Set("Language", language.c_str());
709
710 lexLanguage = wEditor.Lexer();
711
712 Scintilla::ILexer5 *plexerErrorlist = LexillaCreateLexer("errorlist");
713 if (plexerErrorlist) {
714 wOutput.SetILexer(plexerErrorlist);
715 } else {
716 wOutput.SetLexerLanguage("errorlist");
717 }
718
719 const std::string kw0 = props.GetNewExpandString("keywords.", fileNameForExtension.c_str());
720 wEditor.SetKeyWords(0, kw0.c_str());
721
722 for (int wl = 1; wl <= SA::KeywordsetMax; wl++) {
723 std::string kwk = StdStringFromInteger(wl+1);
724 kwk += '.';
725 kwk.insert(0, "keywords");
726 const std::string kw = props.GetNewExpandString(kwk.c_str(), fileNameForExtension.c_str());
727 wEditor.SetKeyWords(wl, kw.c_str());
728 }
729
730 subStyleBases = wEditor.SubStyleBases();
731 if (!subStyleBases.empty()) {
732 wEditor.FreeSubStyles();
733
734 for (const unsigned char subStyleBase : subStyleBases) {
735 //substyles.cpp.11=2
736 const std::string sStyleBase = StdStringFromInteger(subStyleBase);
737 std::string ssSubStylesKey = "substyles.";
738 ssSubStylesKey += language;
739 ssSubStylesKey += ".";
740 ssSubStylesKey += sStyleBase;
741 std::string ssNumber = props.GetNewExpandString(ssSubStylesKey.c_str());
742 int subStyleIdentifiers = atoi(ssNumber.c_str());
743
744 int subStyleIdentifiersStart = 0;
745 if (subStyleIdentifiers) {
746 subStyleIdentifiersStart = wEditor.AllocateSubStyles(subStyleBase, subStyleIdentifiers);
747 if (subStyleIdentifiersStart < 0)
748 subStyleIdentifiers = 0;
749 }
750 for (int subStyle=0; subStyle<subStyleIdentifiers; subStyle++) {
751 // substylewords.11.1.$(file.patterns.cpp)=CharacterSet LexAccessor SString WordList
752 std::string ssWordsKey = "substylewords.";
753 ssWordsKey += sStyleBase;
754 ssWordsKey += ".";
755 ssWordsKey += StdStringFromInteger(subStyle + 1);
756 ssWordsKey += ".";
757 std::string ssWords = props.GetNewExpandString(ssWordsKey.c_str(), fileNameForExtension.c_str());
758 wEditor.SetIdentifiers(subStyleIdentifiersStart + subStyle, ssWords.c_str());
759 }
760 }
761 }
762
763 FilePath homepath = GetSciteDefaultHome();
764 props.Set("SciteDefaultHome", homepath.AsUTF8().c_str());
765 homepath = GetSciteUserHome();
766 props.Set("SciteUserHome", homepath.AsUTF8().c_str());
767
768 for (size_t i=0; propertiesToForward[i]; i++) {
769 ForwardPropertyToEditor(propertiesToForward[i]);
770 }
771
772 if (apisFileNames != props.GetNewExpandString("api.", fileNameForExtension.c_str())) {
773 apis.Clear();
774 ReadAPI(fileNameForExtension);
775 apisFileNames = props.GetNewExpandString("api.", fileNameForExtension.c_str());
776 }
777
778 props.Set("APIPath", apisFileNames.c_str());
779
780 FilePath fileAbbrev = GUI::StringFromUTF8(props.GetNewExpandString("abbreviations.", fileNameForExtension.c_str()));
781 if (!fileAbbrev.IsSet())
782 fileAbbrev = GetAbbrevPropertiesFileName();
783 if (!pathAbbreviations.SameNameAs(fileAbbrev)) {
784 pathAbbreviations = fileAbbrev;
785 ReadAbbrevPropFile();
786 }
787
788 props.Set("AbbrevPath", pathAbbreviations.AsUTF8().c_str());
789
790 const SA::Technology tech = static_cast<SA::Technology>(props.GetInt("technology"));
791 wEditor.SetTechnology(tech);
792 wOutput.SetTechnology(tech);
793
794 const SA::Bidirectional bidirectional = static_cast<SA::Bidirectional>(props.GetInt("bidirectional"));
795 wEditor.SetBidirectional(bidirectional);
796 wOutput.SetBidirectional(bidirectional);
797
798 codePage = props.GetInt("code.page");
799 if (CurrentBuffer()->unicodeMode != uni8Bit) {
800 // Override properties file to ensure Unicode displayed.
801 codePage = SA::CpUtf8;
802 }
803 wEditor.SetCodePage(codePage);
804 const int outputCodePage = props.GetInt("output.code.page", codePage);
805 wOutput.SetCodePage(outputCodePage);
806
807 characterSet = static_cast<SA::CharacterSet>(props.GetInt("character.set", static_cast<int>(SA::CharacterSet::Default)));
808
809 #if defined(__unix__) || defined(__APPLE__)
810 const std::string localeCType = props.GetString("LC_CTYPE");
811 if (localeCType.length())
812 setlocale(LC_CTYPE, localeCType.c_str());
813 else
814 setlocale(LC_CTYPE, "C");
815 #endif
816
817 std::string imeInteraction = props.GetString("ime.interaction");
818 if (imeInteraction.length()) {
819 CallChildren(SA::Message::SetIMEInteraction, props.GetInt("ime.interaction", static_cast<int>(SA::IMEInteraction::Windowed)));
820 }
821 imeAutoComplete = props.GetInt("ime.autocomplete", 0) == 1;
822
823 const SA::Accessibility accessibility = static_cast<SA::Accessibility>(props.GetInt("accessibility", 1));
824 wEditor.SetAccessibility(accessibility);
825 wOutput.SetAccessibility(accessibility);
826
827 wrapStyle = static_cast<SA::Wrap>(props.GetInt("wrap.style", static_cast<int>(SA::Wrap::Word)));
828
829 CallChildren(SA::Message::SetCaretFore,
830 ColourOfProperty(props, "caret.fore", ColourRGB(0, 0, 0)));
831
832 CallChildren(SA::Message::SetMouseSelectionRectangularSwitch, props.GetInt("selection.rectangular.switch.mouse", 0));
833 CallChildren(SA::Message::SetMultipleSelection, props.GetInt("selection.multiple", 1));
834 CallChildren(SA::Message::SetAdditionalSelectionTyping, props.GetInt("selection.additional.typing", 1));
835 CallChildren(SA::Message::SetMultiPaste, props.GetInt("selection.multipaste", 1));
836 CallChildren(SA::Message::SetAdditionalCaretsBlink, props.GetInt("caret.additional.blinks", 1));
837 CallChildren(SA::Message::SetVirtualSpaceOptions, props.GetInt("virtual.space"));
838
839 wEditor.SetMouseDwellTime(props.GetInt("dwell.period", SA::TimeForever));
840
841 const SA::CaretStyle caretStyle = static_cast<SA::CaretStyle>(props.GetInt("caret.style", static_cast<int>(SA::CaretStyle::Line)));
842 wEditor.SetCaretStyle(caretStyle);
843 wOutput.SetCaretStyle(caretStyle);
844 wEditor.SetCaretWidth(props.GetInt("caret.width", 1));
845 wOutput.SetCaretWidth(props.GetInt("caret.width", 1));
846
847 std::string caretLineBack = props.GetExpandedString("caret.line.back");
848 if (caretLineBack.length()) {
849 wEditor.SetCaretLineVisible(true);
850 wEditor.SetCaretLineBack(ColourFromString(caretLineBack));
851 } else {
852 wEditor.SetCaretLineVisible(false);
853 }
854 wEditor.SetCaretLineBackAlpha(
855 static_cast<SA::Alpha>(props.GetInt("caret.line.back.alpha", static_cast<int>(SA::Alpha::NoAlpha))));
856
857 int indicatorsAlpha = props.GetInt("indicators.alpha", 30);
858 if (indicatorsAlpha < 0 || 255 < indicatorsAlpha) // If invalid value,
859 indicatorsAlpha = 30; //then set default value.
860 alphaIndicator = static_cast<SA::Alpha>(indicatorsAlpha);
861 underIndicator = props.GetInt("indicators.under", 0) == 1;
862
863 closeFind = static_cast<CloseFind>(props.GetInt("find.close.on.find", 1));
864
865 const std::string controlCharSymbol = props.GetString("control.char.symbol");
866 if (controlCharSymbol.length()) {
867 wEditor.SetControlCharSymbol(static_cast<unsigned char>(controlCharSymbol[0]));
868 } else {
869 wEditor.SetControlCharSymbol(0);
870 }
871
872 const std::string caretPeriod = props.GetString("caret.period");
873 if (caretPeriod.length()) {
874 wEditor.SetCaretPeriod(atoi(caretPeriod.c_str()));
875 wOutput.SetCaretPeriod(atoi(caretPeriod.c_str()));
876 }
877
878 const int caretZoneX = props.GetInt("caret.policy.width", 50);
879 int caretPolicyX = 0;
880 if (props.GetInt("caret.policy.xslop", 1))
881 caretPolicyX |= static_cast<int>(SA::CaretPolicy::Slop);
882 if (props.GetInt("caret.policy.xstrict"))
883 caretPolicyX |= static_cast<int>(SA::CaretPolicy::Strict);
884 if (props.GetInt("caret.policy.xeven", 1))
885 caretPolicyX |= static_cast<int>(SA::CaretPolicy::Even);
886 if (props.GetInt("caret.policy.xjumps"))
887 caretPolicyX |= static_cast<int>(SA::CaretPolicy::Jumps);
888 //wEditor.SetXCaretPolicy(caretStrict | caretSlop | caretEven | caretJumps);
889 wEditor.SetXCaretPolicy(static_cast<SA::CaretPolicy>(caretPolicyX), caretZoneX);
890
891 const int caretZoneY = props.GetInt("caret.policy.lines");
892 int caretPolicyY = 0;
893 if (props.GetInt("caret.policy.yslop", 1))
894 caretPolicyY |= static_cast<int>(SA::CaretPolicy::Slop);
895 if (props.GetInt("caret.policy.ystrict"))
896 caretPolicyY |= static_cast<int>(SA::CaretPolicy::Strict);
897 if (props.GetInt("caret.policy.yeven", 1))
898 caretPolicyY |= static_cast<int>(SA::CaretPolicy::Even);
899 if (props.GetInt("caret.policy.yjumps"))
900 caretPolicyY |= static_cast<int>(SA::CaretPolicy::Jumps);
901 wEditor.SetYCaretPolicy(static_cast<SA::CaretPolicy>(caretPolicyY), caretZoneY);
902
903 int visiblePolicy = 0;
904 if (props.GetInt("visible.policy.strict"))
905 visiblePolicy |= static_cast<int>(SA::VisiblePolicy::Strict);
906 if (props.GetInt("visible.policy.slop", 1))
907 visiblePolicy |= static_cast<int>(SA::VisiblePolicy::Slop);
908 const int visibleLines = props.GetInt("visible.policy.lines");
909 wEditor.SetVisiblePolicy(static_cast<SA::VisiblePolicy>(visiblePolicy), visibleLines);
910
911 wEditor.SetEdgeColumn(props.GetInt("edge.column", 0));
912 wEditor.SetEdgeMode(static_cast<SA::EdgeVisualStyle>(
913 props.GetInt("edge.mode", static_cast<int>(SA::EdgeVisualStyle::None))));
914 wEditor.SetEdgeColour(
915 ColourOfProperty(props, "edge.colour", ColourRGB(0xff, 0xda, 0xda)));
916
917 std::string selFore = props.GetExpandedString("selection.fore");
918 if (selFore.length()) {
919 CallChildren(SA::Message::SetSelFore, 1, ColourFromString(selFore));
920 } else {
921 CallChildren(SA::Message::SetSelFore, 0, 0);
922 }
923 std::string selBack = props.GetExpandedString("selection.back");
924 if (selBack.length()) {
925 CallChildren(SA::Message::SetSelBack, 1, ColourFromString(selBack));
926 } else {
927 if (selFore.length())
928 CallChildren(SA::Message::SetSelBack, 0, 0);
929 else // Have to show selection somehow
930 CallChildren(SA::Message::SetSelBack, 1, ColourRGB(0xC0, 0xC0, 0xC0));
931 }
932 constexpr int NoAlpha = static_cast<int>(SA::Alpha::NoAlpha);
933 const int selectionAlpha = props.GetInt("selection.alpha", NoAlpha);
934 CallChildren(SA::Message::SetSelAlpha, selectionAlpha);
935
936 std::string selAdditionalFore = props.GetString("selection.additional.fore");
937 if (selAdditionalFore.length()) {
938 CallChildren(SA::Message::SetAdditionalSelFore, ColourFromString(selAdditionalFore));
939 }
940 std::string selAdditionalBack = props.GetString("selection.additional.back");
941 if (selAdditionalBack.length()) {
942 CallChildren(SA::Message::SetAdditionalSelBack, ColourFromString(selAdditionalBack));
943 }
944 const int selectionAdditionalAlpha = (selectionAlpha == NoAlpha) ? NoAlpha : selectionAlpha / 2;
945 CallChildren(SA::Message::SetAdditionalSelAlpha, props.GetInt("selection.additional.alpha", selectionAdditionalAlpha));
946
947 foldColour = props.GetExpandedString("fold.margin.colour");
948 if (foldColour.length()) {
949 CallChildren(SA::Message::SetFoldMarginColour, 1, ColourFromString(foldColour));
950 } else {
951 CallChildren(SA::Message::SetFoldMarginColour, 0, 0);
952 }
953 foldHiliteColour = props.GetExpandedString("fold.margin.highlight.colour");
954 if (foldHiliteColour.length()) {
955 CallChildren(SA::Message::SetFoldMarginHiColour, 1, ColourFromString(foldHiliteColour));
956 } else {
957 CallChildren(SA::Message::SetFoldMarginHiColour, 0, 0);
958 }
959
960 std::string whitespaceFore = props.GetExpandedString("whitespace.fore");
961 if (whitespaceFore.length()) {
962 CallChildren(SA::Message::SetWhitespaceFore, 1, ColourFromString(whitespaceFore));
963 } else {
964 CallChildren(SA::Message::SetWhitespaceFore, 0, 0);
965 }
966 std::string whitespaceBack = props.GetExpandedString("whitespace.back");
967 if (whitespaceBack.length()) {
968 CallChildren(SA::Message::SetWhitespaceBack, 1, ColourFromString(whitespaceBack));
969 } else {
970 CallChildren(SA::Message::SetWhitespaceBack, 0, 0);
971 }
972
973 char bracesStyleKey[200];
974 sprintf(bracesStyleKey, "braces.%s.style", language.c_str());
975 bracesStyle = props.GetInt(bracesStyleKey, 0);
976
977 char key[200] = "";
978 std::string sval;
979
980 sval = FindLanguageProperty("calltip.*.ignorecase");
981 callTipIgnoreCase = sval == "1";
982 sval = FindLanguageProperty("calltip.*.use.escapes");
983 callTipUseEscapes = sval == "1";
984
985 calltipWordCharacters = FindLanguageProperty("calltip.*.word.characters",
986 "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
987 calltipParametersStart = FindLanguageProperty("calltip.*.parameters.start", "(");
988 calltipParametersEnd = FindLanguageProperty("calltip.*.parameters.end", ")");
989 calltipParametersSeparators = FindLanguageProperty("calltip.*.parameters.separators", ",;");
990
991 calltipEndDefinition = FindLanguageProperty("calltip.*.end.definition");
992
993 sprintf(key, "autocomplete.%s.start.characters", language.c_str());
994 autoCompleteStartCharacters = props.GetExpandedString(key);
995 if (autoCompleteStartCharacters == "")
996 autoCompleteStartCharacters = props.GetExpandedString("autocomplete.*.start.characters");
997 // "" is a quite reasonable value for this setting
998
999 sprintf(key, "autocomplete.%s.fillups", language.c_str());
1000 autoCompleteFillUpCharacters = props.GetExpandedString(key);
1001 if (autoCompleteFillUpCharacters == "")
1002 autoCompleteFillUpCharacters =
1003 props.GetExpandedString("autocomplete.*.fillups");
1004 wEditor.AutoCSetFillUps(autoCompleteFillUpCharacters.c_str());
1005
1006 sprintf(key, "autocomplete.%s.typesep", language.c_str());
1007 autoCompleteTypeSeparator = props.GetExpandedString(key);
1008 if (autoCompleteTypeSeparator == "")
1009 autoCompleteTypeSeparator =
1010 props.GetExpandedString("autocomplete.*.typesep");
1011 if (autoCompleteTypeSeparator.length()) {
1012 wEditor.AutoCSetTypeSeparator(
1013 static_cast<unsigned char>(autoCompleteTypeSeparator[0]));
1014 }
1015
1016 sprintf(key, "autocomplete.%s.ignorecase", "*");
1017 sval = props.GetNewExpandString(key);
1018 autoCompleteIgnoreCase = sval == "1";
1019 sprintf(key, "autocomplete.%s.ignorecase", language.c_str());
1020 sval = props.GetNewExpandString(key);
1021 if (sval != "")
1022 autoCompleteIgnoreCase = sval == "1";
1023 wEditor.AutoCSetIgnoreCase(autoCompleteIgnoreCase);
1024 wOutput.AutoCSetIgnoreCase(true);
1025
1026 const int autoCChooseSingle = props.GetInt("autocomplete.choose.single");
1027 wEditor.AutoCSetChooseSingle(autoCChooseSingle);
1028
1029 wEditor.AutoCSetCancelAtStart(false);
1030 wEditor.AutoCSetDropRestOfWord(false);
1031
1032 if (firstPropertiesRead) {
1033 ReadPropertiesInitial();
1034 }
1035
1036 ReadFontProperties();
1037
1038 wEditor.SetPrintMagnification(props.GetInt("print.magnification"));
1039 wEditor.SetPrintColourMode(static_cast<SA::PrintOption>(props.GetInt("print.colour.mode")));
1040
1041 jobQueue.clearBeforeExecute = props.GetInt("clear.before.execute");
1042 jobQueue.timeCommands = props.GetInt("time.commands");
1043
1044 const int blankMarginLeft = props.GetInt("blank.margin.left", 1);
1045 const int blankMarginLeftOutput = props.GetInt("output.blank.margin.left", blankMarginLeft);
1046 const int blankMarginRight = props.GetInt("blank.margin.right", 1);
1047 wEditor.SetMarginLeft(blankMarginLeft);
1048 wEditor.SetMarginRight(blankMarginRight);
1049 wOutput.SetMarginLeft(blankMarginLeftOutput);
1050 wOutput.SetMarginRight(blankMarginRight);
1051
1052 marginWidth = props.GetInt("margin.width");
1053 if (marginWidth == 0)
1054 marginWidth = marginWidthDefault;
1055 wEditor.SetMarginWidthN(1, margin ? marginWidth : 0);
1056
1057 const std::string lineMarginProp = props.GetString("line.margin.width");
1058 lineNumbersWidth = atoi(lineMarginProp.c_str());
1059 if (lineNumbersWidth == 0)
1060 lineNumbersWidth = lineNumbersWidthDefault;
1061 lineNumbersExpand = lineMarginProp.find('+') != std::string::npos;
1062
1063 SetLineNumberWidth();
1064
1065 bufferedDraw = props.GetInt("buffered.draw");
1066 wEditor.SetBufferedDraw(bufferedDraw);
1067 wOutput.SetBufferedDraw(bufferedDraw);
1068
1069 const SA::PhasesDraw phasesDraw = static_cast<SA::PhasesDraw>(
1070 props.GetInt("phases.draw", static_cast<int>(SA::PhasesDraw::Two)));
1071 wEditor.SetPhasesDraw(phasesDraw);
1072 wOutput.SetPhasesDraw(phasesDraw);
1073
1074 wEditor.SetLayoutCache(static_cast<SA::LineCache>(
1075 props.GetInt("cache.layout", static_cast<int>(SA::LineCache::Caret))));
1076 wOutput.SetLayoutCache(static_cast<SA::LineCache>(
1077 props.GetInt("output.cache.layout", static_cast<int>(SA::LineCache::Caret))));
1078
1079 bracesCheck = props.GetInt("braces.check");
1080 bracesSloppy = props.GetInt("braces.sloppy");
1081
1082 wEditor.SetCharsDefault();
1083 wordCharacters = props.GetNewExpandString("word.characters.", fileNameForExtension.c_str());
1084 if (wordCharacters.length()) {
1085 wEditor.SetWordChars(wordCharacters.c_str());
1086 } else {
1087 wordCharacters = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
1088 }
1089
1090 whitespaceCharacters = props.GetNewExpandString("whitespace.characters.", fileNameForExtension.c_str());
1091 if (whitespaceCharacters.length()) {
1092 wEditor.SetWhitespaceChars(whitespaceCharacters.c_str());
1093 }
1094
1095 const std::string viewIndentExamine = GetFileNameProperty("view.indentation.examine");
1096 indentExamine = viewIndentExamine.length() ? static_cast<SA::IndentView>(atoi(viewIndentExamine.c_str())) : SA::IndentView::Real;
1097 wEditor.SetIndentationGuides(props.GetInt("view.indentation.guides") ?
1098 indentExamine : SA::IndentView::None);
1099
1100 wEditor.SetTabIndents(props.GetInt("tab.indents", 1));
1101 wEditor.SetBackSpaceUnIndents(props.GetInt("backspace.unindents", 1));
1102
1103 wEditor.CallTipUseStyle(32);
1104
1105 std::string useStripTrailingSpaces = props.GetNewExpandString("strip.trailing.spaces.", ExtensionFileName().c_str());
1106 if (useStripTrailingSpaces.length() > 0) {
1107 stripTrailingSpaces = atoi(useStripTrailingSpaces.c_str()) != 0;
1108 } else {
1109 stripTrailingSpaces = props.GetInt("strip.trailing.spaces") != 0;
1110 }
1111 ensureFinalLineEnd = props.GetInt("ensure.final.line.end") != 0;
1112 ensureConsistentLineEnds = props.GetInt("ensure.consistent.line.ends") != 0;
1113
1114 indentOpening = props.GetInt("indent.opening");
1115 indentClosing = props.GetInt("indent.closing");
1116 indentMaintain = atoi(props.GetNewExpandString("indent.maintain.", fileNameForExtension.c_str()).c_str());
1117
1118 const std::string lookback = props.GetNewExpandString("statement.lookback.", fileNameForExtension.c_str());
1119 statementLookback = atoi(lookback.c_str());
1120 statementIndent = GetStyleAndWords("statement.indent.");
1121 statementEnd = GetStyleAndWords("statement.end.");
1122 blockStart = GetStyleAndWords("block.start.");
1123 blockEnd = GetStyleAndWords("block.end.");
1124
1125 struct PropToPPC {
1126 const char *propName;
1127 PreProc ppc;
1128 };
1129 PropToPPC propToPPC[] = {
1130 {"preprocessor.start.", PreProc::Start},
1131 {"preprocessor.middle.", PreProc::Middle},
1132 {"preprocessor.end.", PreProc::End},
1133 };
1134 const std::string ppSymbol = props.GetNewExpandString("preprocessor.symbol.", fileNameForExtension.c_str());
1135 preprocessorSymbol = ppSymbol.empty() ? 0 : ppSymbol[0];
1136 preprocOfString.clear();
1137 for (const PropToPPC &preproc : propToPPC) {
1138 const std::string list = props.GetNewExpandString(preproc.propName, fileNameForExtension.c_str());
1139 const std::vector<std::string> words = StringSplit(list, ' ');
1140 for (const std::string &word : words) {
1141 preprocOfString[word] = preproc.ppc;
1142 }
1143 }
1144
1145 memFiles.AppendList(props.GetNewExpandString("find.files").c_str());
1146
1147 wEditor.SetWrapVisualFlags(static_cast<SA::WrapVisualFlag>(props.GetInt("wrap.visual.flags")));
1148 wEditor.SetWrapVisualFlagsLocation(static_cast<SA::WrapVisualLocation>(props.GetInt("wrap.visual.flags.location")));
1149 wEditor.SetWrapStartIndent(props.GetInt("wrap.visual.startindent"));
1150 wEditor.SetWrapIndentMode(static_cast<SA::WrapIndentMode>(props.GetInt("wrap.indent.mode")));
1151
1152 idleStyling = static_cast<SA::IdleStyling>(props.GetInt("idle.styling", static_cast<int>(SA::IdleStyling::None)));
1153 wEditor.SetIdleStyling(idleStyling);
1154 wOutput.SetIdleStyling(static_cast<SA::IdleStyling>(props.GetInt("output.idle.styling", static_cast<int>(SA::IdleStyling::None))));
1155
1156 if (props.GetInt("os.x.home.end.keys")) {
1157 AssignKey(SA::Keys::Home, SA::KeyMod::Norm, SCI_SCROLLTOSTART);
1158 AssignKey(SA::Keys::Home, SA::KeyMod::Shift, SCI_NULL);
1159 AssignKey(SA::Keys::Home, SA::KeyMod::Shift | SA::KeyMod::Alt, SCI_NULL);
1160 AssignKey(SA::Keys::End, SA::KeyMod::Norm, SCI_SCROLLTOEND);
1161 AssignKey(SA::Keys::End, SA::KeyMod::Shift, SCI_NULL);
1162 } else {
1163 if (props.GetInt("wrap.aware.home.end.keys", 0)) {
1164 if (props.GetInt("vc.home.key", 1)) {
1165 AssignKey(SA::Keys::Home, SA::KeyMod::Norm, SCI_VCHOMEWRAP);
1166 AssignKey(SA::Keys::Home, SA::KeyMod::Shift, SCI_VCHOMEWRAPEXTEND);
1167 AssignKey(SA::Keys::Home, SA::KeyMod::Shift | SA::KeyMod::Alt, SCI_VCHOMERECTEXTEND);
1168 } else {
1169 AssignKey(SA::Keys::Home, SA::KeyMod::Norm, SCI_HOMEWRAP);
1170 AssignKey(SA::Keys::Home, SA::KeyMod::Shift, SCI_HOMEWRAPEXTEND);
1171 AssignKey(SA::Keys::Home, SA::KeyMod::Shift | SA::KeyMod::Alt, SCI_HOMERECTEXTEND);
1172 }
1173 AssignKey(SA::Keys::End, SA::KeyMod::Norm, SCI_LINEENDWRAP);
1174 AssignKey(SA::Keys::End, SA::KeyMod::Shift, SCI_LINEENDWRAPEXTEND);
1175 } else {
1176 if (props.GetInt("vc.home.key", 1)) {
1177 AssignKey(SA::Keys::Home, SA::KeyMod::Norm, SCI_VCHOME);
1178 AssignKey(SA::Keys::Home, SA::KeyMod::Shift, SCI_VCHOMEEXTEND);
1179 AssignKey(SA::Keys::Home, SA::KeyMod::Shift | SA::KeyMod::Alt, SCI_VCHOMERECTEXTEND);
1180 } else {
1181 AssignKey(SA::Keys::Home, SA::KeyMod::Norm, SCI_HOME);
1182 AssignKey(SA::Keys::Home, SA::KeyMod::Shift, SCI_HOMEEXTEND);
1183 AssignKey(SA::Keys::Home, SA::KeyMod::Shift | SA::KeyMod::Alt, SCI_HOMERECTEXTEND);
1184 }
1185 AssignKey(SA::Keys::End, SA::KeyMod::Norm, SCI_LINEEND);
1186 AssignKey(SA::Keys::End, SA::KeyMod::Shift, SCI_LINEENDEXTEND);
1187 }
1188 }
1189
1190 AssignKey(static_cast<SA::Keys>('L'), SA::KeyMod::Shift | SA::KeyMod::Ctrl, SCI_LINEDELETE);
1191
1192
1193 scrollOutput = props.GetInt("output.scroll", 1);
1194
1195 tabHideOne = props.GetInt("tabbar.hide.one");
1196
1197 SetToolsMenu();
1198
1199 wEditor.SetFoldFlags(static_cast<SA::FoldFlag>(props.GetInt("fold.flags")));
1200
1201 // To put the folder markers in the line number region
1202 //wEditor.SetMarginMaskN(0, SC_MASK_FOLDERS);
1203
1204 wEditor.SetModEventMask(SA::ModificationFlags::ChangeFold);
1205
1206 if (0==props.GetInt("undo.redo.lazy")) {
1207 // Trap for insert/delete notifications (also fired by undo
1208 // and redo) so that the buttons can be enabled if needed.
1209 const SA::ModificationFlags flagsCurrent = wEditor.ModEventMask();
1210 const SA::ModificationFlags flags =
1211 flagsCurrent |
1212 SA::ModificationFlags::InsertText |
1213 SA::ModificationFlags::DeleteText |
1214 SA::ModificationFlags::LastStepInUndoRedo;
1215 wEditor.SetModEventMask(flags);
1216
1217 // LastStepInUndoRedo is probably not needed in the mask; it
1218 // doesn't seem to fire as an event of its own; just modifies the
1219 // insert and delete events.
1220 }
1221
1222 // Create a margin column for the folding symbols
1223 wEditor.SetMarginTypeN(2, SA::MarginType::Symbol);
1224
1225 foldMarginWidth = props.GetInt("fold.margin.width");
1226 if (foldMarginWidth == 0)
1227 foldMarginWidth = foldMarginWidthDefault;
1228 wEditor.SetMarginWidthN(2, foldMargin ? foldMarginWidth : 0);
1229
1230 wEditor.SetMarginMaskN(2, SA::MaskFolders);
1231 wEditor.SetMarginSensitiveN(2, true);
1232
1233 // Define foreground (outline) and background (fill) colour of folds
1234 const int foldSymbols = props.GetInt("fold.symbols");
1235 std::string foldFore = props.GetExpandedString("fold.fore");
1236 if (foldFore.length() == 0) {
1237 // Set default colour for outline
1238 switch (foldSymbols) {
1239 case 0: // Arrows
1240 foldFore = "#000000";
1241 break;
1242 case 1: // + -
1243 foldFore = "#FFFFFF";
1244 break;
1245 case 2: // Circles
1246 foldFore = "#404040";
1247 break;
1248 case 3: // Squares
1249 foldFore = "#808080";
1250 break;
1251 }
1252 }
1253 const SA::Colour colourFoldFore = ColourFromString(foldFore);
1254
1255 std::string foldBack = props.GetExpandedString("fold.back");
1256 // Set default colour for fill
1257 if (foldBack.length() == 0) {
1258 switch (foldSymbols) {
1259 case 0:
1260 case 1:
1261 foldBack = "#000000";
1262 break;
1263 case 2:
1264 case 3:
1265 foldBack = "#FFFFFF";
1266 break;
1267 }
1268 }
1269 const SA::Colour colourFoldBack = ColourFromString(foldBack);
1270
1271 // Enable/disable highlight for current folding block (smallest one that contains the caret)
1272 const int isHighlightEnabled = props.GetInt("fold.highlight", 0);
1273 // Define the colour of highlight
1274 const SA::Colour colourFoldBlockHighlight = ColourOfProperty(props, "fold.highlight.colour", ColourRGB(0xFF, 0, 0));
1275
1276 switch (foldSymbols) {
1277 case 0:
1278 // Arrow pointing right for contracted folders, arrow pointing down for expanded
1279 DefineMarker(SA::MarkerOutline::FolderOpen, SA::MarkerSymbol::ArrowDown,
1280 colourFoldFore, colourFoldBack, colourFoldBlockHighlight);
1281 DefineMarker(SA::MarkerOutline::Folder, SA::MarkerSymbol::Arrow,
1282 colourFoldFore, colourFoldBack, colourFoldBlockHighlight);
1283 DefineMarker(SA::MarkerOutline::FolderSub, SA::MarkerSymbol::Empty,
1284 colourFoldFore, colourFoldBack, colourFoldBlockHighlight);
1285 DefineMarker(SA::MarkerOutline::FolderTail, SA::MarkerSymbol::Empty,
1286 colourFoldFore, colourFoldBack, colourFoldBlockHighlight);
1287 DefineMarker(SA::MarkerOutline::FolderEnd, SA::MarkerSymbol::Empty,
1288 colourFoldFore, colourFoldBack, colourFoldBlockHighlight);
1289 DefineMarker(SA::MarkerOutline::FolderOpenMid, SA::MarkerSymbol::Empty,
1290 colourFoldFore, colourFoldBack, colourFoldBlockHighlight);
1291 DefineMarker(SA::MarkerOutline::FolderMidTail, SA::MarkerSymbol::Empty,
1292 colourFoldFore, colourFoldBack, colourFoldBlockHighlight);
1293 // The highlight is disabled for arrow.
1294 wEditor.MarkerEnableHighlight(false);
1295 break;
1296 case 1:
1297 // Plus for contracted folders, minus for expanded
1298 DefineMarker(SA::MarkerOutline::FolderOpen, SA::MarkerSymbol::Minus,
1299 colourFoldFore, colourFoldBack, colourFoldBlockHighlight);
1300 DefineMarker(SA::MarkerOutline::Folder, SA::MarkerSymbol::Plus,
1301 colourFoldFore, colourFoldBack, colourFoldBlockHighlight);
1302 DefineMarker(SA::MarkerOutline::FolderSub, SA::MarkerSymbol::Empty,
1303 colourFoldFore, colourFoldBack, colourFoldBlockHighlight);
1304 DefineMarker(SA::MarkerOutline::FolderTail, SA::MarkerSymbol::Empty,
1305 colourFoldFore, colourFoldBack, colourFoldBlockHighlight);
1306 DefineMarker(SA::MarkerOutline::FolderEnd, SA::MarkerSymbol::Empty,
1307 colourFoldFore, colourFoldBack, colourFoldBlockHighlight);
1308 DefineMarker(SA::MarkerOutline::FolderOpenMid, SA::MarkerSymbol::Empty,
1309 colourFoldFore, colourFoldBack, colourFoldBlockHighlight);
1310 DefineMarker(SA::MarkerOutline::FolderMidTail, SA::MarkerSymbol::Empty,
1311 colourFoldFore, colourFoldBack, colourFoldBlockHighlight);
1312 // The highlight is disabled for plus/minus.
1313 wEditor.MarkerEnableHighlight(false);
1314 break;
1315 case 2:
1316 // Like a flattened tree control using circular headers and curved joins
1317 DefineMarker(SA::MarkerOutline::FolderOpen, SA::MarkerSymbol::CircleMinus,
1318 colourFoldBack, colourFoldFore, colourFoldBlockHighlight);
1319 DefineMarker(SA::MarkerOutline::Folder, SA::MarkerSymbol::CirclePlus,
1320 colourFoldBack, colourFoldFore, colourFoldBlockHighlight);
1321 DefineMarker(SA::MarkerOutline::FolderSub, SA::MarkerSymbol::VLine,
1322 colourFoldBack, colourFoldFore, colourFoldBlockHighlight);
1323 DefineMarker(SA::MarkerOutline::FolderTail, SA::MarkerSymbol::LCornerCurve,
1324 colourFoldBack, colourFoldFore, colourFoldBlockHighlight);
1325 DefineMarker(SA::MarkerOutline::FolderEnd, SA::MarkerSymbol::CirclePlusConnected,
1326 colourFoldBack, colourFoldFore, colourFoldBlockHighlight);
1327 DefineMarker(SA::MarkerOutline::FolderOpenMid, SA::MarkerSymbol::CircleMinusConnected,
1328 colourFoldBack, colourFoldFore, colourFoldBlockHighlight);
1329 DefineMarker(SA::MarkerOutline::FolderMidTail, SA::MarkerSymbol::TCornerCurve,
1330 colourFoldBack, colourFoldFore, colourFoldBlockHighlight);
1331 wEditor.MarkerEnableHighlight(isHighlightEnabled);
1332 break;
1333 case 3:
1334 // Like a flattened tree control using square headers
1335 DefineMarker(SA::MarkerOutline::FolderOpen, SA::MarkerSymbol::BoxMinus,
1336 colourFoldBack, colourFoldFore, colourFoldBlockHighlight);
1337 DefineMarker(SA::MarkerOutline::Folder, SA::MarkerSymbol::BoxPlus,
1338 colourFoldBack, colourFoldFore, colourFoldBlockHighlight);
1339 DefineMarker(SA::MarkerOutline::FolderSub, SA::MarkerSymbol::VLine,
1340 colourFoldBack, colourFoldFore, colourFoldBlockHighlight);
1341 DefineMarker(SA::MarkerOutline::FolderTail, SA::MarkerSymbol::LCorner,
1342 colourFoldBack, colourFoldFore, colourFoldBlockHighlight);
1343 DefineMarker(SA::MarkerOutline::FolderEnd, SA::MarkerSymbol::BoxPlusConnected,
1344 colourFoldBack, colourFoldFore, colourFoldBlockHighlight);
1345 DefineMarker(SA::MarkerOutline::FolderOpenMid, SA::MarkerSymbol::BoxMinusConnected,
1346 colourFoldBack, colourFoldFore, colourFoldBlockHighlight);
1347 DefineMarker(SA::MarkerOutline::FolderMidTail, SA::MarkerSymbol::TCorner,
1348 colourFoldBack, colourFoldFore, colourFoldBlockHighlight);
1349 wEditor.MarkerEnableHighlight(isHighlightEnabled);
1350 break;
1351 }
1352
1353 wEditor.MarkerSetFore(markerBookmark,
1354 ColourOfProperty(props, "bookmark.fore", ColourRGB(0xbe, 0, 0)));
1355 wEditor.MarkerSetBack(markerBookmark,
1356 ColourOfProperty(props, "bookmark.back", ColourRGB(0xe2, 0x40, 0x40)));
1357 wEditor.MarkerSetAlpha(markerBookmark,
1358 static_cast<SA::Alpha>(props.GetInt("bookmark.alpha", static_cast<int>(SA::Alpha::NoAlpha))));
1359 const std::string bookMarkXPM = props.GetString("bookmark.pixmap");
1360 if (bookMarkXPM.length()) {
1361 wEditor.MarkerDefinePixmap(markerBookmark, bookMarkXPM.c_str());
1362 } else if (props.GetString("bookmark.fore").length()) {
1363 wEditor.MarkerDefine(markerBookmark, static_cast<SA::MarkerSymbol>(
1364 props.GetInt("bookmark.symbol", static_cast<int>(SA::MarkerSymbol::Bookmark))));
1365 } else {
1366 // No bookmark.fore setting so display default pixmap.
1367 wEditor.MarkerDefinePixmap(markerBookmark, reinterpret_cast<const char *>(bookmarkBluegem));
1368 }
1369
1370 wEditor.SetScrollWidth(props.GetInt("horizontal.scroll.width", 2000));
1371 wEditor.SetScrollWidthTracking(props.GetInt("horizontal.scroll.width.tracking", 1));
1372 wOutput.SetScrollWidth(props.GetInt("output.horizontal.scroll.width", 2000));
1373 wOutput.SetScrollWidthTracking(props.GetInt("output.horizontal.scroll.width.tracking", 1));
1374
1375 // Do these last as they force a style refresh
1376 wEditor.SetHScrollBar(props.GetInt("horizontal.scrollbar", 1));
1377 wOutput.SetHScrollBar(props.GetInt("output.horizontal.scrollbar", 1));
1378
1379 wEditor.SetEndAtLastLine(props.GetInt("end.at.last.line", 1));
1380 wEditor.SetCaretSticky(static_cast<SA::CaretSticky>(props.GetInt("caret.sticky", 0)));
1381
1382 // Clear all previous indicators.
1383 wEditor.SetIndicatorCurrent(indicatorHighlightCurrentWord);
1384 wEditor.IndicatorClearRange(0, wEditor.Length());
1385 wOutput.SetIndicatorCurrent(indicatorHighlightCurrentWord);
1386 wOutput.IndicatorClearRange(0, wOutput.Length());
1387 currentWordHighlight.statesOfDelay = currentWordHighlight.noDelay;
1388
1389 currentWordHighlight.isEnabled = props.GetInt("highlight.current.word", 0) == 1;
1390 if (currentWordHighlight.isEnabled) {
1391 const std::string highlightCurrentWordIndicatorString = props.GetExpandedString("highlight.current.word.indicator");
1392 IndicatorDefinition highlightCurrentWordIndicator(highlightCurrentWordIndicatorString.c_str());
1393 if (highlightCurrentWordIndicatorString.length() == 0) {
1394 highlightCurrentWordIndicator.style = SA::IndicatorStyle::RoundBox;
1395 std::string highlightCurrentWordColourString = props.GetExpandedString("highlight.current.word.colour");
1396 if (highlightCurrentWordColourString.length() == 0) {
1397 // Set default colour for highlight.
1398 highlightCurrentWordColourString = "#A0A000";
1399 }
1400 highlightCurrentWordIndicator.colour = ColourFromString(highlightCurrentWordColourString);
1401 highlightCurrentWordIndicator.fillAlpha = alphaIndicator;
1402 highlightCurrentWordIndicator.under = underIndicator;
1403 }
1404 SetOneIndicator(wEditor, indicatorHighlightCurrentWord, highlightCurrentWordIndicator);
1405 SetOneIndicator(wOutput, indicatorHighlightCurrentWord, highlightCurrentWordIndicator);
1406 currentWordHighlight.isOnlyWithSameStyle = props.GetInt("highlight.current.word.by.style", 0) == 1;
1407 HighlightCurrentWord(true);
1408 }
1409
1410 std::map<std::string, std::string> eConfig = editorConfig->MapFromAbsolutePath(filePath);
1411 for (const std::pair<const std::string, std::string> &pss : eConfig) {
1412 if (pss.first == "indent_style") {
1413 wEditor.SetUseTabs(pss.second == "tab");
1414 } else if (pss.first == "indent_size") {
1415 wEditor.SetIndent(std::stoi(pss.second));
1416 } else if (pss.first == "tab_width") {
1417 wEditor.SetTabWidth(std::stoi(pss.second));
1418 } else if (pss.first == "end_of_line") {
1419 if (pss.second == "lf") {
1420 wEditor.SetEOLMode(SA::EndOfLine::Lf);
1421 } else if (pss.second == "cr") {
1422 wEditor.SetEOLMode(SA::EndOfLine::Cr);
1423 } else if (pss.second == "crlf") {
1424 wEditor.SetEOLMode(SA::EndOfLine::Lf);
1425 }
1426 } else if (pss.first == "charset") {
1427 if (pss.second == "latin1") {
1428 CurrentBuffer()->unicodeMode = uni8Bit;
1429 codePage = 0;
1430 } else {
1431 if (pss.second == "utf-8")
1432 CurrentBuffer()->unicodeMode = uniCookie;
1433 if (pss.second == "utf-8-bom")
1434 CurrentBuffer()->unicodeMode = uniUTF8;
1435 if (pss.second == "utf-16be")
1436 CurrentBuffer()->unicodeMode = uni16BE;
1437 if (pss.second == "utf-16le")
1438 CurrentBuffer()->unicodeMode = uni16LE;
1439 codePage = SA::CpUtf8;
1440 }
1441 wEditor.SetCodePage(codePage);
1442 } else if (pss.first == "trim_trailing_whitespace") {
1443 stripTrailingSpaces = pss.second == "true";
1444 } else if (pss.first == "insert_final_newline") {
1445 ensureFinalLineEnd = pss.second == "true";
1446 }
1447 }
1448
1449 if (extender) {
1450 FilePath defaultDir = GetDefaultDirectory();
1451 FilePath scriptPath;
1452
1453 // Check for an extension script
1454 GUI::gui_string extensionFile = GUI::StringFromUTF8(
1455 props.GetNewExpandString("extension.", fileNameForExtension.c_str()));
1456 if (extensionFile.length()) {
1457 // find file in local directory
1458 FilePath docDir = filePath.Directory();
1459 if (Exists(docDir.AsInternal(), extensionFile.c_str(), &scriptPath)) {
1460 // Found file in document directory
1461 extender->Load(scriptPath.AsUTF8().c_str());
1462 } else if (Exists(defaultDir.AsInternal(), extensionFile.c_str(), &scriptPath)) {
1463 // Found file in global directory
1464 extender->Load(scriptPath.AsUTF8().c_str());
1465 } else if (Exists(GUI_TEXT(""), extensionFile.c_str(), &scriptPath)) {
1466 // Found as completely specified file name
1467 extender->Load(scriptPath.AsUTF8().c_str());
1468 }
1469 }
1470 }
1471
1472 delayBeforeAutoSave = props.GetInt("save.on.timer");
1473 if (delayBeforeAutoSave) {
1474 TimerStart(timerAutoSave);
1475 } else {
1476 TimerEnd(timerAutoSave);
1477 }
1478
1479 firstPropertiesRead = false;
1480 needReadProperties = false;
1481 }
1482
ReadFontProperties()1483 void SciTEBase::ReadFontProperties() {
1484 char key[200] = "";
1485 const char *languageName = language.c_str();
1486
1487 if (lexLanguage == lexLPeg) {
1488 // Retrieve style info.
1489 char propStr[256] = "";
1490 for (int i = 0; i < StyleMax; i++) {
1491 sprintf(key, "style.lpeg.%0d", i);
1492 wEditor.PrivateLexerCall(i - StyleMax,
1493 const_cast<char *>(propStr));
1494 props.Set(key, static_cast<const char *>(propStr));
1495 }
1496 languageName = "lpeg";
1497 }
1498
1499 // Set styles
1500 // For each window set the global default style, then the language default style, then the other global styles, then the other language styles
1501
1502 const SA::FontQuality fontQuality = static_cast<SA::FontQuality>(props.GetInt("font.quality"));
1503 wEditor.SetFontQuality(fontQuality);
1504 wOutput.SetFontQuality(fontQuality);
1505
1506 wEditor.StyleResetDefault();
1507 wOutput.StyleResetDefault();
1508
1509 sprintf(key, "style.%s.%0d", "*", StyleDefault);
1510 std::string sval = props.GetNewExpandString(key);
1511 SetOneStyle(wEditor, StyleDefault, StyleDefinition(sval));
1512 SetOneStyle(wOutput, StyleDefault, StyleDefinition(sval));
1513
1514 sprintf(key, "style.%s.%0d", languageName, StyleDefault);
1515 sval = props.GetNewExpandString(key);
1516 SetOneStyle(wEditor, StyleDefault, StyleDefinition(sval));
1517
1518 wEditor.StyleClearAll();
1519
1520 SetStyleFor(wEditor, "*");
1521 SetStyleFor(wEditor, languageName);
1522 if (props.GetInt("error.inline")) {
1523 wEditor.ReleaseAllExtendedStyles();
1524 diagnosticStyleStart = wEditor.AllocateExtendedStyles(diagnosticStyles);
1525 SetStyleBlock(wEditor, "error", diagnosticStyleStart, diagnosticStyleStart+diagnosticStyles-1);
1526 }
1527
1528 const int diffToSecondary = static_cast<int>(wEditor.DistanceToSecondaryStyles());
1529 for (const unsigned char subStyleBase : subStyleBases) {
1530 const int subStylesStart = wEditor.SubStylesStart(subStyleBase);
1531 const int subStylesLength = wEditor.SubStylesLength(subStyleBase);
1532 for (int subStyle=0; subStyle<subStylesLength; subStyle++) {
1533 for (int active=0; active<(diffToSecondary?2:1); active++) {
1534 const int activity = active * diffToSecondary;
1535 sprintf(key, "style.%s.%0d.%0d", languageName, subStyleBase + activity, subStyle+1);
1536 sval = props.GetNewExpandString(key);
1537 SetOneStyle(wEditor, subStylesStart + subStyle + activity, StyleDefinition(sval));
1538 }
1539 }
1540 }
1541
1542 // Turn grey while loading
1543 if (CurrentBuffer()->lifeState == Buffer::reading)
1544 wEditor.StyleSetBack(StyleDefault, 0xEEEEEE);
1545
1546 wOutput.StyleClearAll();
1547
1548 sprintf(key, "style.%s.%0d", "errorlist", StyleDefault);
1549 sval = props.GetNewExpandString(key);
1550 SetOneStyle(wOutput, StyleDefault, StyleDefinition(sval));
1551
1552 wOutput.StyleClearAll();
1553
1554 SetStyleFor(wOutput, "*");
1555 SetStyleFor(wOutput, "errorlist");
1556
1557 if (CurrentBuffer()->useMonoFont) {
1558 sval = props.GetExpandedString("font.monospace");
1559 StyleDefinition sd(sval.c_str());
1560 for (int style = 0; style <= StyleMax; style++) {
1561 if (style != static_cast<int>(SA::StylesCommon::LineNumber)) {
1562 if (sd.specified & StyleDefinition::sdFont) {
1563 wEditor.StyleSetFont(style, sd.font.c_str());
1564 }
1565 if (sd.specified & StyleDefinition::sdSize) {
1566 wEditor.StyleSetSizeFractional(style, sd.FractionalSize());
1567 }
1568 }
1569 }
1570 }
1571 }
1572
1573 // Properties that are interactively modifiable are only read from the properties file once.
SetPropertiesInitial()1574 void SciTEBase::SetPropertiesInitial() {
1575 splitVertical = props.GetInt("split.vertical");
1576 openFilesHere = props.GetInt("check.if.already.open");
1577 wrap = props.GetInt("wrap");
1578 wrapOutput = props.GetInt("output.wrap");
1579 indentationWSVisible = props.GetInt("view.indentation.whitespace", 1);
1580 sbVisible = props.GetInt("statusbar.visible");
1581 tbVisible = props.GetInt("toolbar.visible");
1582 tabVisible = props.GetInt("tabbar.visible");
1583 tabMultiLine = props.GetInt("tabbar.multiline");
1584 lineNumbers = props.GetInt("line.margin.visible");
1585 margin = props.GetInt("margin.width");
1586 foldMargin = props.GetInt("fold.margin.width", foldMarginWidthDefault);
1587
1588 matchCase = props.GetInt("find.replace.matchcase");
1589 regExp = props.GetInt("find.replace.regexp");
1590 unSlash = props.GetInt("find.replace.escapes");
1591 wrapFind = props.GetInt("find.replace.wrap", 1);
1592 focusOnReplace = props.GetInt("find.replacewith.focus", 1);
1593 }
1594
Text(const char * s,bool retainIfNotFound)1595 GUI::gui_string Localization::Text(const char *s, bool retainIfNotFound) {
1596 const std::string sEllipse("..."); // An ASCII ellipse
1597 const std::string utfEllipse("\xe2\x80\xa6"); // A UTF-8 ellipse
1598 std::string translation = s;
1599 const int ellipseIndicator = Remove(translation, sEllipse);
1600 const int utfEllipseIndicator = Remove(translation, utfEllipse);
1601 const std::string menuAccessIndicatorChar(1, static_cast<char>(menuAccessIndicator[0]));
1602 const int accessKeyPresent = Remove(translation, menuAccessIndicatorChar);
1603 LowerCaseAZ(translation);
1604 Substitute(translation, "\n", "\\n");
1605 translation = GetString(translation.c_str());
1606 if (translation.length()) {
1607 if (ellipseIndicator)
1608 translation += sEllipse;
1609 if (utfEllipseIndicator)
1610 translation += utfEllipse;
1611 if (0 == accessKeyPresent) {
1612 #if !defined(GTK)
1613 // Following codes are required because accelerator is not always
1614 // part of alphabetical word in several language. In these cases,
1615 // accelerator is written like "(&O)".
1616 const size_t posOpenParenAnd = translation.find("(&");
1617 if ((posOpenParenAnd != std::string::npos) && (translation.find(")", posOpenParenAnd) == posOpenParenAnd + 3)) {
1618 translation.erase(posOpenParenAnd, 4);
1619 } else {
1620 Remove(translation, std::string("&"));
1621 }
1622 #else
1623 Remove(translation, std::string("&"));
1624 #endif
1625 }
1626 Substitute(translation, "&", menuAccessIndicatorChar);
1627 Substitute(translation, "\\n", "\n");
1628 } else {
1629 translation = missing;
1630 }
1631 if ((translation.length() > 0) || !retainIfNotFound) {
1632 return GUI::StringFromUTF8(translation);
1633 }
1634 return GUI::StringFromUTF8(s);
1635 }
1636
LocaliseMessage(const char * s,const GUI::gui_char * param0,const GUI::gui_char * param1,const GUI::gui_char * param2)1637 GUI::gui_string SciTEBase::LocaliseMessage(const char *s, const GUI::gui_char *param0, const GUI::gui_char *param1, const GUI::gui_char *param2) {
1638 GUI::gui_string translation = localiser.Text(s);
1639 if (param0)
1640 Substitute(translation, GUI_TEXT("^0"), param0);
1641 if (param1)
1642 Substitute(translation, GUI_TEXT("^1"), param1);
1643 if (param2)
1644 Substitute(translation, GUI_TEXT("^2"), param2);
1645 return translation;
1646 }
1647
ReadLocalization()1648 void SciTEBase::ReadLocalization() {
1649 localiser.Clear();
1650 GUI::gui_string title = GUI_TEXT("locale.properties");
1651 const std::string localeProps = props.GetExpandedString("locale.properties");
1652 if (localeProps.length()) {
1653 title = GUI::StringFromUTF8(localeProps);
1654 }
1655 FilePath propdir = GetSciteDefaultHome();
1656 FilePath localePath(propdir, title);
1657 localiser.Read(localePath, propdir, filter, &importFiles, 0);
1658 localiser.SetMissing(props.GetString("translation.missing"));
1659 localiser.read = true;
1660 }
1661
ReadPropertiesInitial()1662 void SciTEBase::ReadPropertiesInitial() {
1663 SetPropertiesInitial();
1664 const int sizeHorizontal = props.GetInt("output.horizontal.size", 0);
1665 const int sizeVertical = props.GetInt("output.vertical.size", 0);
1666 const int hideOutput = props.GetInt("output.initial.hide", 0);
1667 if ((!splitVertical && (sizeVertical > 0) && (heightOutput < sizeVertical)) ||
1668 (splitVertical && (sizeHorizontal > 0) && (heightOutput < sizeHorizontal))) {
1669 previousHeightOutput = splitVertical ? sizeHorizontal : sizeVertical;
1670 if (!hideOutput) {
1671 heightOutput = NormaliseSplit(previousHeightOutput);
1672 SizeSubWindows();
1673 Redraw();
1674 }
1675 }
1676 ViewWhitespace(props.GetInt("view.whitespace"));
1677 wEditor.SetIndentationGuides(props.GetInt("view.indentation.guides") ?
1678 indentExamine : SA::IndentView::None);
1679
1680 wEditor.SetViewEOL(props.GetInt("view.eol"));
1681 wEditor.SetZoom(props.GetInt("magnification"));
1682 wOutput.SetZoom(props.GetInt("output.magnification"));
1683 wEditor.SetWrapMode(wrap ? wrapStyle : SA::Wrap::None);
1684 wOutput.SetWrapMode(wrapOutput ? wrapStyle : SA::Wrap::None);
1685
1686 std::string menuLanguageProp = props.GetExpandedString("menu.language");
1687 std::replace(menuLanguageProp.begin(), menuLanguageProp.end(), '|', '\0');
1688 const char *sMenuLanguage = menuLanguageProp.c_str();
1689 while (*sMenuLanguage) {
1690 LanguageMenuItem lmi;
1691 lmi.menuItem = sMenuLanguage;
1692 sMenuLanguage += strlen(sMenuLanguage) + 1;
1693 lmi.extension = sMenuLanguage;
1694 sMenuLanguage += strlen(sMenuLanguage) + 1;
1695 lmi.menuKey = sMenuLanguage;
1696 sMenuLanguage += strlen(sMenuLanguage) + 1;
1697 languageMenu.push_back(lmi);
1698 }
1699 SetLanguageMenu();
1700
1701 // load the user defined short cut props
1702 std::string shortCutProp = props.GetNewExpandString("user.shortcuts");
1703 if (shortCutProp.length()) {
1704 const size_t pipes = std::count(shortCutProp.begin(), shortCutProp.end(), '|');
1705 std::replace(shortCutProp.begin(), shortCutProp.end(), '|', '\0');
1706 const char *sShortCutProp = shortCutProp.c_str();
1707 for (size_t item = 0; item < pipes/2; item++) {
1708 ShortcutItem sci;
1709 sci.menuKey = sShortCutProp;
1710 sShortCutProp += strlen(sShortCutProp) + 1;
1711 sci.menuCommand = sShortCutProp;
1712 sShortCutProp += strlen(sShortCutProp) + 1;
1713 shortCutItemList.push_back(sci);
1714 }
1715 }
1716 // end load the user defined short cut props
1717
1718 FilePath homepath = GetSciteDefaultHome();
1719 props.Set("SciteDefaultHome", homepath.AsUTF8().c_str());
1720 homepath = GetSciteUserHome();
1721 props.Set("SciteUserHome", homepath.AsUTF8().c_str());
1722 }
1723
GetDefaultPropertiesFileName()1724 FilePath SciTEBase::GetDefaultPropertiesFileName() {
1725 return FilePath(GetSciteDefaultHome(), propGlobalFileName);
1726 }
1727
GetAbbrevPropertiesFileName()1728 FilePath SciTEBase::GetAbbrevPropertiesFileName() {
1729 return FilePath(GetSciteUserHome(), propAbbrevFileName);
1730 }
1731
GetUserPropertiesFileName()1732 FilePath SciTEBase::GetUserPropertiesFileName() {
1733 return FilePath(GetSciteUserHome(), propUserFileName);
1734 }
1735
GetLocalPropertiesFileName()1736 FilePath SciTEBase::GetLocalPropertiesFileName() {
1737 return FilePath(filePath.Directory(), propLocalFileName);
1738 }
1739
GetDirectoryPropertiesFileName()1740 FilePath SciTEBase::GetDirectoryPropertiesFileName() {
1741 FilePath propfile;
1742
1743 if (filePath.IsSet()) {
1744 propfile.Set(filePath.Directory(), propDirectoryFileName);
1745
1746 // if this file does not exist try to find the prop file in a parent directory
1747 while (!propfile.Directory().IsRoot() && !propfile.Exists()) {
1748 propfile.Set(propfile.Directory().Directory(), propDirectoryFileName);
1749 }
1750
1751 // not found -> set it to the initial directory
1752 if (!propfile.Exists()) {
1753 propfile.Set(filePath.Directory(), propDirectoryFileName);
1754 }
1755 }
1756 return propfile;
1757 }
1758
OpenProperties(int propsFile)1759 void SciTEBase::OpenProperties(int propsFile) {
1760 FilePath propfile;
1761 switch (propsFile) {
1762 case IDM_OPENLOCALPROPERTIES:
1763 propfile = GetLocalPropertiesFileName();
1764 Open(propfile, ofQuiet);
1765 break;
1766 case IDM_OPENUSERPROPERTIES:
1767 propfile = GetUserPropertiesFileName();
1768 Open(propfile, ofQuiet);
1769 break;
1770 case IDM_OPENABBREVPROPERTIES:
1771 propfile = pathAbbreviations;
1772 Open(propfile, ofQuiet);
1773 break;
1774 case IDM_OPENGLOBALPROPERTIES:
1775 propfile = GetDefaultPropertiesFileName();
1776 Open(propfile, ofQuiet);
1777 break;
1778 case IDM_OPENLUAEXTERNALFILE: {
1779 GUI::gui_string extlua = GUI::StringFromUTF8(props.GetExpandedString("ext.lua.startup.script"));
1780 if (extlua.length()) {
1781 Open(extlua, ofQuiet);
1782 }
1783 break;
1784 }
1785 case IDM_OPENDIRECTORYPROPERTIES: {
1786 propfile = GetDirectoryPropertiesFileName();
1787 const bool alreadyExists = propfile.Exists();
1788 Open(propfile, ofQuiet);
1789 if (!alreadyExists)
1790 SaveAsDialog();
1791 }
1792 break;
1793 }
1794 }
1795
1796 // return the int value of the command name passed in.
GetMenuCommandAsInt(std::string commandName)1797 int SciTEBase::GetMenuCommandAsInt(std::string commandName) {
1798 int i = IFaceTable::FindConstant(commandName.c_str());
1799 if (i != -1) {
1800 return IFaceTable::constants[i].value;
1801 }
1802
1803 // Check also for a SCI command, as long as it has no parameters
1804 i = IFaceTable::FindFunctionByConstantName(commandName.c_str());
1805 if (i != -1 &&
1806 IFaceTable::functions[i].paramType[0] == iface_void &&
1807 IFaceTable::functions[i].paramType[1] == iface_void) {
1808 return IFaceTable::functions[i].value;
1809 }
1810
1811 // Otherwise we might have entered a number as command to access a "SCI_" command
1812 return atoi(commandName.c_str());
1813 }
1814