Re: Patch for Scintillua style handling
Mitchell <[email protected]>
| Newsgroups | gmane.editors.scite.general |
|---|---|
| Message-ID | <[email protected]> |
Hi Neil, I have one more patch for you before 5.3.0 goes out. This is a diff and file against the change you previously committed for me. For Scintillua style names with more than one component (e.g. 'function.builtin' or 'string.longstring'), a property like this is set: style.scintillua.cpp.3=$(scintillua.styles.function),$(scintillua.styles.function.builtin) This allows for more targeted styling. It's similar to your tags concept: https://www.scintilla.org/StyleMetadata.html I'm still not an expert with C++, so feel free to point out anything that needs changing or could be done better. Cheers, Mitchell -- You received this message because you are subscribed to the Google Groups "scite-interest" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/scite-interest/20220823235923.0694f23064e3aad51528ebf7%40triplequasar.com.
scite_scintillua.diff
(text/x-diff, 2.3 KB)
diff -r be5c8e9e2e0d src/SciTEProps.cxx
--- a/src/SciTEProps.cxx Tue Aug 16 09:43:05 2022 +1000
+++ b/src/SciTEProps.cxx Tue Aug 23 23:37:48 2022 -0400
@@ -1668,22 +1668,31 @@
namespace {
-// Scintillua's style numbers are not constant, so ask it for names of styles
-// and create a mapping of style numbers to more constant style definitions.
-// For example, if Scintillua reports for the cpp lexer that style number 2 is
-// associated with comments, create the property:
+// Scintillua's style numbers are not constant, so ask it for names of styles and create a
+// mapping of style numbers to more constant style definitions.
+// For example, if Scintillua reports for the cpp lexer that style number 2 is a 'comment',
+// create the property:
// style.scintillua.cpp.2=$(scintillua.styles.comment)
-// That way the user can define 'scintillua.styles.comment' once and it will
-// be used for whatever the style number for comments is in any given lexer.
+// That way the user can define 'scintillua.styles.comment' once and it will be used for whatever
+// the style number for comments is in any given lexer.
+// Similarly, if Scintillua reports for the lua lexer that style number 20 is 'string.longstring',
+// create the property:
+// style.scintillua.lua.20=$(scintillua.styles.string),$(scintillua.styles.string.longstring)
void SetScintilluaStyles(GUI::ScintillaWindow &wEditor, PropSetFile& props, const char *languageName) {
const auto setStyle = [&wEditor, &props, &languageName](int style) {
+ std::string finalPropStr;
+ const std::string &name = wEditor.NameOfStyle(style);
+ size_t end = -1;
+ do {
+ end = name.find('.', ++end);
+ char propStr[128] = "";
+ sprintf(propStr, "$(scintillua.styles.%s),", end == std::string::npos ?
+ name.c_str() : name.substr(0, end).c_str());
+ finalPropStr += propStr;
+ } while (end != std::string::npos);
char key[256] = "";
- char styleName[64] = "";
- char propStr[128] = "";
sprintf(key, "style.%s.%0d", languageName, style);
- wEditor.NameOfStyle(style, styleName);
- sprintf(propStr, "$(scintillua.styles.%s)", styleName);
- props.Set(key, propStr);
+ props.Set(key, finalPropStr.c_str());
};
const int namedStyles = wEditor.NamedStyles(); // this count includes predefined styles
constexpr int LastPredefined = static_cast<int>(Scintilla::StylesCommon::LastPredefined);
SciTEProps.cxx
(text/x-c++src, 73.8 KB)
// SciTE - Scintilla based Text Editor /** @file SciTEProps.cxx ** Properties management. **/ // Copyright 1998-2011 by Neil Hodgson <[email protected]> // The License.txt file describes the conditions under which this software may be distributed. #include <cstddef> #include <cstdlib> #include <cstdint> #include <cstring> #include <cstdio> #include <ctime> #include <clocale> #include <tuple> #include <string> #include <string_view> #include <vector> #include <map> #include <set> #include <optional> #include <algorithm> #include <memory> #include <chrono> #include <atomic> #include <mutex> #include <fcntl.h> #include "ILexer.h" #include "ScintillaTypes.h" #include "ScintillaMessages.h" #include "ScintillaCall.h" #include "Scintilla.h" #include "SciLexer.h" #include "Lexilla.h" #include "LexillaAccess.h" #include "GUI.h" #include "ScintillaWindow.h" #if (defined(__unix__) || defined(__APPLE__)) && !defined(QT_QML) const GUI::gui_char menuAccessIndicator[] = GUI_TEXT("_"); #else const GUI::gui_char menuAccessIndicator[] = GUI_TEXT("&"); #endif #include "StringList.h" #include "StringHelpers.h" #include "FilePath.h" #include "StyleDefinition.h" #include "PropSetFile.h" #include "StyleWriter.h" #include "Extender.h" #include "SciTE.h" #include "JobQueue.h" #include "Cookie.h" #include "Worker.h" #include "MatchMarker.h" #include "EditorConfig.h" #include "Searcher.h" #include "SciTEBase.h" #include "IFaceTable.h" void SciTEBase::SetImportMenu() { for (int i = 0; i < importMax; i++) { DestroyMenuItem(menuOptions, importCmdID + i); } if (!importFiles.empty()) { for (int stackPos = 0; stackPos < static_cast<int>(importFiles.size()) && stackPos < importMax; stackPos++) { const int itemID = importCmdID + stackPos; if (importFiles[stackPos].IsSet()) { GUI::gui_string entry = localiser.Text("Open"); entry += GUI_TEXT(" "); entry += importFiles[stackPos].Name().AsInternal(); SetMenuItem(menuOptions, IMPORT_START + stackPos, itemID, entry.c_str()); } } } } void SciTEBase::ImportMenu(int pos) { if (pos >= 0) { if (importFiles[pos].IsSet()) { Open(importFiles[pos]); } } } void SciTEBase::SetLanguageMenu() { for (int i = 0; i < 100; i++) { DestroyMenuItem(menuLanguage, languageCmdID + i); } for (unsigned int item = 0; item < languageMenu.size(); item++) { const int itemID = languageCmdID + item; const GUI::gui_string entry = localiser.Text(languageMenu[item].menuItem.c_str()); const GUI::gui_string menuKey = GUI::StringFromUTF8(languageMenu[item].menuKey); if (entry.size() && entry[0] != '#') { SetMenuItem(menuLanguage, item, itemID, entry.c_str(), menuKey.c_str()); } } } // Null except on Windows where it may be overridden void SciTEBase::ReadEmbeddedProperties() { } const GUI::gui_char propLocalFileName[] = GUI_TEXT("SciTE.properties"); const GUI::gui_char propDirectoryFileName[] = GUI_TEXT("SciTEDirectory.properties"); void SciTEBase::ReadEnvironment() { #if defined(__unix__) || defined(__APPLE__) extern char **environ; char **e = environ; #else char **e = _environ; #endif for (; e && *e; e++) { const auto [key, value] = ViewSplit(*e, '='); propsPlatform.Set(key, value); } } /** Read global and user properties files. */ void SciTEBase::ReadGlobalPropFile() { // Appearance and Contrast may be read in embedded or global properties // so set them in deepest property set propsPlatform. propsPlatform.Set("Appearance", StdStringFromInteger(appearance.dark)); propsPlatform.Set("Contrast", StdStringFromInteger(appearance.highContrast)); std::string excludes; std::string includes; // Want to apply imports.exclude and imports.include but these may well be in // user properties. for (int attempt=0; attempt<2; attempt++) { std::string excludesRead = props.GetString("imports.exclude"); std::string includesRead = props.GetString("imports.include"); if ((attempt > 0) && ((excludesRead == excludes) && (includesRead == includes))) break; excludes = excludesRead; includes = includesRead; filter.SetFilter(excludes, includes); importFiles.clear(); ReadEmbeddedProperties(); propsBase.Clear(); FilePath propfileBase = GetDefaultPropertiesFileName(); propsBase.Read(propfileBase, propfileBase.Directory(), filter, &importFiles, 0); propsUser.Clear(); FilePath propfileUser = GetUserPropertiesFileName(); propsUser.Read(propfileUser, propfileUser.Directory(), filter, &importFiles, 0); } if (!localiser.read) { ReadLocalization(); } } void SciTEBase::ReadAbbrevPropFile() { propsAbbrev.Clear(); propsAbbrev.Read(pathAbbreviations, pathAbbreviations.Directory(), filter, &importFiles, 0); } /** Reads the directory properties file depending on the variable "properties.directory.enable". Also sets the variable $(SciteDirectoryHome) to the path where this property file is found. If it is not found $(SciteDirectoryHome) will be set to $(FilePath). */ void SciTEBase::ReadDirectoryPropFile() { propsDirectory.Clear(); propsDirectory.SetPath("FilePath", filePath); propsDirectory.SetPath("FileDir", filePath.Directory()); propsDirectory.SetPath("FileName", filePath.BaseName()); propsDirectory.SetPath("FileExt", filePath.Extension()); propsDirectory.SetPath("FileNameExt", FileNameExt()); if (props.GetInt("properties.directory.enable") != 0) { const FilePath propfile = GetDirectoryPropertiesFileName(); const FilePath propfileDirectory = propfile.Directory(); const GUI::gui_string relPath = propfileDirectory.RelativePathTo(filePath); propsDirectory.Set("RelativePath", GUI::UTF8FromString(relPath)); props.SetPath("SciteDirectoryHome", propfileDirectory); propsDirectory.Read(propfile, propfileDirectory, filter, nullptr, 0); } else { propsDirectory.SetPath("RelativePath", filePath.Name()); } } /** Read local and directory properties file. */ void SciTEBase::ReadLocalPropFile() { // The directory properties acts like a base local properties file. // Therefore it must be read always before reading the local prop file. ReadDirectoryPropFile(); FilePath propfile = GetLocalPropertiesFileName(); propsLocal.Clear(); propsLocal.Read(propfile, propfile.Directory(), filter, nullptr, 0); props.Set("Chrome", "#C0C0C0"); props.Set("ChromeHighlight", "#FFFFFF"); FilePath fileDirectory = filePath.Directory(); editorConfig->Clear(); if (props.GetInt("editor.config.enable", 0)) { editorConfig->ReadFromDirectory(fileDirectory); } } SA::Colour ColourOfProperty(const PropSetFile &props, const char *key, SA::Colour colourDefault) { std::string colour = props.GetExpandedString(key); if (colour.length()) { return ColourFromString(colour); } return colourDefault; } SA::ColourAlpha ColourAlphaOfProperty(const PropSetFile &props, const char *key, SA::ColourAlpha colourDefault) { std::string colour = props.GetExpandedString(key); if (colour.length()) { return ColourAlphaFromString(colour); } return colourDefault; } namespace { void OptionalSetColour(GUI::ScintillaWindow &scintilla, SA::Element element, const PropSetFile &props, const char *key) { std::string colour = props.GetExpandedString(key); if (colour.length()) { const SA::Colour colourElement = ColourAlphaFromString(colour); scintilla.SetElementColour(element, colourElement); } else { scintilla.ResetElementColour(element); } } } void SciTEBase::SetElementColour(SA::Element element, const char *key) { OptionalSetColour(wEditor, element, props, key); OptionalSetColour(wOutput, element, props, key); } /** * Put the next property item from the given property string * into the buffer pointed by @a pPropItem. * @return NULL if the end of the list is met, else, it points to the next item. */ const char *SciTEBase::GetNextPropItem( const char *pStart, /**< the property string to parse for the first call, * pointer returned by the previous call for the following. */ char *pPropItem, ///< pointer on a buffer receiving the requested prop item size_t maxLen) noexcept { ///< size of the above buffer ptrdiff_t size = maxLen - 1; *pPropItem = '\0'; if (!pStart) { return nullptr; } const char *pNext = strchr(pStart, ','); if (pNext) { // Separator is found if (size > pNext - pStart) { // Found string fits in buffer size = pNext - pStart; } pNext++; } strncpy(pPropItem, pStart, size); pPropItem[size] = '\0'; return pNext; } std::string SciTEBase::StyleString(const char *lang, int style) const { char key[200]; sprintf(key, "style.%s.%0d", lang, style); return props.GetExpandedString(key); } StyleDefinition SciTEBase::StyleDefinitionFor(int style) { const std::string ssDefault = StyleString("*", style); std::string ss = StyleString(language.c_str(), style); if (!subStyleBases.empty()) { const int baseStyle = wEditor.StyleFromSubStyle(style); if (baseStyle != style) { const int primaryStyle = wEditor.PrimaryStyleFromStyle(style); const int distanceSecondary = (style == primaryStyle) ? 0 : wEditor.DistanceToSecondaryStyles(); const int primaryBase = baseStyle - distanceSecondary; const int subStylesStart = wEditor.SubStylesStart(primaryBase); const int subStylesLength = wEditor.SubStylesLength(primaryBase); const int subStyle = style - (subStylesStart + distanceSecondary); if (subStyle < subStylesLength) { char key[200]; sprintf(key, "style.%s.%0d.%0d", language.c_str(), baseStyle, subStyle + 1); ss = props.GetNewExpandString(key); } } } StyleDefinition sd(ssDefault); sd.ParseStyleDefinition(ss); return sd; } void SciTEBase::SetOneStyle(GUI::ScintillaWindow &win, int style, const StyleDefinition &sd) { if (sd.specified & StyleDefinition::sdItalics) win.StyleSetItalic(style, sd.italics); if (sd.specified & StyleDefinition::sdWeight) win.StyleSetWeight(style, sd.weight); if (sd.specified & StyleDefinition::sdFont) { win.StyleSetFont(style, sd.font.c_str()); bool inMonospacedList = !monospacedList.empty() && (monospacedList.back() == "*"); if (!inMonospacedList) { inMonospacedList = std::find(monospacedList.begin(), monospacedList.end(), sd.font) != monospacedList.end(); } win.StyleSetCheckMonospaced(style, inMonospacedList); } if (sd.specified & StyleDefinition::sdFore) win.StyleSetFore(style, sd.Fore()); if (sd.specified & StyleDefinition::sdBack) win.StyleSetBack(style, sd.Back()); if (sd.specified & StyleDefinition::sdSize) win.StyleSetSizeFractional(style, sd.FractionalSize()); if (sd.specified & StyleDefinition::sdEOLFilled) win.StyleSetEOLFilled(style, sd.eolfilled); if (sd.specified & StyleDefinition::sdUnderlined) win.StyleSetUnderline(style, sd.underlined); if (sd.specified & StyleDefinition::sdCaseForce) win.StyleSetCase(style, sd.caseForce); if (sd.specified & StyleDefinition::sdVisible) win.StyleSetVisible(style, sd.visible); if (sd.specified & StyleDefinition::sdChangeable) win.StyleSetChangeable(style, sd.changeable); win.StyleSetCharacterSet(style, characterSet); } void SciTEBase::SetStyleBlock(GUI::ScintillaWindow &win, const char *lang, int start, int last) { for (int style = start; style <= last; style++) { if (style != StyleDefault) { char key[200]; sprintf(key, "style.%s.%0d", lang, style-start); std::string sval = props.GetExpandedString(key); if (sval.length()) { SetOneStyle(win, style, StyleDefinition(sval)); } } } } void SciTEBase::SetStyleFor(GUI::ScintillaWindow &win, const char *lang) { SetStyleBlock(win, lang, 0, StyleMax); } void SciTEBase::SetOneIndicator(GUI::ScintillaWindow &win, SA::IndicatorNumbers indicator, const IndicatorDefinition &ind) { const int indic = static_cast<int>(indicator); win.IndicSetStyle(indic, ind.style); win.IndicSetFore(indic, ind.colour); win.IndicSetAlpha(indic, ind.fillAlpha); win.IndicSetOutlineAlpha(indic, ind.outlineAlpha); win.IndicSetUnder(indic, ind.under); } void SciTEBase::SetIndicatorFromProperty(GUI::ScintillaWindow &win, SA::IndicatorNumbers indicator, const std::string &propertyName) { const std::string indicatorString = props.GetExpandedString(propertyName.c_str()); if (!indicatorString.empty()) { IndicatorDefinition modifiedIndicator(indicatorString); SetOneIndicator(win, indicator, modifiedIndicator); } } void SciTEBase::SetMarkerFromProperty(GUI::ScintillaWindow &win, int marker, const std::string &propertyName) { const std::string markerString = props.GetExpandedString(propertyName.c_str()); if (!markerString.empty()) { MarkerDefinition markerValue(markerString); win.MarkerDefine(marker, markerValue.style); win.MarkerSetFore(marker, markerValue.colour); win.MarkerSetBack(marker, markerValue.back); } } std::string SciTEBase::ExtensionFileName() const { if (CurrentBufferConst()->overrideExtension.length()) { return CurrentBufferConst()->overrideExtension; } else { FilePath name = FileNameExt(); if (name.IsSet()) { #if !defined(GTK) // Force extension to lower case std::string extension = name.Extension().AsUTF8(); if (extension.empty()) { return name.AsUTF8(); } else { LowerCaseAZ(extension); return name.BaseName().AsUTF8() + "." + extension; } #else return name.AsUTF8(); #endif } else { return props.GetString("default.file.ext"); } } } void SciTEBase::ForwardPropertyToEditor(const char *key) { if (props.Exists(key)) { std::string value = props.GetExpandedString(key); wEditor.SetProperty(key, value.c_str()); wOutput.SetProperty(key, value.c_str()); } } void SciTEBase::DefineMarker(SA::MarkerOutline marker, SA::MarkerSymbol markerType, MarkerAppearance markerAppearance) { const int markerNumber = static_cast<int>(marker); wEditor.MarkerDefine(markerNumber, markerType); wEditor.MarkerSetForeTranslucent(markerNumber, markerAppearance.fore); wEditor.MarkerSetBackTranslucent(markerNumber, markerAppearance.back); wEditor.MarkerSetBackSelectedTranslucent(markerNumber, markerAppearance.backSelected); wEditor.MarkerSetStrokeWidth(markerNumber, markerAppearance.strokeWidth); } void SciTEBase::ReadAPI(const std::string &fileNameForExtension) { std::string sApiFileNames = props.GetNewExpandString("api.", fileNameForExtension.c_str()); if (sApiFileNames.length() > 0) { std::vector<std::string> vApiFileNames = StringSplit(sApiFileNames, ';'); std::vector<char> data; // Load files into data for (const std::string &vApiFileName : vApiFileNames) { std::string contents = FilePath(GUI::StringFromUTF8(vApiFileName)).Read(); data.insert(data.end(), contents.begin(), contents.end()); } // Initialise apis if (data.size() > 0) { apis.Set(data); } } } std::string SciTEBase::FindLanguageProperty(const char *pattern, const char *defaultValue) { std::string key = pattern; Substitute(key, "*", language); std::string ret = props.GetExpandedString(key.c_str()); if (ret == "") ret = props.GetExpandedString(pattern); if (ret == "") ret = defaultValue; return ret; } /** * A list of all the properties that should be forwarded to Scintilla lexers. */ static const char *propertiesToForward[] = { "fold.scintillua.by.indentation", "fold.scintillua.line.groups", "fold.scintillua.on.zero.sum.lines", "fold.scintillua.compact", //++Autogenerated -- run ../scripts/RegenerateSource.py to regenerate //**\(\t"\*",\n\) "asp.default.language", "fold", "fold.abl.comment.multiline", "fold.abl.syntax.based", "fold.asm.comment.explicit", "fold.asm.comment.multiline", "fold.asm.explicit.anywhere", "fold.asm.explicit.end", "fold.asm.explicit.start", "fold.asm.syntax.based", "fold.at.else", "fold.baan.inner.level", "fold.baan.keywords.based", "fold.baan.sections", "fold.baan.syntax.based", "fold.basic.comment.explicit", "fold.basic.explicit.anywhere", "fold.basic.explicit.end", "fold.basic.explicit.start", "fold.basic.syntax.based", "fold.cil.comment.multiline", "fold.coffeescript.comment", "fold.comment", "fold.comment.nimrod", "fold.comment.yaml", "fold.compact", "fold.cpp.comment.explicit", "fold.cpp.comment.multiline", "fold.cpp.explicit.anywhere", "fold.cpp.explicit.end", "fold.cpp.explicit.start", "fold.cpp.preprocessor.at.else", "fold.cpp.syntax.based", "fold.d.comment.explicit", "fold.d.comment.multiline", "fold.d.explicit.anywhere", "fold.d.explicit.end", "fold.d.explicit.start", "fold.d.syntax.based", "fold.dataflex.compilerlist", "fold.directive", "fold.fsharp.comment.multiline", "fold.fsharp.comment.stream", "fold.fsharp.imports", "fold.fsharp.preprocessor", "fold.gdscript.quotes", "fold.haskell.imports", "fold.html", "fold.html.preprocessor", "fold.hypertext.comment", "fold.hypertext.heredoc", "fold.julia.docstring", "fold.julia.syntax.based", "fold.perl.at.else", "fold.perl.comment.explicit", "fold.perl.package", "fold.perl.pod", "fold.preprocessor", "fold.quotes.nimrod", "fold.quotes.python", "fold.raku.comment.multiline", "fold.raku.comment.pod", "fold.rust.comment.explicit", "fold.rust.comment.multiline", "fold.rust.explicit.anywhere", "fold.rust.explicit.end", "fold.rust.explicit.start", "fold.rust.syntax.based", "fold.sql.at.else", "fold.sql.only.begin", "fold.verilog.flags", "fold.xml.at.tag.open", "html.tags.case.sensitive", "lexer.as.comment.character", "lexer.asm.comment.delimiter", "lexer.baan.styling.within.preprocessor", "lexer.caml.magic", "lexer.cpp.allow.dollars", "lexer.cpp.backquoted.strings", "lexer.cpp.escape.sequence", "lexer.cpp.hashquoted.strings", "lexer.cpp.track.preprocessor", "lexer.cpp.triplequoted.strings", "lexer.cpp.update.preprocessor", "lexer.cpp.verbatim.strings.allow.escapes", "lexer.css.hss.language", "lexer.css.less.language", "lexer.css.scss.language", "lexer.d.fold.at.else", "lexer.edifact.highlight.un.all", "lexer.errorlist.escape.sequences", "lexer.errorlist.value.separate", "lexer.flagship.styling.within.preprocessor", "lexer.gdscript.keywords2.no.sub.identifiers", "lexer.gdscript.literals.binary", "lexer.gdscript.strings.over.newline", "lexer.gdscript.unicode.identifiers", "lexer.gdscript.whinge.level", "lexer.haskell.allow.hash", "lexer.haskell.allow.questionmark", "lexer.haskell.allow.quotes", "lexer.haskell.cpp", "lexer.haskell.import.safe", "lexer.html.django", "lexer.html.mako", "lexer.json.allow.comments", "lexer.json.escape.sequence", "lexer.julia.highlight.lexerror", "lexer.julia.highlight.typeannotation", "lexer.markdown.header.eolfill", "lexer.metapost.comment.process", "lexer.metapost.interface.default", "lexer.nim.raw.strings.highlight.ident", "lexer.pascal.smart.highlighting", "lexer.props.allow.initial.spaces", "lexer.python.decorator.attributes", "lexer.python.identifier.attributes", "lexer.python.keywords2.no.sub.identifiers", "lexer.python.literals.binary", "lexer.python.strings.b", "lexer.python.strings.f", "lexer.python.strings.over.newline", "lexer.python.strings.u", "lexer.python.unicode.identifiers", "lexer.rust.fold.at.else", "lexer.sql.allow.dotted.word", "lexer.sql.backticks.identifier", "lexer.sql.numbersign.comment", "lexer.tex.auto.if", "lexer.tex.comment.process", "lexer.tex.interface.default", "lexer.tex.use.keywords", "lexer.verilog.allupperkeywords", "lexer.verilog.fold.preprocessor.else", "lexer.verilog.portstyling", "lexer.verilog.track.preprocessor", "lexer.verilog.update.preprocessor", "lexer.visualprolog.backquoted.strings", "lexer.visualprolog.verbatim.strings", "lexer.xml.allow.scripts", "nsis.ignorecase", "nsis.uservars", "ps.level", "sql.backslash.escapes", "styling.within.preprocessor", "tab.timmy.whinge.level", //--Autogenerated -- end of automatically generated section nullptr, }; /* XPM */ static const char *bookmarkBluegem[] = { /* width height num_colors chars_per_pixel */ " 15 15 64 1", /* colors */ " c none", ". c #0c0630", "# c #8c8a8c", "a c #244a84", "b c #545254", "c c #cccecc", "d c #949594", "e c #346ab4", "f c #242644", "g c #3c3e3c", "h c #6ca6fc", "i c #143789", "j c #204990", "k c #5c8dec", "l c #707070", "m c #3c82dc", "n c #345db4", "o c #619df7", "p c #acacac", "q c #346ad4", "r c #1c3264", "s c #174091", "t c #5482df", "u c #4470c4", "v c #2450a0", "w c #14162c", "x c #5c94f6", "y c #b7b8b7", "z c #646464", "A c #3c68b8", "B c #7cb8fc", "C c #7c7a7c", "D c #3462b9", "E c #7c7eac", "F c #44464c", "G c #a4a4a4", "H c #24224c", "I c #282668", "J c #5c5a8c", "K c #7c8ebc", "L c #dcd7e4", "M c #141244", "N c #1c2e5c", "O c #24327c", "P c #4472cc", "Q c #6ca2fc", "R c #74b2fc", "S c #24367c", "T c #b4b2c4", "U c #403e58", "V c #4c7fd6", "W c #24428c", "X c #747284", "Y c #142e7c", "Z c #64a2fc", "0 c #3c72dc", "1 c #bcbebc", "2 c #6c6a6c", "3 c #848284", "4 c #2c5098", "5 c #1c1a1c", "6 c #243250", "7 c #7cbefc", "8 c #d4d2d4", /* pixels */ " yCbgbCy ", " #zGGyGGz# ", " #zXTLLLTXz# ", " p5UJEKKKEJU5p ", " lfISa444aSIfl ", " wIYij444jsYIw ", " .OsvnAAAnvsO. ", " MWvDuVVVPDvWM ", " HsDPVkxxtPDsH ", " UiAtxohZxtuiU ", " pNnkQRBRhkDNp ", " 1FrqoR7Bo0rF1 ", " 8GC6aemea6CG8 ", " cG3l2z2l3Gc ", " 1GdddG1 " }; std::string SciTEBase::GetFileNameProperty(const char *name) { std::string namePlusDot = name; namePlusDot.append("."); std::string valueForFileName = props.GetNewExpandString(namePlusDot.c_str(), ExtensionFileName().c_str()); if (valueForFileName.length() != 0) { return valueForFileName; } else { return props.GetString(name); } } void SciTEBase::SetRepresentations() { wEditor.ClearAllRepresentations(); const std::string representations = props.GetExpandedString("representations"); std::string_view reprs = representations; bool colourSet = false; SA::Colour colourRepresentation = 0; bool appearanceSet = false; SA::RepresentationAppearance appearanceRepresentation = SA::RepresentationAppearance::Blob; while (!reprs.empty()) { if (reprs[0] == ',') { reprs.remove_prefix(1); } if (!reprs.empty()) { const std::string_view item = reprs.substr(0, reprs.find_first_of(',')); if (!item.empty()) { if (item[0] == '!') { // Appearance if (item.length() == 1) { appearanceSet = false; } else { appearanceSet = true; const std::string sAppearance(item.substr(1)); appearanceRepresentation = static_cast<SA::RepresentationAppearance>(IntegerFromString(sAppearance, 0)); } } else if (item[0] == '#') { // Colour if (item.length() == 1) { colourSet = false; } else { colourSet = true; colourRepresentation = ColourAlphaFromString(item); } } else { const size_t eqPos = item.find_first_of('='); if (eqPos != std::string_view::npos) { const std::string target = UnicodeUnEscape(item.substr(0, eqPos)); const std::string representation = UnicodeUnEscape(item.substr(eqPos+1)); wEditor.SetRepresentation(target.c_str(), representation.c_str()); if (appearanceSet) { wEditor.SetRepresentationAppearance(target.c_str(), appearanceRepresentation); } if (colourSet) { wEditor.SetRepresentationColour(target.c_str(), colourRepresentation); } } } reprs.remove_prefix(item.length()); } } } } void SciTEBase::ReadProperties() { if (extender) extender->Clear(); const std::string lexillaPath = props.GetExpandedString("lexilla.path"); Lexilla::Load(lexillaPath.empty() ? "." : lexillaPath); std::vector<std::string> libraryProperties = Lexilla::LibraryProperties(); for (std::string property : libraryProperties) { std::string key("lexilla.context."); key += property; std::string value = props.GetExpandedString(key.c_str()); Lexilla::SetProperty(property.c_str(), value.c_str()); } const std::string fileNameForExtension = ExtensionFileName(); language = props.GetNewExpandString("lexer.", fileNameForExtension.c_str()); if (language.empty()) { language = "null"; } if (static_cast<int>(wEditor.DocumentOptions()) & static_cast<int>(SA::DocumentOption::StylesNone)) { language = "null"; } const std::string languageCurrent = wEditor.LexerLanguage(); if (language != languageCurrent) { if (StartsWith(language, "script_")) { wEditor.SetILexer(nullptr); } else { Scintilla::ILexer5 *plexer = Lexilla::MakeLexer(language); wEditor.SetILexer(plexer); } } props.Set("Language", language); lexLanguage = wEditor.Lexer(); const std::string languageOutput = wOutput.LexerLanguage(); if (languageOutput != "errorlist") { Scintilla::ILexer5 *plexerErrorlist = Lexilla::MakeLexer("errorlist"); wOutput.SetILexer(plexerErrorlist); } const std::string kw0 = props.GetNewExpandString("keywords.", fileNameForExtension.c_str()); wEditor.SetKeyWords(0, kw0.c_str()); for (int wl = 1; wl <= SA::KeywordsetMax; wl++) { std::string kwk = StdStringFromInteger(wl+1); kwk += '.'; kwk.insert(0, "keywords"); const std::string kw = props.GetNewExpandString(kwk.c_str(), fileNameForExtension.c_str()); wEditor.SetKeyWords(wl, kw.c_str()); } subStyleBases = wEditor.SubStyleBases(); if (!subStyleBases.empty()) { wEditor.FreeSubStyles(); for (const unsigned char subStyleBase : subStyleBases) { //substyles.cpp.11=2 const std::string sStyleBase = StdStringFromInteger(subStyleBase); std::string ssSubStylesKey = "substyles."; ssSubStylesKey += language; ssSubStylesKey += "."; ssSubStylesKey += sStyleBase; std::string ssNumber = props.GetNewExpandString(ssSubStylesKey.c_str()); int subStyleIdentifiers = atoi(ssNumber.c_str()); int subStyleIdentifiersStart = 0; if (subStyleIdentifiers) { subStyleIdentifiersStart = wEditor.AllocateSubStyles(subStyleBase, subStyleIdentifiers); if (subStyleIdentifiersStart < 0) subStyleIdentifiers = 0; } for (int subStyle=0; subStyle<subStyleIdentifiers; subStyle++) { // substylewords.11.1.$(file.patterns.cpp)=CharacterSet LexAccessor SString WordList std::string ssWordsKey = "substylewords."; ssWordsKey += sStyleBase; ssWordsKey += "."; ssWordsKey += StdStringFromInteger(subStyle + 1); ssWordsKey += "."; std::string ssWords = props.GetNewExpandString(ssWordsKey.c_str(), fileNameForExtension.c_str()); wEditor.SetIdentifiers(subStyleIdentifiersStart + subStyle, ssWords.c_str()); } } } props.SetPath("SciteDefaultHome", GetSciteDefaultHome()); props.SetPath("SciteUserHome", GetSciteUserHome()); for (size_t i=0; propertiesToForward[i]; i++) { ForwardPropertyToEditor(propertiesToForward[i]); } if (apisFileNames != props.GetNewExpandString("api.", fileNameForExtension.c_str())) { apis.Clear(); ReadAPI(fileNameForExtension); apisFileNames = props.GetNewExpandString("api.", fileNameForExtension.c_str()); } props.Set("APIPath", apisFileNames); FilePath fileAbbrev = GUI::StringFromUTF8(props.GetNewExpandString("abbreviations.", fileNameForExtension.c_str())); if (!fileAbbrev.IsSet()) fileAbbrev = GetAbbrevPropertiesFileName(); if (!pathAbbreviations.SameNameAs(fileAbbrev)) { pathAbbreviations = fileAbbrev; ReadAbbrevPropFile(); } props.SetPath("AbbrevPath", pathAbbreviations); const SA::Technology tech = static_cast<SA::Technology>(props.GetInt("technology")); wEditor.SetTechnology(tech); wOutput.SetTechnology(tech); const SA::Bidirectional bidirectional = static_cast<SA::Bidirectional>(props.GetInt("bidirectional")); wEditor.SetBidirectional(bidirectional); wOutput.SetBidirectional(bidirectional); codePage = props.GetInt("code.page"); if (CurrentBuffer()->unicodeMode != UniMode::uni8Bit) { // Override properties file to ensure Unicode displayed. codePage = SA::CpUtf8; } wEditor.SetCodePage(codePage); const int outputCodePage = props.GetInt("output.code.page", codePage); wOutput.SetCodePage(outputCodePage); characterSet = static_cast<SA::CharacterSet>(props.GetInt("character.set", static_cast<int>(SA::CharacterSet::Default))); SetRepresentations(); #if defined(__unix__) || defined(__APPLE__) const std::string localeCType = props.GetString("LC_CTYPE"); if (localeCType.length()) setlocale(LC_CTYPE, localeCType.c_str()); else setlocale(LC_CTYPE, "C"); #endif std::string imeInteraction = props.GetString("ime.interaction"); if (imeInteraction.length()) { CallChildren(SA::Message::SetIMEInteraction, props.GetInt("ime.interaction", static_cast<int>(SA::IMEInteraction::Windowed))); } imeAutoComplete = props.GetInt("ime.autocomplete", 0) == 1; const SA::Accessibility accessibility = static_cast<SA::Accessibility>(props.GetInt("accessibility", 1)); wEditor.SetAccessibility(accessibility); wOutput.SetAccessibility(accessibility); wrapStyle = static_cast<SA::Wrap>(props.GetInt("wrap.style", static_cast<int>(SA::Wrap::Word))); CallChildren(SA::Message::SetMouseSelectionRectangularSwitch, props.GetInt("selection.rectangular.switch.mouse", 0)); CallChildren(SA::Message::SetMultipleSelection, props.GetInt("selection.multiple", 1)); CallChildren(SA::Message::SetAdditionalSelectionTyping, props.GetInt("selection.additional.typing", 1)); CallChildren(SA::Message::SetMultiPaste, props.GetInt("selection.multipaste", 1)); CallChildren(SA::Message::SetAdditionalCaretsBlink, props.GetInt("caret.additional.blinks", 1)); CallChildren(SA::Message::SetVirtualSpaceOptions, props.GetInt("virtual.space")); wEditor.SetMouseDwellTime(props.GetInt("dwell.period", SA::TimeForever)); SetElementColour(SA::Element::Caret, "caret.fore"); SetElementColour(SA::Element::CaretAdditional, "caret.additional.fore"); const SA::CaretStyle caretStyle = static_cast<SA::CaretStyle>(props.GetInt("caret.style", static_cast<int>(SA::CaretStyle::Line))); wEditor.SetCaretStyle(caretStyle); wOutput.SetCaretStyle(caretStyle); wEditor.SetCaretWidth(props.GetInt("caret.width", 1)); wOutput.SetCaretWidth(props.GetInt("caret.width", 1)); const std::string caretLineLayer = props.GetExpandedString("caret.line.layer"); if (caretLineLayer.empty()) { std::string caretLineBack = props.GetExpandedString("caret.line.back"); if (caretLineBack.length()) { wEditor.SetCaretLineVisible(true); wEditor.SetCaretLineBack(ColourFromString(caretLineBack)); } else { wEditor.SetCaretLineVisible(false); } wEditor.SetCaretLineBackAlpha( static_cast<SA::Alpha>(props.GetInt("caret.line.back.alpha", static_cast<int>(SA::Alpha::NoAlpha)))); } else { // New scheme const int layer = IntegerFromString(caretLineLayer, 0); CallChildren(SA::Message::SetCaretLineLayer, layer); SetElementColour(SA::Element::CaretLineBack, "caret.line.back"); const int caretLineFrame = props.GetInt("caret.line.frame"); CallChildren(SA::Message::SetCaretLineFrame, caretLineFrame); } int indicatorsAlpha = props.GetInt("indicators.alpha", 30); if (indicatorsAlpha < 0 || 255 < indicatorsAlpha) // If invalid value, indicatorsAlpha = 30; //then set default value. alphaIndicator = static_cast<SA::Alpha>(indicatorsAlpha); underIndicator = props.GetInt("indicators.under", 0) == 1; closeFind = static_cast<CloseFind>(props.GetInt("find.close.on.find", 1)); const std::string controlCharSymbol = props.GetString("control.char.symbol"); if (controlCharSymbol.length()) { wEditor.SetControlCharSymbol(static_cast<unsigned char>(controlCharSymbol[0])); } else { wEditor.SetControlCharSymbol(0); } const std::string caretPeriod = props.GetString("caret.period"); if (caretPeriod.length()) { wEditor.SetCaretPeriod(atoi(caretPeriod.c_str())); wOutput.SetCaretPeriod(atoi(caretPeriod.c_str())); } const int caretZoneX = props.GetInt("caret.policy.width", 50); int caretPolicyX = 0; if (props.GetInt("caret.policy.xslop", 1)) caretPolicyX |= static_cast<int>(SA::CaretPolicy::Slop); if (props.GetInt("caret.policy.xstrict")) caretPolicyX |= static_cast<int>(SA::CaretPolicy::Strict); if (props.GetInt("caret.policy.xeven", 1)) caretPolicyX |= static_cast<int>(SA::CaretPolicy::Even); if (props.GetInt("caret.policy.xjumps")) caretPolicyX |= static_cast<int>(SA::CaretPolicy::Jumps); //wEditor.SetXCaretPolicy(caretStrict | caretSlop | caretEven | caretJumps); wEditor.SetXCaretPolicy(static_cast<SA::CaretPolicy>(caretPolicyX), caretZoneX); const int caretZoneY = props.GetInt("caret.policy.lines"); int caretPolicyY = 0; if (props.GetInt("caret.policy.yslop", 1)) caretPolicyY |= static_cast<int>(SA::CaretPolicy::Slop); if (props.GetInt("caret.policy.ystrict")) caretPolicyY |= static_cast<int>(SA::CaretPolicy::Strict); if (props.GetInt("caret.policy.yeven", 1)) caretPolicyY |= static_cast<int>(SA::CaretPolicy::Even); if (props.GetInt("caret.policy.yjumps")) caretPolicyY |= static_cast<int>(SA::CaretPolicy::Jumps); wEditor.SetYCaretPolicy(static_cast<SA::CaretPolicy>(caretPolicyY), caretZoneY); int visiblePolicy = 0; if (props.GetInt("visible.policy.strict")) visiblePolicy |= static_cast<int>(SA::VisiblePolicy::Strict); if (props.GetInt("visible.policy.slop", 1)) visiblePolicy |= static_cast<int>(SA::VisiblePolicy::Slop); const int visibleLines = props.GetInt("visible.policy.lines"); wEditor.SetVisiblePolicy(static_cast<SA::VisiblePolicy>(visiblePolicy), visibleLines); wEditor.SetEdgeColumn(props.GetInt("edge.column", 0)); wEditor.SetEdgeMode(static_cast<SA::EdgeVisualStyle>( props.GetInt("edge.mode", static_cast<int>(SA::EdgeVisualStyle::None)))); wEditor.SetEdgeColour( ColourOfProperty(props, "edge.colour", ColourRGB(0xff, 0xda, 0xda))); const std::string selectionLayer = props.GetExpandedString("selection.layer"); if (selectionLayer.empty()) { std::string selFore = props.GetExpandedString("selection.fore"); if (selFore.length()) { CallChildren(SA::Message::SetSelFore, 1, ColourFromString(selFore)); } else { CallChildren(SA::Message::SetSelFore, 0, 0); } std::string selBack = props.GetExpandedString("selection.back"); if (selBack.length()) { CallChildren(SA::Message::SetSelBack, 1, ColourFromString(selBack)); } else { if (selFore.length()) CallChildren(SA::Message::SetSelBack, 0, 0); else // Have to show selection somehow CallChildren(SA::Message::SetSelBack, 1, ColourRGB(0xC0, 0xC0, 0xC0)); } constexpr int NoAlpha = static_cast<int>(SA::Alpha::NoAlpha); const int selectionAlpha = props.GetInt("selection.alpha", NoAlpha); CallChildren(SA::Message::SetSelAlpha, selectionAlpha); std::string selAdditionalFore = props.GetString("selection.additional.fore"); if (selAdditionalFore.length()) { CallChildren(SA::Message::SetAdditionalSelFore, ColourFromString(selAdditionalFore)); } std::string selAdditionalBack = props.GetString("selection.additional.back"); if (selAdditionalBack.length()) { CallChildren(SA::Message::SetAdditionalSelBack, ColourFromString(selAdditionalBack)); } const int selectionAdditionalAlpha = (selectionAlpha == NoAlpha) ? NoAlpha : selectionAlpha / 2; CallChildren(SA::Message::SetAdditionalSelAlpha, props.GetInt("selection.additional.alpha", selectionAdditionalAlpha)); } else { // New scheme const int layer = IntegerFromString(selectionLayer, 0); CallChildren(SA::Message::SetSelectionLayer, layer); SetElementColour(SA::Element::SelectionText, "selection.fore"); SetElementColour(SA::Element::SelectionBack, "selection.back"); SetElementColour(SA::Element::SelectionAdditionalText, "selection.additional.fore"); SetElementColour(SA::Element::SelectionAdditionalBack, "selection.additional.back"); SetElementColour(SA::Element::SelectionSecondaryText, "selection.secondary.fore"); SetElementColour(SA::Element::SelectionSecondaryBack, "selection.secondary.back"); SetElementColour(SA::Element::SelectionInactiveText, "selection.inactive.fore"); SetElementColour(SA::Element::SelectionInactiveBack, "selection.inactive.back"); } foldColour = props.GetExpandedString("fold.margin.colour"); if (foldColour.length()) { CallChildren(SA::Message::SetFoldMarginColour, 1, ColourFromString(foldColour)); } else { CallChildren(SA::Message::SetFoldMarginColour, 0, 0); } foldHiliteColour = props.GetExpandedString("fold.margin.highlight.colour"); if (foldHiliteColour.length()) { CallChildren(SA::Message::SetFoldMarginHiColour, 1, ColourFromString(foldHiliteColour)); } else { CallChildren(SA::Message::SetFoldMarginHiColour, 0, 0); } SetElementColour(SA::Element::WhiteSpace, "whitespace.fore"); SetElementColour(SA::Element::WhiteSpaceBack, "whitespace.back"); CallChildren(SA::Message::SetWhitespaceSize, props.GetInt("whitespace.size", 1)); char bracesStyleKey[200]; sprintf(bracesStyleKey, "braces.%s.style", language.c_str()); bracesStyle = props.GetInt(bracesStyleKey, 0); char key[200] = ""; std::string sval; sval = FindLanguageProperty("calltip.*.ignorecase"); callTipIgnoreCase = sval == "1"; sval = FindLanguageProperty("calltip.*.use.escapes"); callTipUseEscapes = sval == "1"; calltipWordCharacters = FindLanguageProperty("calltip.*.word.characters", "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); calltipParametersStart = FindLanguageProperty("calltip.*.parameters.start", "("); calltipParametersEnd = FindLanguageProperty("calltip.*.parameters.end", ")"); calltipParametersSeparators = FindLanguageProperty("calltip.*.parameters.separators", ",;"); calltipEndDefinition = FindLanguageProperty("calltip.*.end.definition"); sprintf(key, "autocomplete.%s.start.characters", language.c_str()); autoCompleteStartCharacters = props.GetExpandedString(key); if (autoCompleteStartCharacters == "") autoCompleteStartCharacters = props.GetExpandedString("autocomplete.*.start.characters"); // "" is a quite reasonable value for this setting sprintf(key, "autocomplete.%s.fillups", language.c_str()); autoCompleteFillUpCharacters = props.GetExpandedString(key); if (autoCompleteFillUpCharacters == "") autoCompleteFillUpCharacters = props.GetExpandedString("autocomplete.*.fillups"); wEditor.AutoCSetFillUps(autoCompleteFillUpCharacters.c_str()); sprintf(key, "autocomplete.%s.typesep", language.c_str()); autoCompleteTypeSeparator = props.GetExpandedString(key); if (autoCompleteTypeSeparator == "") autoCompleteTypeSeparator = props.GetExpandedString("autocomplete.*.typesep"); if (autoCompleteTypeSeparator.length()) { wEditor.AutoCSetTypeSeparator( static_cast<unsigned char>(autoCompleteTypeSeparator[0])); } sprintf(key, "autocomplete.%s.ignorecase", "*"); sval = props.GetNewExpandString(key); autoCompleteIgnoreCase = sval == "1"; sprintf(key, "autocomplete.%s.ignorecase", language.c_str()); sval = props.GetNewExpandString(key); if (sval != "") autoCompleteIgnoreCase = sval == "1"; wEditor.AutoCSetIgnoreCase(autoCompleteIgnoreCase); wOutput.AutoCSetIgnoreCase(true); autoCompleteVisibleItemCount = props.GetInt("autocomplete.visible.item.count", 9); const int autoCChooseSingle = props.GetInt("autocomplete.choose.single"); wEditor.AutoCSetChooseSingle(autoCChooseSingle); wEditor.AutoCSetCancelAtStart(false); wEditor.AutoCSetDropRestOfWord(false); OptionalSetColour(wEditor, SA::Element::List, props, "autocomplete.fore"); OptionalSetColour(wEditor, SA::Element::ListBack, props, "autocomplete.back"); OptionalSetColour(wEditor, SA::Element::ListSelected, props, "autocomplete.selected.fore"); OptionalSetColour(wEditor, SA::Element::ListSelectedBack, props, "autocomplete.selected.back"); if (firstPropertiesRead) { ReadPropertiesInitial(); } ReadFontProperties(); wEditor.SetPrintMagnification(props.GetInt("print.magnification")); wEditor.SetPrintColourMode(static_cast<SA::PrintOption>(props.GetInt("print.colour.mode"))); jobQueue.clearBeforeExecute = props.GetInt("clear.before.execute"); jobQueue.timeCommands = props.GetInt("time.commands"); const int blankMarginLeft = props.GetInt("blank.margin.left", 1); const int blankMarginLeftOutput = props.GetInt("output.blank.margin.left", blankMarginLeft); const int blankMarginRight = props.GetInt("blank.margin.right", 1); wEditor.SetMarginLeft(blankMarginLeft); wEditor.SetMarginRight(blankMarginRight); wOutput.SetMarginLeft(blankMarginLeftOutput); wOutput.SetMarginRight(blankMarginRight); marginWidth = props.GetInt("margin.width"); if (marginWidth == 0) marginWidth = marginWidthDefault; wEditor.SetMarginWidthN(1, margin ? marginWidth : 0); const std::string lineMarginProp = props.GetString("line.margin.width"); lineNumbersWidth = atoi(lineMarginProp.c_str()); if (lineNumbersWidth == 0) lineNumbersWidth = lineNumbersWidthDefault; lineNumbersExpand = lineMarginProp.find('+') != std::string::npos; SetLineNumberWidth(); bufferedDraw = props.GetInt("buffered.draw"); wEditor.SetBufferedDraw(bufferedDraw); wOutput.SetBufferedDraw(bufferedDraw); const SA::PhasesDraw phasesDraw = static_cast<SA::PhasesDraw>( props.GetInt("phases.draw", static_cast<int>(SA::PhasesDraw::Two))); wEditor.SetPhasesDraw(phasesDraw); wOutput.SetPhasesDraw(phasesDraw); wEditor.SetLayoutCache(static_cast<SA::LineCache>( props.GetInt("cache.layout", static_cast<int>(SA::LineCache::Caret)))); wOutput.SetLayoutCache(static_cast<SA::LineCache>( props.GetInt("output.cache.layout", static_cast<int>(SA::LineCache::Caret)))); wEditor.SetLayoutThreads(props.GetInt("threads.layout", 1)); bracesCheck = props.GetInt("braces.check"); bracesSloppy = props.GetInt("braces.sloppy"); wEditor.SetCharsDefault(); wordCharacters = props.GetNewExpandString("word.characters.", fileNameForExtension.c_str()); if (wordCharacters.length()) { wEditor.SetWordChars(wordCharacters.c_str()); } else { wordCharacters = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; } whitespaceCharacters = props.GetNewExpandString("whitespace.characters.", fileNameForExtension.c_str()); if (whitespaceCharacters.length()) { wEditor.SetWhitespaceChars(whitespaceCharacters.c_str()); } const std::string viewIndentExamine = GetFileNameProperty("view.indentation.examine"); indentExamine = viewIndentExamine.length() ? static_cast<SA::IndentView>(atoi(viewIndentExamine.c_str())) : SA::IndentView::Real; wEditor.SetIndentationGuides(props.GetInt("view.indentation.guides") ? indentExamine : SA::IndentView::None); wEditor.SetTabIndents(props.GetInt("tab.indents", 1)); wEditor.SetBackSpaceUnIndents(props.GetInt("backspace.unindents", 1)); wEditor.CallTipUseStyle(32); std::string useStripTrailingSpaces = props.GetNewExpandString("strip.trailing.spaces.", ExtensionFileName().c_str()); if (useStripTrailingSpaces.length() > 0) { stripTrailingSpaces = atoi(useStripTrailingSpaces.c_str()) != 0; } else { stripTrailingSpaces = props.GetInt("strip.trailing.spaces") != 0; } ensureFinalLineEnd = props.GetInt("ensure.final.line.end") != 0; ensureConsistentLineEnds = props.GetInt("ensure.consistent.line.ends") != 0; indentOpening = props.GetInt("indent.opening"); indentClosing = props.GetInt("indent.closing"); indentMaintain = atoi(props.GetNewExpandString("indent.maintain.", fileNameForExtension.c_str()).c_str()); const std::string lookback = props.GetNewExpandString("statement.lookback.", fileNameForExtension.c_str()); statementLookback = atoi(lookback.c_str()); statementIndent = GetStyleAndWords("statement.indent."); statementEnd = GetStyleAndWords("statement.end."); blockStart = GetStyleAndWords("block.start."); blockEnd = GetStyleAndWords("block.end."); struct PropToPPC { const char *propName; PreProc ppc; }; PropToPPC propToPPC[] = { {"preprocessor.start.", PreProc::Start}, {"preprocessor.middle.", PreProc::Middle}, {"preprocessor.end.", PreProc::End}, }; const std::string ppSymbol = props.GetNewExpandString("preprocessor.symbol.", fileNameForExtension.c_str()); preprocessorSymbol = ppSymbol.empty() ? 0 : ppSymbol[0]; preprocOfString.clear(); for (const PropToPPC &preproc : propToPPC) { const std::string list = props.GetNewExpandString(preproc.propName, fileNameForExtension.c_str()); const std::vector<std::string> words = StringSplit(list, ' '); for (const std::string &word : words) { preprocOfString[word] = preproc.ppc; } } std::vector<std::string> fileSets = StringSplit(props.GetNewExpandString("find.files"), '|'); for (const std::string &fileSet : fileSets) { memFiles.Append(fileSet); } wEditor.SetWrapVisualFlags(static_cast<SA::WrapVisualFlag>(props.GetInt("wrap.visual.flags"))); wEditor.SetWrapVisualFlagsLocation(static_cast<SA::WrapVisualLocation>(props.GetInt("wrap.visual.flags.location"))); wEditor.SetWrapStartIndent(props.GetInt("wrap.visual.startindent")); wEditor.SetWrapIndentMode(static_cast<SA::WrapIndentMode>(props.GetInt("wrap.indent.mode"))); idleStyling = static_cast<SA::IdleStyling>(props.GetInt("idle.styling", static_cast<int>(SA::IdleStyling::None))); wEditor.SetIdleStyling(idleStyling); wOutput.SetIdleStyling(static_cast<SA::IdleStyling>(props.GetInt("output.idle.styling", static_cast<int>(SA::IdleStyling::None)))); if (props.GetInt("os.x.home.end.keys")) { AssignKey(SA::Keys::Home, SA::KeyMod::Norm, SCI_SCROLLTOSTART); AssignKey(SA::Keys::Home, SA::KeyMod::Shift, SCI_NULL); AssignKey(SA::Keys::Home, SA::KeyMod::Shift | SA::KeyMod::Alt, SCI_NULL); AssignKey(SA::Keys::End, SA::KeyMod::Norm, SCI_SCROLLTOEND); AssignKey(SA::Keys::End, SA::KeyMod::Shift, SCI_NULL); } else { if (props.GetInt("wrap.aware.home.end.keys", 0)) { if (props.GetInt("vc.home.key", 1)) { AssignKey(SA::Keys::Home, SA::KeyMod::Norm, SCI_VCHOMEWRAP); AssignKey(SA::Keys::Home, SA::KeyMod::Shift, SCI_VCHOMEWRAPEXTEND); AssignKey(SA::Keys::Home, SA::KeyMod::Shift | SA::KeyMod::Alt, SCI_VCHOMERECTEXTEND); } else { AssignKey(SA::Keys::Home, SA::KeyMod::Norm, SCI_HOMEWRAP); AssignKey(SA::Keys::Home, SA::KeyMod::Shift, SCI_HOMEWRAPEXTEND); AssignKey(SA::Keys::Home, SA::KeyMod::Shift | SA::KeyMod::Alt, SCI_HOMERECTEXTEND); } AssignKey(SA::Keys::End, SA::KeyMod::Norm, SCI_LINEENDWRAP); AssignKey(SA::Keys::End, SA::KeyMod::Shift, SCI_LINEENDWRAPEXTEND); } else { if (props.GetInt("vc.home.key", 1)) { AssignKey(SA::Keys::Home, SA::KeyMod::Norm, SCI_VCHOME); AssignKey(SA::Keys::Home, SA::KeyMod::Shift, SCI_VCHOMEEXTEND); AssignKey(SA::Keys::Home, SA::KeyMod::Shift | SA::KeyMod::Alt, SCI_VCHOMERECTEXTEND); } else { AssignKey(SA::Keys::Home, SA::KeyMod::Norm, SCI_HOME); AssignKey(SA::Keys::Home, SA::KeyMod::Shift, SCI_HOMEEXTEND); AssignKey(SA::Keys::Home, SA::KeyMod::Shift | SA::KeyMod::Alt, SCI_HOMERECTEXTEND); } AssignKey(SA::Keys::End, SA::KeyMod::Norm, SCI_LINEEND); AssignKey(SA::Keys::End, SA::KeyMod::Shift, SCI_LINEENDEXTEND); } } AssignKey(static_cast<SA::Keys>('L'), SA::KeyMod::Shift | SA::KeyMod::Ctrl, SCI_LINEDELETE); scrollOutput = props.GetInt("output.scroll", 1); tabHideOne = props.GetInt("tabbar.hide.one"); SetToolsMenu(); wEditor.SetFoldFlags(static_cast<SA::FoldFlag>(props.GetInt("fold.flags"))); // To put the folder markers in the line number region //wEditor.SetMarginMaskN(0, SC_MASK_FOLDERS); wEditor.SetModEventMask(SA::ModificationFlags::ChangeFold); if (0==props.GetInt("undo.redo.lazy")) { // Trap for insert/delete notifications (also fired by undo // and redo) so that the buttons can be enabled if needed. const SA::ModificationFlags flagsCurrent = wEditor.ModEventMask(); const SA::ModificationFlags flags = flagsCurrent | SA::ModificationFlags::InsertText | SA::ModificationFlags::DeleteText | SA::ModificationFlags::LastStepInUndoRedo; wEditor.SetModEventMask(flags); // LastStepInUndoRedo is probably not needed in the mask; it // doesn't seem to fire as an event of its own; just modifies the // insert and delete events. } // Create a margin column for the folding symbols wEditor.SetMarginTypeN(2, SA::MarginType::Symbol); foldMarginWidth = props.GetInt("fold.margin.width"); if (foldMarginWidth == 0) foldMarginWidth = foldMarginWidthDefault; SetFoldWidth(); wEditor.SetMarginMaskN(2, SA::MaskFolders); wEditor.SetMarginSensitiveN(2, true); // Define foreground (outline) and background (fill) colour of folds const int foldSymbols = props.GetInt("fold.symbols"); std::string foldFore = props.GetExpandedString("fold.fore"); if (foldFore.length() == 0) { // Set default colour for outline switch (foldSymbols) { case 0: // Arrows foldFore = "#000000"; break; case 1: // + - foldFore = "#FFFFFF"; break; case 2: // Circles foldFore = "#404040"; break; case 3: // Squares foldFore = "#808080"; break; } } const SA::ColourAlpha colourFoldFore = ColourAlphaFromString(foldFore); std::string foldBack = props.GetExpandedString("fold.back"); // Set default colour for fill if (foldBack.length() == 0) { switch (foldSymbols) { case 0: case 1: foldBack = "#000000"; break; case 2: case 3: foldBack = "#FFFFFF"; break; } } const SA::ColourAlpha colourFoldBack = ColourAlphaFromString(foldBack); // Enable/disable highlight for current folding block (smallest one that contains the caret) const int isHighlightEnabled = props.GetInt("fold.highlight", 0); // Define the colour of highlight const SA::ColourAlpha colourFoldBlockHighlight = ColourAlphaOfProperty( props, "fold.highlight.colour", ColourRGBA(0xFF, 0, 0)); const int foldStrokeWidth = props.GetInt("fold.stroke.width", 100); // Isolated and connected fold markers use foreground and background colours differently MarkerAppearance isolated { colourFoldFore, colourFoldBack, colourFoldBlockHighlight, foldStrokeWidth }; MarkerAppearance connected { colourFoldBack, colourFoldFore, colourFoldBlockHighlight, foldStrokeWidth }; switch (foldSymbols) { case 0: // Arrow pointing right for contracted folders, arrow pointing down for expanded DefineMarker(SA::MarkerOutline::FolderOpen, SA::MarkerSymbol::ArrowDown, isolated); DefineMarker(SA::MarkerOutline::Folder, SA::MarkerSymbol::Arrow, isolated); DefineMarker(SA::MarkerOutline::FolderSub, SA::MarkerSymbol::Empty, isolated); DefineMarker(SA::MarkerOutline::FolderTail, SA::MarkerSymbol::Empty, isolated); DefineMarker(SA::MarkerOutline::FolderEnd, SA::MarkerSymbol::Empty, isolated); DefineMarker(SA::MarkerOutline::FolderOpenMid, SA::MarkerSymbol::Empty, isolated); DefineMarker(SA::MarkerOutline::FolderMidTail, SA::MarkerSymbol::Empty, isolated); // The highlight is disabled for arrow. wEditor.MarkerEnableHighlight(false); break; case 1: // Plus for contracted folders, minus for expanded DefineMarker(SA::MarkerOutline::FolderOpen, SA::MarkerSymbol::Minus, isolated); DefineMarker(SA::MarkerOutline::Folder, SA::MarkerSymbol::Plus, isolated); DefineMarker(SA::MarkerOutline::FolderSub, SA::MarkerSymbol::Empty, isolated); DefineMarker(SA::MarkerOutline::FolderTail, SA::MarkerSymbol::Empty, isolated); DefineMarker(SA::MarkerOutline::FolderEnd, SA::MarkerSymbol::Empty, isolated); DefineMarker(SA::MarkerOutline::FolderOpenMid, SA::MarkerSymbol::Empty, isolated); DefineMarker(SA::MarkerOutline::FolderMidTail, SA::MarkerSymbol::Empty, isolated); // The highlight is disabled for plus/minus. wEditor.MarkerEnableHighlight(false); break; case 2: // Like a flattened tree control using circular headers and curved joins DefineMarker(SA::MarkerOutline::FolderOpen, SA::MarkerSymbol::CircleMinus, connected); DefineMarker(SA::MarkerOutline::Folder, SA::MarkerSymbol::CirclePlus, connected); DefineMarker(SA::MarkerOutline::FolderSub, SA::MarkerSymbol::VLine, connected); DefineMarker(SA::MarkerOutline::FolderTail, SA::MarkerSymbol::LCornerCurve, connected); DefineMarker(SA::MarkerOutline::FolderEnd, SA::MarkerSymbol::CirclePlusConnected, connected); DefineMarker(SA::MarkerOutline::FolderOpenMid, SA::MarkerSymbol::CircleMinusConnected, connected); DefineMarker(SA::MarkerOutline::FolderMidTail, SA::MarkerSymbol::TCornerCurve, connected); wEditor.MarkerEnableHighlight(isHighlightEnabled); break; case 3: // Like a flattened tree control using square headers DefineMarker(SA::MarkerOutline::FolderOpen, SA::MarkerSymbol::BoxMinus, connected); DefineMarker(SA::MarkerOutline::Folder, SA::MarkerSymbol::BoxPlus, connected); DefineMarker(SA::MarkerOutline::FolderSub, SA::MarkerSymbol::VLine, connected); DefineMarker(SA::MarkerOutline::FolderTail, SA::MarkerSymbol::LCorner, connected); DefineMarker(SA::MarkerOutline::FolderEnd, SA::MarkerSymbol::BoxPlusConnected, connected); DefineMarker(SA::MarkerOutline::FolderOpenMid, SA::MarkerSymbol::BoxMinusConnected, connected); DefineMarker(SA::MarkerOutline::FolderMidTail, SA::MarkerSymbol::TCorner, connected); wEditor.MarkerEnableHighlight(isHighlightEnabled); break; } wEditor.MarkerSetForeTranslucent(markerBookmark, ColourAlphaOfProperty(props, "bookmark.fore", ColourRGBA(0xbe, 0, 0))); wEditor.MarkerSetBackTranslucent(markerBookmark, ColourAlphaOfProperty(props, "bookmark.back", ColourRGBA(0xe2, 0x40, 0x40))); wEditor.MarkerSetAlpha(markerBookmark, static_cast<SA::Alpha>(props.GetInt("bookmark.alpha", static_cast<int>(SA::Alpha::NoAlpha)))); wEditor.MarkerSetStrokeWidth(markerBookmark, props.GetInt("bookmark.stroke.width", 100)); const std::string bookMarkXPM = props.GetString("bookmark.pixmap"); if (bookMarkXPM.length()) { wEditor.MarkerDefinePixmap(markerBookmark, bookMarkXPM.c_str()); } else if (props.GetString("bookmark.fore").length()) { wEditor.MarkerDefine(markerBookmark, static_cast<SA::MarkerSymbol>( props.GetInt("bookmark.symbol", static_cast<int>(SA::MarkerSymbol::Bookmark)))); } else { // No bookmark.fore setting so display default pixmap. wEditor.MarkerDefinePixmap(markerBookmark, reinterpret_cast<const char *>(bookmarkBluegem)); } wEditor.MarkerDefine(markerFilterMatch, SA::MarkerSymbol::Background); wEditor.MarkerSetLayer(markerFilterMatch, Scintilla::Layer::UnderText); const SA::ColourAlpha filterMatch = ColourAlphaOfProperty(props, "filter.match.back", ColourRGBA(0xff, 0xe0, 0, 0x20)); wEditor.MarkerSetBackTranslucent(markerFilterMatch, filterMatch); wEditor.MarkerSetAlpha(markerFilterMatch, static_cast<SA::Alpha>(filterMatch >> 24)); wEditor.SetScrollWidth(props.GetInt("horizontal.scroll.width", 2000)); wEditor.SetScrollWidthTracking(props.GetInt("horizontal.scroll.width.tracking", 1)); wOutput.SetScrollWidth(props.GetInt("output.horizontal.scroll.width", 2000)); wOutput.SetScrollWidthTracking(props.GetInt("output.horizontal.scroll.width.tracking", 1)); // Do these last as they force a style refresh wEditor.SetHScrollBar(props.GetInt("horizontal.scrollbar", 1)); wOutput.SetHScrollBar(props.GetInt("output.horizontal.scrollbar", 1)); wEditor.SetEndAtLastLine(props.GetInt("end.at.last.line", 1)); wEditor.SetCaretSticky(static_cast<SA::CaretSticky>(props.GetInt("caret.sticky", 0))); // Clear all previous indicators. wEditor.SetIndicatorCurrent(indicatorHighlightCurrentWord); wEditor.IndicatorClearRange(0, wEditor.Length()); wOutput.SetIndicatorCurrent(indicatorHighlightCurrentWord); wOutput.IndicatorClearRange(0, wOutput.Length()); currentWordHighlight.statesOfDelay = CurrentWordHighlight::StatesOfDelay::noDelay; SetElementColour(SA::Element::FoldLine, "fold.line.colour"); SetElementColour(SA::Element::HiddenLine, "hidden.line.colour"); currentWordHighlight.isEnabled = props.GetInt("highlight.current.word", 0) == 1; if (currentWordHighlight.isEnabled) { const std::string highlightCurrentWordIndicatorString = props.GetExpandedString("highlight.current.word.indicator"); IndicatorDefinition highlightCurrentWordIndicator(highlightCurrentWordIndicatorString.c_str()); if (highlightCurrentWordIndicatorString.length() == 0) { highlightCurrentWordIndicator.style = SA::IndicatorStyle::RoundBox; std::string highlightCurrentWordColourString = props.GetExpandedString("highlight.current.word.colour"); if (highlightCurrentWordColourString.length() == 0) { // Set default colour for highlight. highlightCurrentWordColourString = "#A0A000"; } highlightCurrentWordIndicator.colour = ColourFromString(highlightCurrentWordColourString); highlightCurrentWordIndicator.fillAlpha = alphaIndicator; highlightCurrentWordIndicator.under = underIndicator; } const SA::IndicatorNumbers indicatorNumHCWI = static_cast<SA::IndicatorNumbers>(indicatorHighlightCurrentWord); SetOneIndicator(wEditor, indicatorNumHCWI, highlightCurrentWordIndicator); SetOneIndicator(wOutput, indicatorNumHCWI, highlightCurrentWordIndicator); currentWordHighlight.isOnlyWithSameStyle = props.GetInt("highlight.current.word.by.style", 0) == 1; HighlightCurrentWord(true); } SetIndicatorFromProperty(wEditor, SA::IndicatorNumbers::HistoryRevertedToOriginInsertion, "indicator.reverted.to.origin.insertion"); SetIndicatorFromProperty(wEditor, SA::IndicatorNumbers::HistoryRevertedToOriginDeletion, "indicator.reverted.to.origin.deletion"); SetIndicatorFromProperty(wEditor, SA::IndicatorNumbers::HistorySavedInsertion, "indicator.saved.insertion"); SetIndicatorFromProperty(wEditor, SA::IndicatorNumbers::HistorySavedDeletion, "indicator.saved.deletion"); SetIndicatorFromProperty(wEditor, SA::IndicatorNumbers::HistoryModifiedInsertion, "indicator.modified.insertion"); SetIndicatorFromProperty(wEditor, SA::IndicatorNumbers::HistoryModifiedDeletion, "indicator.modified.deletion"); SetIndicatorFromProperty(wEditor, SA::IndicatorNumbers::HistoryRevertedToModifiedInsertion, "indicator.reverted.to.modified.insertion"); SetIndicatorFromProperty(wEditor, SA::IndicatorNumbers::HistoryRevertedToModifiedDeletion, "indicator.reverted.to.modified.deletion"); constexpr size_t markerHistory = static_cast<size_t>(SA::MarkerOutline::HistoryRevertedToOrigin); SetMarkerFromProperty(wEditor, markerHistory+0, "marker.reverted.to.origin"); SetMarkerFromProperty(wEditor, markerHistory+1, "marker.saved"); SetMarkerFromProperty(wEditor, markerHistory+2, "marker.modified"); SetMarkerFromProperty(wEditor, markerHistory+3, "marker.reverted.to.modified"); ReadEditorConfig(fileNameForExtension); if (extender) { FilePath defaultDir = GetDefaultDirectory(); FilePath scriptPath; // Check for an extension script GUI::gui_string extensionFile = GUI::StringFromUTF8( props.GetNewExpandString("extension.", fileNameForExtension.c_str())); if (extensionFile.length()) { // find file in local directory FilePath docDir = filePath.Directory(); if (Exists(docDir.AsInternal(), extensionFile.c_str(), &scriptPath)) { // Found file in document directory extender->Load(scriptPath.AsUTF8().c_str()); } else if (Exists(defaultDir.AsInternal(), extensionFile.c_str(), &scriptPath)) { // Found file in global directory extender->Load(scriptPath.AsUTF8().c_str()); } else if (Exists(GUI_TEXT(""), extensionFile.c_str(), &scriptPath)) { // Found as completely specified file name extender->Load(scriptPath.AsUTF8().c_str()); } } } delayBeforeAutoSave = props.GetInt("save.on.timer"); if (delayBeforeAutoSave) { TimerStart(timerAutoSave); } else { TimerEnd(timerAutoSave); } firstPropertiesRead = false; needReadProperties = false; } void SciTEBase::ReadEditorConfig(const std::string &fileNameForExtension) { std::map<std::string, std::string> eConfig = editorConfig->MapFromAbsolutePath(filePath); for (const std::pair<const std::string, std::string> &pss : eConfig) { try { if (pss.first == "indent_style") { const bool useTabs = pss.second == "tab"; propsDiscovered.Set("use.tabs", useTabs ? "1" : "0"); propsDiscovered.Set("use.tabs." + fileNameForExtension, useTabs ? "1" : "0"); wEditor.SetUseTabs(useTabs); } else if (pss.first == "indent_size") { std::string sIndentSize = pss.second; if (sIndentSize == "tab") { sIndentSize = props.GetExpandedString("tabsize"); if (sIndentSize.empty()) { sIndentSize = "8"; } } propsDiscovered.Set("indent.size", sIndentSize); propsDiscovered.Set("indent.size." + fileNameForExtension, sIndentSize); wEditor.SetIndent(std::stoi(sIndentSize)); } else if (pss.first == "tab_width") { propsDiscovered.Set("tabsize", pss.second); propsDiscovered.Set("tab.size." + fileNameForExtension, pss.second); wEditor.SetTabWidth(std::stoi(pss.second)); } else if (pss.first == "end_of_line") { if (pss.second == "lf") { propsDiscovered.Set("eol.mode", "LF"); wEditor.SetEOLMode(SA::EndOfLine::Lf); } else if (pss.second == "cr") { propsDiscovered.Set("eol.mode", "CR"); wEditor.SetEOLMode(SA::EndOfLine::Cr); } else if (pss.second == "crlf") { propsDiscovered.Set("eol.mode", "CRLF"); wEditor.SetEOLMode(SA::EndOfLine::CrLf); } } else if (pss.first == "charset") { if (pss.second == "latin1") { CurrentBuffer()->unicodeMode = UniMode::uni8Bit; codePage = 0; } else { if (pss.second == "utf-8") CurrentBuffer()->unicodeMode = UniMode::cookie; if (pss.second == "utf-8-bom") CurrentBuffer()->unicodeMode = UniMode::utf8; if (pss.second == "utf-16be") CurrentBuffer()->unicodeMode = UniMode::uni16BE; if (pss.second == "utf-16le") CurrentBuffer()->unicodeMode = UniMode::uni16LE; codePage = SA::CpUtf8; } wEditor.SetCodePage(codePage); } else if (pss.first == "trim_trailing_whitespace") { stripTrailingSpaces = pss.second == "true"; } else if (pss.first == "insert_final_newline") { ensureFinalLineEnd = pss.second == "true"; } } catch (std::invalid_argument &) { std::string diagnostic = "Invalid argument in .editorconfig '"; diagnostic += pss.first; diagnostic += "="; diagnostic += pss.second; diagnostic += "'.\n"; OutputAppendString(diagnostic.c_str()); SetOutputVisibility(true); } } } namespace { // Scintillua's style numbers are not constant, so ask it for names of styles and create a // mapping of style numbers to more constant style definitions. // For example, if Scintillua reports for the cpp lexer that style number 2 is a 'comment', // create the property: // style.scintillua.cpp.2=$(scintillua.styles.comment) // That way the user can define 'scintillua.styles.comment' once and it will be used for whatever // the style number for comments is in any given lexer. // Similarly, if Scintillua reports for the lua lexer that style number 20 is 'string.longstring', // create the property: // style.scintillua.lua.20=$(scintillua.styles.string),$(scintillua.styles.string.longstring) void SetScintilluaStyles(GUI::ScintillaWindow &wEditor, PropSetFile& props, const char *languageName) { const auto setStyle = [&wEditor, &props, &languageName](int style) { std::string finalPropStr; const std::string &name = wEditor.NameOfStyle(style); size_t end = -1; do { end = name.find('.', ++end); char propStr[128] = ""; sprintf(propStr, "$(scintillua.styles.%s),", end == std::string::npos ? name.c_str() : name.substr(0, end).c_str()); finalPropStr += propStr; } while (end != std::string::npos); char key[256] = ""; sprintf(key, "style.%s.%0d", languageName, style); props.Set(key, finalPropStr.c_str()); }; const int namedStyles = wEditor.NamedStyles(); // this count includes predefined styles constexpr int LastPredefined = static_cast<int>(Scintilla::StylesCommon::LastPredefined); constexpr int numPredefined = LastPredefined - StyleDefault + 1; for (int i = 0; i < std::min(namedStyles - numPredefined, StyleDefault); i++) { setStyle(i); } for (int i = StyleDefault; i <= LastPredefined; i++) { setStyle(i); } for (int i = LastPredefined + 1; i < namedStyles; i++) { setStyle(i); } } } void SciTEBase::ReadFontProperties() { const std::string monospaceFonts = props.GetExpandedString("font.monospaced.list"); monospacedList = StringSplit(monospaceFonts, ';'); char key[200] = ""; const char *languageName = language.c_str(); if (StartsWith(languageName, "scintillua.") && language.length() < 240) { SetScintilluaStyles(wEditor, props, languageName); } // Set styles // For each window set the global default style, then the language default style, then the other global styles, then the other language styles const SA::FontQuality fontQuality = static_cast<SA::FontQuality>(props.GetInt("font.quality")); wEditor.SetFontQuality(fontQuality); wOutput.SetFontQuality(fontQuality); wEditor.StyleResetDefault(); wOutput.StyleResetDefault(); std::string fontLocale = props.GetExpandedString("font.locale"); if (!fontLocale.empty()) { wEditor.SetFontLocale(fontLocale.c_str()); wOutput.SetFontLocale(fontLocale.c_str()); } sprintf(key, "style.%s.%0d", "*", StyleDefault); std::string sval = props.GetNewExpandString(key); SetOneStyle(wEditor, StyleDefault, StyleDefinition(sval)); SetOneStyle(wOutput, StyleDefault, StyleDefinition(sval)); sprintf(key, "style.%s.%0d", languageName, StyleDefault); sval = props.GetNewExpandString(key); SetOneStyle(wEditor, StyleDefault, StyleDefinition(sval)); wEditor.StyleClearAll(); SetStyleFor(wEditor, "*"); SetStyleFor(wEditor, languageName); if (props.GetInt("error.inline")) { wEditor.ReleaseAllExtendedStyles(); diagnosticStyleStart = wEditor.AllocateExtendedStyles(diagnosticStyles); SetStyleBlock(wEditor, "error", diagnosticStyleStart, diagnosticStyleStart+diagnosticStyles-1); } const int diffToSecondary = static_cast<int>(wEditor.DistanceToSecondaryStyles()); for (const unsigned char subStyleBase : subStyleBases) { const int subStylesStart = wEditor.SubStylesStart(subStyleBase); const int subStylesLength = wEditor.SubStylesLength(subStyleBase); for (int subStyle=0; subStyle<subStylesLength; subStyle++) { for (int active=0; active<(diffToSecondary?2:1); active++) { const int activity = active * diffToSecondary; sprintf(key, "style.%s.%0d.%0d", languageName, subStyleBase + activity, subStyle+1); sval = props.GetNewExpandString(key); SetOneStyle(wEditor, subStylesStart + subStyle + activity, StyleDefinition(sval)); } } } // Turn grey while loading if (CurrentBuffer()->lifeState == Buffer::LifeState::reading) wEditor.StyleSetBack(StyleDefault, 0xEEEEEE); wOutput.StyleClearAll(); sprintf(key, "style.%s.%0d", "errorlist", StyleDefault); sval = props.GetNewExpandString(key); SetOneStyle(wOutput, StyleDefault, StyleDefinition(sval)); wOutput.StyleClearAll(); SetStyleFor(wOutput, "*"); SetStyleFor(wOutput, "errorlist"); if (CurrentBuffer()->useMonoFont) { sval = props.GetExpandedString("font.monospace"); StyleDefinition sd(sval.c_str()); for (int style = 0; style <= StyleMax; style++) { if (style != static_cast<int>(SA::StylesCommon::LineNumber)) { if (sd.specified & StyleDefinition::sdFont) { wEditor.StyleSetFont(style, sd.font.c_str()); } if (sd.specified & StyleDefinition::sdSize) { wEditor.StyleSetSizeFractional(style, sd.FractionalSize()); } } } } } // Properties that are interactively modifiable are only read from the properties file once. void SciTEBase::SetPropertiesInitial() { splitVertical = props.GetInt("split.vertical"); openFilesHere = props.GetInt("check.if.already.open"); wrap = props.GetInt("wrap"); wrapOutput = props.GetInt("output.wrap"); indentationWSVisible = props.GetInt("view.indentation.whitespace", 1); sbVisible = props.GetInt("statusbar.visible"); tbVisible = props.GetInt("toolbar.visible"); tabVisible = props.GetInt("tabbar.visible"); tabMultiLine = props.GetInt("tabbar.multiline"); lineNumbers = props.GetInt("line.margin.visible"); margin = props.GetInt("margin.width"); foldMargin = props.GetInt("fold.margin.width", foldMarginWidthDefault); matchCase = props.GetInt("find.replace.matchcase"); regExp = props.GetInt("find.replace.regexp"); unSlash = props.GetInt("find.replace.escapes"); wrapFind = props.GetInt("find.replace.wrap", 1); focusOnReplace = props.GetInt("find.replacewith.focus", 1); } GUI::gui_string Localization::Text(std::string_view sv, bool retainIfNotFound) const { const std::string sEllipse("..."); // An ASCII ellipse const std::string utfEllipse("\xe2\x80\xa6"); // A UTF-8 ellipse std::string translation(sv); const int ellipseIndicator = Remove(translation, sEllipse); const int utfEllipseIndicator = Remove(translation, utfEllipse); const std::string menuAccessIndicatorChar(1, static_cast<char>(menuAccessIndicator[0])); const int accessKeyPresent = Remove(translation, menuAccessIndicatorChar); LowerCaseAZ(translation); Substitute(translation, "\n", "\\n"); translation = GetString(translation.c_str()); if (translation.length()) { if (ellipseIndicator) translation += sEllipse; if (utfEllipseIndicator) translation += utfEllipse; if (0 == accessKeyPresent) { #if !defined(GTK) // Following codes are required because accelerator is not always // part of alphabetical word in several language. In these cases, // accelerator is written like "(&O)". const size_t posOpenParenAnd = translation.find("(&"); if ((posOpenParenAnd != std::string::npos) && (translation.find(")", posOpenParenAnd) == posOpenParenAnd + 3)) { translation.erase(posOpenParenAnd, 4); } else { Remove(translation, std::string("&")); } #else Remove(translation, std::string("&")); #endif } Substitute(translation, "&", menuAccessIndicatorChar); Substitute(translation, "\\n", "\n"); } else { translation = missing; } if ((translation.length() > 0) || !retainIfNotFound) { return GUI::StringFromUTF8(translation); } return GUI::StringFromUTF8(std::string(sv)); } GUI::gui_string SciTEBase::LocaliseMessage(const char *s, const GUI::gui_char *param0, const GUI::gui_char *param1, const GUI::gui_char *param2) { GUI::gui_string translation = localiser.Text(s); if (param0) Substitute(translation, GUI_TEXT("^0"), param0); if (param1) Substitute(translation, GUI_TEXT("^1"), param1); if (param2) Substitute(translation, GUI_TEXT("^2"), param2); return translation; } void SciTEBase::ReadLocalization() { localiser.Clear(); GUI::gui_string title = GUI_TEXT("locale.properties"); const std::string localeProps = props.GetExpandedString("locale.properties"); if (localeProps.length()) { title = GUI::StringFromUTF8(localeProps); } FilePath propdir = GetSciteDefaultHome(); FilePath localePath(propdir, title); localiser.Read(localePath, propdir, filter, &importFiles, 0); localiser.SetMissing(props.GetString("translation.missing")); localiser.read = true; } void SciTEBase::ReadPropertiesInitial() { SetPropertiesInitial(); const int sizeHorizontal = props.GetInt("output.horizontal.size", 0); const int sizeVertical = props.GetInt("output.vertical.size", 0); const int hideOutput = props.GetInt("output.initial.hide", 0); if ((!splitVertical && (sizeVertical > 0) && (heightOutput < sizeVertical)) || (splitVertical && (sizeHorizontal > 0) && (heightOutput < sizeHorizontal))) { previousHeightOutput = splitVertical ? sizeHorizontal : sizeVertical; if (!hideOutput) { heightOutput = NormaliseSplit(previousHeightOutput); SizeSubWindows(); Redraw(); } } ViewWhitespace(props.GetInt("view.whitespace")); wEditor.SetIndentationGuides(props.GetInt("view.indentation.guides") ? indentExamine : SA::IndentView::None); wEditor.SetViewEOL(props.GetInt("view.eol")); wEditor.SetZoom(props.GetInt("magnification")); wOutput.SetZoom(props.GetInt("output.magnification")); wEditor.SetWrapMode(wrap ? wrapStyle : SA::Wrap::None); wOutput.SetWrapMode(wrapOutput ? wrapStyle : SA::Wrap::None); std::string menuLanguageProp = props.GetExpandedString("menu.language"); std::replace(menuLanguageProp.begin(), menuLanguageProp.end(), '|', '\0'); const char *sMenuLanguage = menuLanguageProp.c_str(); while (*sMenuLanguage) { LanguageMenuItem lmi; lmi.menuItem = sMenuLanguage; sMenuLanguage += strlen(sMenuLanguage) + 1; lmi.extension = sMenuLanguage; sMenuLanguage += strlen(sMenuLanguage) + 1; lmi.menuKey = sMenuLanguage; sMenuLanguage += strlen(sMenuLanguage) + 1; languageMenu.push_back(lmi); } SetLanguageMenu(); // load the user defined short cut props std::string shortCutProp = props.GetNewExpandString("user.shortcuts"); if (shortCutProp.length()) { const size_t pipes = std::count(shortCutProp.begin(), shortCutProp.end(), '|'); std::replace(shortCutProp.begin(), shortCutProp.end(), '|', '\0'); const char *sShortCutProp = shortCutProp.c_str(); for (size_t item = 0; item < pipes/2; item++) { ShortcutItem sci; sci.menuKey = sShortCutProp; sShortCutProp += strlen(sShortCutProp) + 1; sci.menuCommand = sShortCutProp; sShortCutProp += strlen(sShortCutProp) + 1; shortCutItemList.push_back(sci); } } // end load the user defined short cut props props.SetPath("SciteDefaultHome", GetSciteDefaultHome()); props.SetPath("SciteUserHome", GetSciteUserHome()); } FilePath SciTEBase::GetDefaultPropertiesFileName() { return FilePath(GetSciteDefaultHome(), propGlobalFileName); } FilePath SciTEBase::GetAbbrevPropertiesFileName() { return FilePath(GetSciteUserHome(), propAbbrevFileName); } FilePath SciTEBase::GetUserPropertiesFileName() { return FilePath(GetSciteUserHome(), propUserFileName); } FilePath SciTEBase::GetLocalPropertiesFileName() { return FilePath(filePath.Directory(), propLocalFileName); } FilePath SciTEBase::GetDirectoryPropertiesFileName() { FilePath propfile; if (filePath.IsSet()) { propfile.Set(filePath.Directory(), propDirectoryFileName); // if this file does not exist try to find the prop file in a parent directory while (!propfile.Directory().IsRoot() && !propfile.Exists()) { propfile.Set(propfile.Directory().Directory(), propDirectoryFileName); } // not found -> set it to the initial directory if (!propfile.Exists()) { propfile.Set(filePath.Directory(), propDirectoryFileName); } } return propfile; } void SciTEBase::OpenProperties(int propsFile) { FilePath propfile; switch (propsFile) { case IDM_OPENLOCALPROPERTIES: propfile = GetLocalPropertiesFileName(); Open(propfile, ofQuiet); break; case IDM_OPENUSERPROPERTIES: propfile = GetUserPropertiesFileName(); Open(propfile, ofQuiet); break; case IDM_OPENABBREVPROPERTIES: propfile = pathAbbreviations; Open(propfile, ofQuiet); break; case IDM_OPENGLOBALPROPERTIES: propfile = GetDefaultPropertiesFileName(); Open(propfile, ofQuiet); break; case IDM_OPENLUAEXTERNALFILE: { GUI::gui_string extlua = GUI::StringFromUTF8(props.GetExpandedString("ext.lua.startup.script")); if (extlua.length()) { Open(extlua, ofQuiet); } break; } case IDM_OPENDIRECTORYPROPERTIES: { propfile = GetDirectoryPropertiesFileName(); const bool alreadyExists = propfile.Exists(); Open(propfile, ofQuiet); if (!alreadyExists) SaveAsDialog(); } break; } } // return the int value of the command name passed in. int SciTEBase::GetMenuCommandAsInt(const std::string &commandName) { int i = IFaceTable::FindConstant(commandName.c_str()); if (i != -1) { return IFaceTable::constants[i].value; } // Check also for a SCI command, as long as it has no parameters i = IFaceTable::FindFunctionByConstantName(commandName.c_str()); if (i != -1 && IFaceTable::functions[i].paramType[0] == iface_void && IFaceTable::functions[i].paramType[1] == iface_void) { return IFaceTable::functions[i].value; } // Otherwise we might have entered a number as command to access a "SCI_" command return atoi(commandName.c_str()); }