Branch: refs/heads/master Author: Thomas Martitz thomas.martitz@mailbox.org Committer: Thomas Martitz thomas.martitz@mailbox.org Date: Mon, 15 Nov 2021 06:46:40 UTC Commit: 6d109b309165ff0bfb17a2b21056bd498d54c032 https://github.com/geany/geany/commit/6d109b309165ff0bfb17a2b21056bd498d54c0...
Log Message: ----------- Update to Scintilla 5.1.3 and Lexilla 5.1.2
Notable changes: Scintilla: - Add SC_ELEMENT_FOLD_LINE to set the colour of fold lines. Add SC_ELEMENT_HIDDEN_LINE to show where lines are hidden. - On GTK, fix the line spacing so that underscores and accents are visible for some fonts such as DejaVu Sans Mono 10.
Lexilla - Implement conditional group rules in CSS. Issue #25, Pull request #28. - Check PHP numeric literals, showing invalid values with default style instead of numeric. Issue #20.
The CSS change causes compatiblity trouble. We exposed the changed style in filetypes.css. Users must update local copies.
Modified Paths: -------------- data/filedefs/filetypes.css scintilla/gtk/PlatGTK.cxx scintilla/gtk/ScintillaGTK.cxx scintilla/gtk/ScintillaGTK.h scintilla/gtk/ScintillaGTKAccessible.cxx scintilla/include/Scintilla.h scintilla/include/Scintilla.iface scintilla/include/ScintillaCall.h scintilla/include/ScintillaMessages.h scintilla/include/ScintillaTypes.h scintilla/lexilla/include/SciLexer.h scintilla/lexilla/lexers/LexCSS.cxx scintilla/lexilla/lexers/LexHTML.cxx scintilla/lexilla/lexers/LexMarkdown.cxx scintilla/lexilla/lexlib/WordList.cxx scintilla/lexilla/lexlib/WordList.h scintilla/lexilla/version.txt scintilla/src/AutoComplete.cxx scintilla/src/AutoComplete.h scintilla/src/CallTip.cxx scintilla/src/CallTip.h scintilla/src/CaseConvert.cxx scintilla/src/CaseFolder.cxx scintilla/src/CaseFolder.h scintilla/src/CellBuffer.cxx scintilla/src/ContractionState.cxx scintilla/src/Decoration.cxx scintilla/src/Document.cxx scintilla/src/Document.h scintilla/src/EditModel.cxx scintilla/src/EditModel.h scintilla/src/EditView.cxx scintilla/src/Editor.cxx scintilla/src/Editor.h scintilla/src/Geometry.cxx scintilla/src/Geometry.h scintilla/src/Indicator.cxx scintilla/src/KeyMap.cxx scintilla/src/KeyMap.h scintilla/src/LineMarker.cxx scintilla/src/MarginView.cxx scintilla/src/MarginView.h scintilla/src/PositionCache.cxx scintilla/src/PositionCache.h scintilla/src/RESearch.cxx scintilla/src/RESearch.h scintilla/src/ScintillaBase.cxx scintilla/src/Selection.cxx scintilla/src/Selection.h scintilla/src/Style.cxx scintilla/src/Style.h scintilla/src/UniConversion.h scintilla/src/UniqueString.cxx scintilla/src/UniqueString.h scintilla/src/ViewStyle.cxx scintilla/src/ViewStyle.h scintilla/version.txt src/highlightingmappings.h
Modified: data/filedefs/filetypes.css 2 lines changed, 1 insertions(+), 1 deletions(-) =================================================================== @@ -24,7 +24,7 @@ pseudoelement=string_2 extended_identifier=keyword_1 extended_pseudoclass=string_1 extended_pseudoelement=string_2 -media=parameter +group_rule=parameter
[keywords] # CSS 1 properties
Modified: scintilla/gtk/PlatGTK.cxx 4 lines changed, 2 insertions(+), 2 deletions(-) =================================================================== @@ -1073,7 +1073,7 @@ XYPOSITION SurfaceImpl::Ascent(const Font *font_) { if (PFont(font_)->pfd) { PangoFontMetrics *metrics = pango_context_get_metrics(pcontext, PFont(font_)->pfd, pango_context_get_language(pcontext)); - ascent = std::round(floatFromPangoUnits( + ascent = std::ceil(floatFromPangoUnits( pango_font_metrics_get_ascent(metrics))); pango_font_metrics_unref(metrics); } @@ -1087,7 +1087,7 @@ XYPOSITION SurfaceImpl::Descent(const Font *font_) { if (PFont(font_)->pfd) { PangoFontMetrics *metrics = pango_context_get_metrics(pcontext, PFont(font_)->pfd, pango_context_get_language(pcontext)); - const XYPOSITION descent = std::round(floatFromPangoUnits( + const XYPOSITION descent = std::ceil(floatFromPangoUnits( pango_font_metrics_get_descent(metrics))); pango_font_metrics_unref(metrics); return descent;
Modified: scintilla/gtk/ScintillaGTK.cxx 50 lines changed, 38 insertions(+), 12 deletions(-) =================================================================== @@ -5,6 +5,7 @@
#include <cstddef> #include <cstdlib> +#include <cstdint> #include <cassert> #include <cstring> #include <cstdio> @@ -179,6 +180,18 @@ GdkAtom SelectionOfGSD(GtkSelectionData *sd) noexcept { return gtk_selection_data_get_selection(sd); }
+bool SettingGet(GtkSettings *settings, const gchar *name, gpointer value) noexcept { + if (!settings) { + return false; + } + if (!g_object_class_find_property(G_OBJECT_GET_CLASS( + G_OBJECT(settings)), name)) { + return false; + } + g_object_get(G_OBJECT(settings), name, value, nullptr); + return true; +} + }
FontOptions::FontOptions(GtkWidget *widget) noexcept { @@ -218,6 +231,8 @@ ScintillaGTK::ScintillaGTK(_ScintillaObject *sci_) : preeditInitialized(false), im_context(nullptr), lastNonCommonScript(G_UNICODE_SCRIPT_INVALID_CODE), + settings(nullptr), + settingsHandlerId(0), lastWheelMouseTime(0), lastWheelMouseDirection(0), wheelMouseIntensity(0), @@ -264,6 +279,12 @@ ScintillaGTK::~ScintillaGTK() { } ClearPrimarySelection(); wPreedit.Destroy(); + if (settingsHandlerId) { + g_signal_handler_disconnect(settings, settingsHandlerId); + } + if (settings) { + g_object_unref(settings); + } }
void ScintillaGTK::RealizeThis(GtkWidget *widget) { @@ -341,6 +362,15 @@ void ScintillaGTK::RealizeThis(GtkWidget *widget) { cursor = gdk_cursor_new_for_display(pdisplay, GDK_LEFT_PTR); gdk_window_set_cursor(PWindow(scrollbarh), cursor); UnRefCursor(cursor); + + using NotifyLambda = void (*)(GObject *, GParamSpec *, ScintillaGTK *); + if (settings) { + settingsHandlerId = g_signal_connect(settings, "notify::gtk-xft-dpi", + G_CALLBACK(static_cast<NotifyLambda>([](GObject *, GParamSpec *, ScintillaGTK *sciThis) { + sciThis->InvalidateStyleRedraw(); + })), + this); + } }
void ScintillaGTK::Realize(GtkWidget *widget) { @@ -669,20 +699,16 @@ void ScintillaGTK::Init() { gtk_container_add(GTK_CONTAINER(PWidget(wPreedit)), predrw); gtk_widget_show(predrw);
+ settings = gtk_settings_get_default(); + // Set caret period based on GTK settings gboolean blinkOn = false; - if (g_object_class_find_property(G_OBJECT_GET_CLASS( - G_OBJECT(gtk_settings_get_default())), "gtk-cursor-blink")) { - g_object_get(G_OBJECT( - gtk_settings_get_default()), "gtk-cursor-blink", &blinkOn, nullptr); - } - if (blinkOn && - g_object_class_find_property(G_OBJECT_GET_CLASS( - G_OBJECT(gtk_settings_get_default())), "gtk-cursor-blink-time")) { - gint value; - g_object_get(G_OBJECT( - gtk_settings_get_default()), "gtk-cursor-blink-time", &value, nullptr); - caret.period = static_cast<int>(value / 1.75); + SettingGet(settings, "gtk-cursor-blink", &blinkOn); + if (blinkOn) { + gint value = 500; + if (SettingGet(settings, "gtk-cursor-blink-time", &value)) { + caret.period = static_cast<int>(value / 1.75); + } } else { caret.period = 0; }
Modified: scintilla/gtk/ScintillaGTK.h 3 lines changed, 3 insertions(+), 0 deletions(-) =================================================================== @@ -62,6 +62,9 @@ class ScintillaGTK : public ScintillaBase { GtkIMContext *im_context; GUnicodeScript lastNonCommonScript;
+ GtkSettings *settings; + gulong settingsHandlerId; + // Wheel mouse support unsigned int linesPerScroll; gint64 lastWheelMouseTime;
Modified: scintilla/gtk/ScintillaGTKAccessible.cxx 1 lines changed, 1 insertions(+), 0 deletions(-) =================================================================== @@ -53,6 +53,7 @@
#include <cstddef> #include <cstdlib> +#include <cstdint> #include <cassert> #include <cstring>
Modified: scintilla/include/Scintilla.h 6 lines changed, 6 insertions(+), 0 deletions(-) =================================================================== @@ -272,6 +272,8 @@ typedef sptr_t (*SciFnDirectStatus)(sptr_t ptr, unsigned int iMessage, uptr_t wP #define SCI_STYLEGETWEIGHT 2064 #define SCI_STYLESETCHARACTERSET 2066 #define SCI_STYLESETHOTSPOT 2409 +#define SCI_STYLESETCHECKMONOSPACED 2254 +#define SCI_STYLEGETCHECKMONOSPACED 2255 #define SC_ELEMENT_LIST 0 #define SC_ELEMENT_LIST_BACK 1 #define SC_ELEMENT_LIST_SELECTED 2 @@ -291,6 +293,8 @@ typedef sptr_t (*SciFnDirectStatus)(sptr_t ptr, unsigned int iMessage, uptr_t wP #define SC_ELEMENT_WHITE_SPACE_BACK 61 #define SC_ELEMENT_HOT_SPOT_ACTIVE 70 #define SC_ELEMENT_HOT_SPOT_ACTIVE_BACK 71 +#define SC_ELEMENT_FOLD_LINE 80 +#define SC_ELEMENT_HIDDEN_LINE 81 #define SCI_SETELEMENTCOLOUR 2753 #define SCI_GETELEMENTCOLOUR 2754 #define SCI_RESETELEMENTCOLOUR 2755 @@ -310,6 +314,8 @@ typedef sptr_t (*SciFnDirectStatus)(sptr_t ptr, unsigned int iMessage, uptr_t wP #define SCI_SETSELECTIONLAYER 2763 #define SCI_GETCARETLINELAYER 2764 #define SCI_SETCARETLINELAYER 2765 +#define SCI_GETCARETLINEHIGHLIGHTSUBLINE 2773 +#define SCI_SETCARETLINEHIGHLIGHTSUBLINE 2774 #define SCI_SETCARETFORE 2069 #define SCI_ASSIGNCMDKEY 2070 #define SCI_CLEARCMDKEY 2071
Modified: scintilla/include/Scintilla.iface 14 lines changed, 14 insertions(+), 0 deletions(-) =================================================================== @@ -677,6 +677,12 @@ set void StyleSetCharacterSet=2066(int style, CharacterSet characterSet) # Set a style to be a hotspot or not. set void StyleSetHotSpot=2409(int style, bool hotspot)
+# Indicate that a style may be monospaced over ASCII graphics characters which enables optimizations. +set void StyleSetCheckMonospaced=2254(int style, bool checkMonospaced) + +# Get whether a style may be monospaced. +get bool StyleGetCheckMonospaced=2255(int style,) + enu Element=SC_ELEMENT_ val SC_ELEMENT_LIST=0 val SC_ELEMENT_LIST_BACK=1 @@ -697,6 +703,8 @@ val SC_ELEMENT_WHITE_SPACE=60 val SC_ELEMENT_WHITE_SPACE_BACK=61 val SC_ELEMENT_HOT_SPOT_ACTIVE=70 val SC_ELEMENT_HOT_SPOT_ACTIVE_BACK=71 +val SC_ELEMENT_FOLD_LINE=80 +val SC_ELEMENT_HIDDEN_LINE=81
# Set the colour of an element. Translucency (alpha) may or may not be significant # and this may depend on the platform. The alpha byte should commonly be 0xff for opaque. @@ -753,6 +761,12 @@ get Layer GetCaretLineLayer=2764(,) # Set the layer of the background of the line containing the caret. set void SetCaretLineLayer=2765(Layer layer,)
+# Get only highlighting subline instead of whole line. +get bool GetCaretLineHighlightSubLine=2773(,) + +# Set only highlighting subline instead of whole line. +set void SetCaretLineHighlightSubLine=2774(bool subLine,) + # Set the foreground colour of the caret. set void SetCaretFore=2069(colour fore,)
Modified: scintilla/include/ScintillaCall.h 4 lines changed, 4 insertions(+), 0 deletions(-) =================================================================== @@ -196,6 +196,8 @@ class ScintillaCall { Scintilla::FontWeight StyleGetWeight(int style); void StyleSetCharacterSet(int style, Scintilla::CharacterSet characterSet); void StyleSetHotSpot(int style, bool hotspot); + void StyleSetCheckMonospaced(int style, bool checkMonospaced); + bool StyleGetCheckMonospaced(int style); void SetElementColour(Scintilla::Element element, ColourAlpha colourElement); ColourAlpha ElementColour(Scintilla::Element element); void ResetElementColour(Scintilla::Element element); @@ -212,6 +214,8 @@ class ScintillaCall { void SetSelectionLayer(Scintilla::Layer layer); Scintilla::Layer CaretLineLayer(); void SetCaretLineLayer(Scintilla::Layer layer); + bool CaretLineHighlightSubLine(); + void SetCaretLineHighlightSubLine(bool subLine); void SetCaretFore(Colour fore); void AssignCmdKey(int keyDefinition, int sciCommand); void ClearCmdKey(int keyDefinition);
Modified: scintilla/include/ScintillaMessages.h 4 lines changed, 4 insertions(+), 0 deletions(-) =================================================================== @@ -133,6 +133,8 @@ enum class Message { StyleGetWeight = 2064, StyleSetCharacterSet = 2066, StyleSetHotSpot = 2409, + StyleSetCheckMonospaced = 2254, + StyleGetCheckMonospaced = 2255, SetElementColour = 2753, GetElementColour = 2754, ResetElementColour = 2755, @@ -149,6 +151,8 @@ enum class Message { SetSelectionLayer = 2763, GetCaretLineLayer = 2764, SetCaretLineLayer = 2765, + GetCaretLineHighlightSubLine = 2773, + SetCaretLineHighlightSubLine = 2774, SetCaretFore = 2069, AssignCmdKey = 2070, ClearCmdKey = 2071,
Modified: scintilla/include/ScintillaTypes.h 2 lines changed, 2 insertions(+), 0 deletions(-) =================================================================== @@ -180,6 +180,8 @@ enum class Element { WhiteSpaceBack = 61, HotSpotActive = 70, HotSpotActiveBack = 71, + FoldLine = 80, + HiddenLine = 81, };
enum class Layer {
Modified: scintilla/lexilla/include/SciLexer.h 2 lines changed, 1 insertions(+), 1 deletions(-) =================================================================== @@ -765,7 +765,7 @@ #define SCE_CSS_EXTENDED_IDENTIFIER 19 #define SCE_CSS_EXTENDED_PSEUDOCLASS 20 #define SCE_CSS_EXTENDED_PSEUDOELEMENT 21 -#define SCE_CSS_MEDIA 22 +#define SCE_CSS_GROUP_RULE 22 #define SCE_CSS_VARIABLE 23 #define SCE_POV_DEFAULT 0 #define SCE_POV_COMMENT 1
Modified: scintilla/lexilla/lexers/LexCSS.cxx 8 lines changed, 4 insertions(+), 4 deletions(-) =================================================================== @@ -209,7 +209,7 @@ static void ColouriseCssDoc(Sci_PositionU startPos, Sci_Position length, int ini case '{': nestingLevel++; switch (lastState) { - case SCE_CSS_MEDIA: + case SCE_CSS_GROUP_RULE: sc.SetState(SCE_CSS_DEFAULT); break; case SCE_CSS_TAG: @@ -458,8 +458,8 @@ static void ColouriseCssDoc(Sci_PositionU startPos, Sci_Position length, int ini sc.ChangeState(SCE_CSS_VALUE); break; case SCE_CSS_DIRECTIVE: - if (op == '@' && strcmp(s2, "media") == 0) - sc.ChangeState(SCE_CSS_MEDIA); + if (op == '@' && (strcmp(s2, "media") == 0 || strcmp(s2, "supports") == 0 || strcmp(s2, "document") == 0 || strcmp(s2, "-moz-document") == 0)) + sc.ChangeState(SCE_CSS_GROUP_RULE); break; } } @@ -492,7 +492,7 @@ static void ColouriseCssDoc(Sci_PositionU startPos, Sci_Position length, int ini } else if (IsCssOperator(sc.ch) && (sc.state != SCE_CSS_ATTRIBUTE || sc.ch == ']') && (sc.state != SCE_CSS_VALUE || sc.ch == ';' || sc.ch == '}' || sc.ch == '!') - && ((sc.state != SCE_CSS_DIRECTIVE && sc.state != SCE_CSS_MEDIA) || sc.ch == ';' || sc.ch == '{') + && ((sc.state != SCE_CSS_DIRECTIVE && sc.state != SCE_CSS_GROUP_RULE) || sc.ch == ';' || sc.ch == '{') ) { if (sc.state != SCE_CSS_OPERATOR) lastState = sc.state;
Modified: scintilla/lexilla/lexers/LexHTML.cxx 140 lines changed, 127 insertions(+), 13 deletions(-) =================================================================== @@ -524,6 +524,119 @@ bool isDjangoBlockEnd(const int ch, const int chNext, const std::string &blockTy } }
+class PhpNumberState { + enum NumberBase { BASE_10 = 0, BASE_2, BASE_8, BASE_16 }; + static constexpr const char *const digitList[] = { "_0123456789", "_01", "_01234567", "_0123456789abcdefABCDEF" }; + + NumberBase base = BASE_10; + bool decimalPart = false; + bool exponentPart = false; + bool invalid = false; + bool finished = false; + + bool leadingZero = false; + bool invalidBase8 = false; + + bool betweenDigits = false; + bool decimalChar = false; + bool exponentChar = false; + +public: + inline bool isInvalid() { return invalid; } + inline bool isFinished() { return finished; } + + bool init(int ch, int chPlus1, int chPlus2) { + base = BASE_10; + decimalPart = false; + exponentPart = false; + invalid = false; + finished = false; + + leadingZero = false; + invalidBase8 = false; + + betweenDigits = false; + decimalChar = false; + exponentChar = false; + + if (ch == '.' && strchr(digitList[BASE_10] + !betweenDigits, chPlus1) != nullptr) { + decimalPart = true; + betweenDigits = true; + } else if (ch == '0' && (chPlus1 == 'b' || chPlus1 == 'B')) { + base = BASE_2; + } else if (ch == '0' && (chPlus1 == 'o' || chPlus1 == 'O')) { + base = BASE_8; + } else if (ch == '0' && (chPlus1 == 'x' || chPlus1 == 'X')) { + base = BASE_16; + } else if (strchr(digitList[BASE_10] + !betweenDigits, ch) != nullptr) { + leadingZero = ch == '0'; + betweenDigits = true; + check(chPlus1, chPlus2); + if (finished && leadingZero) { + // single zero should be base 10 + base = BASE_10; + } + } else { + return false; + } + return true; + } + + bool check(int ch, int chPlus1) { + if (strchr(digitList[base] + !betweenDigits, ch) != nullptr) { + if (leadingZero) { + invalidBase8 = invalidBase8 || strchr(digitList[BASE_8] + !betweenDigits, ch) == nullptr; + } + + betweenDigits = ch != '_'; + decimalChar = false; + exponentChar = false; + } else if (ch == '_') { + invalid = true; + + betweenDigits = false; + decimalChar = false; + // exponentChar is unchanged + } else if (base == BASE_10 && ch == '.' && ( + !(decimalPart || exponentPart) || strchr(digitList[BASE_10] + !betweenDigits, chPlus1) != nullptr) + ) { + invalid = invalid || !betweenDigits || decimalPart || exponentPart; + decimalPart = true; + + betweenDigits = false; + decimalChar = true; + exponentChar = false; + } else if (base == BASE_10 && (ch == 'e' || ch == 'E')) { + invalid = invalid || !(betweenDigits || decimalChar) || exponentPart; + exponentPart = true; + + betweenDigits = false; + decimalChar = false; + exponentChar = true; + } else if (base == BASE_10 && (ch == '-' || ch == '+') && exponentChar) { + invalid = invalid || strchr(digitList[BASE_10] + !betweenDigits, chPlus1) == nullptr; + + betweenDigits = false; + decimalChar = false; + // exponentChar is unchanged + } else if (IsPhpWordChar(ch)) { + invalid = true; + + betweenDigits = false; + decimalChar = false; + exponentChar = false; + } else { + invalid = invalid || !(betweenDigits || decimalChar); + finished = true; + if (base == BASE_10 && leadingZero && !decimalPart && !exponentPart) { + base = BASE_8; + invalid = invalid || invalidBase8; + } + } + return finished; + } +}; + bool isPHPStringState(int state) { return (state == SCE_HPHP_HSTRING) || @@ -960,6 +1073,7 @@ void SCI_METHOD LexerHTML::Lex(Sci_PositionU startPos, Sci_Position length, int } styler.StartAt(startPos); std::string prevWord; + PhpNumberState phpNumber; std::string phpStringDelimiter; int StateToPrint = initStyle; int state = stateForPrintState(StateToPrint); @@ -1254,7 +1368,7 @@ void SCI_METHOD LexerHTML::Lex(Sci_PositionU startPos, Sci_Position length, int ///////////////////////////////////// // handle the start of PHP pre-processor = Non-HTML else if ((state != SCE_H_ASPAT) && - !isStringState(state) && + !isPHPStringState(state) && (state != SCE_HPHP_COMMENT) && (state != SCE_HPHP_COMMENTLINE) && (ch == '<') && @@ -1430,6 +1544,7 @@ void SCI_METHOD LexerHTML::Lex(Sci_PositionU startPos, Sci_Position length, int (chPrev == '<') && (ch == '!') && (StateToPrint != SCE_H_CDATA) && + (!isStringState(StateToPrint)) && (!IsCommentState(StateToPrint)) && (!IsScriptCommentState(StateToPrint))) { beforePreProc = state; @@ -2273,7 +2388,7 @@ void SCI_METHOD LexerHTML::Lex(Sci_PositionU startPos, Sci_Position length, int break; ///////////// start - PHP state handling case SCE_HPHP_WORD: - if (!IsAWordChar(ch)) { + if (!IsPhpWordChar(ch)) { classifyWordHTPHP(styler.GetStartSegment(), i - 1, keywords5, styler); if (ch == '/' && chNext == '*') { i++; @@ -2306,15 +2421,9 @@ void SCI_METHOD LexerHTML::Lex(Sci_PositionU startPos, Sci_Position length, int } break; case SCE_HPHP_NUMBER: - // recognize bases 8,10 or 16 integers OR floating-point numbers - if (!IsADigit(ch) - && strchr(".xXabcdefABCDEF_", ch) == NULL - && ((ch != '-' && ch != '+') || (chPrev != 'e' && chPrev != 'E'))) { - styler.ColourTo(i - 1, SCE_HPHP_NUMBER); - if (IsOperator(ch)) - state = SCE_HPHP_OPERATOR; - else - state = SCE_HPHP_DEFAULT; + if (phpNumber.check(chNext, chNext2)) { + styler.ColourTo(i, phpNumber.isInvalid() ? SCE_HPHP_DEFAULT : SCE_HPHP_NUMBER); + state = SCE_HPHP_DEFAULT; } break; case SCE_HPHP_VARIABLE: @@ -2395,8 +2504,13 @@ void SCI_METHOD LexerHTML::Lex(Sci_PositionU startPos, Sci_Position length, int case SCE_HPHP_OPERATOR: case SCE_HPHP_DEFAULT: styler.ColourTo(i - 1, StateToPrint); - if (IsADigit(ch) || (ch == '.' && IsADigit(chNext))) { - state = SCE_HPHP_NUMBER; + if (phpNumber.init(ch, chNext, chNext2)) { + if (phpNumber.isFinished()) { + styler.ColourTo(i, phpNumber.isInvalid() ? SCE_HPHP_DEFAULT : SCE_HPHP_NUMBER); + state = SCE_HPHP_DEFAULT; + } else { + state = SCE_HPHP_NUMBER; + } } else if (IsAWordStart(ch)) { state = SCE_HPHP_WORD; } else if (ch == '/' && chNext == '*') {
Modified: scintilla/lexilla/lexers/LexMarkdown.cxx 9 lines changed, 7 insertions(+), 2 deletions(-) =================================================================== @@ -56,8 +56,13 @@
using namespace Lexilla;
-static inline bool IsNewline(const int ch) { - return (ch == '\n' || ch == '\r'); +namespace { + +constexpr bool IsNewline(const int ch) { + // sc.GetRelative(i) returns '\0' if out of range + return (ch == '\n' || ch == '\r' || ch == '\0'); +} + }
// True if can follow ch down to the end with possibly trailing whitespace
Modified: scintilla/lexilla/lexlib/WordList.cxx 85 lines changed, 34 insertions(+), 51 deletions(-) =================================================================== @@ -11,18 +11,20 @@
#include <algorithm> #include <iterator> +#include <memory>
#include "WordList.h"
using namespace Lexilla;
+namespace { + /** * Creates an array that points into each word in the string and puts \0 terminators * after each word. */ -static char **ArrayFromWordList(char *wordlist, size_t slen, int *len, bool onlyLineEnds = false) { - int prev = '\n'; - int words = 0; +std::unique_ptr<char *[]> ArrayFromWordList(char *wordlist, size_t slen, size_t *len, bool onlyLineEnds = false) { + size_t words = 0; // For rapid determination of whether a character is a separator, build // a look up table. bool wordSeparator[256] = {}; // Initialise all to false. @@ -32,26 +34,27 @@ static char **ArrayFromWordList(char *wordlist, size_t slen, int *len, bool only wordSeparator[static_cast<unsigned int>(' ')] = true; wordSeparator[static_cast<unsigned int>('\t')] = true; } + unsigned char prev = '\n'; for (int j = 0; wordlist[j]; j++) { - const int curr = static_cast<unsigned char>(wordlist[j]); + const unsigned char curr = wordlist[j]; if (!wordSeparator[curr] && wordSeparator[prev]) words++; prev = curr; } - char **keywords = new char *[words + 1]; - int wordsStore = 0; + std::unique_ptr<char *[]> keywords = std::make_unique<char *[]>(words + 1); + size_t wordsStore = 0; if (words) { - prev = '\0'; + unsigned char previous = '\0'; for (size_t k = 0; k < slen; k++) { if (!wordSeparator[static_cast<unsigned char>(wordlist[k])]) { - if (!prev) { + if (!previous) { keywords[wordsStore] = &wordlist[k]; wordsStore++; } } else { wordlist[k] = '\0'; } - prev = wordlist[k]; + previous = wordlist[k]; } } assert(wordsStore < (words + 1)); @@ -60,8 +63,14 @@ static char **ArrayFromWordList(char *wordlist, size_t slen, int *len, bool only return keywords; }
-WordList::WordList(bool onlyLineEnds_) : - words(0), list(0), len(0), onlyLineEnds(onlyLineEnds_) { +bool cmpWords(const char *a, const char *b) noexcept { + return strcmp(a, b) < 0; +} + +} + +WordList::WordList(bool onlyLineEnds_) noexcept : + words(nullptr), list(nullptr), len(0), onlyLineEnds(onlyLineEnds_) { // Prevent warnings by static analyzers about uninitialized starts. starts[0] = -1; } @@ -77,78 +86,52 @@ WordList::operator bool() const noexcept { bool WordList::operator!=(const WordList &other) const noexcept { if (len != other.len) return true; - for (int i=0; i<len; i++) { + for (size_t i=0; i<len; i++) { if (strcmp(words[i], other.words[i]) != 0) return true; } return false; }
int WordList::Length() const noexcept { - return len; + return static_cast<int>(len); }
void WordList::Clear() noexcept { - if (words) { - delete []list; - delete []words; - } - words = nullptr; + delete []list; list = nullptr; + delete []words; + words = nullptr; len = 0; }
-#ifdef _MSC_VER - -static bool cmpWords(const char *a, const char *b) { - return strcmp(a, b) < 0; -} - -#else - -static int cmpWords(const void *a, const void *b) { - return strcmp(*static_cast<const char * const *>(a), *static_cast<const char * const *>(b)); -} - -static void SortWordList(char **words, unsigned int len) { - qsort(words, len, sizeof(*words), cmpWords); -} - -#endif - bool WordList::Set(const char *s) { const size_t lenS = strlen(s) + 1; - char *listTemp = new char[lenS]; - memcpy(listTemp, s, lenS); - int lenTemp = 0; - char **wordsTemp = ArrayFromWordList(listTemp, lenS - 1, &lenTemp, onlyLineEnds); -#ifdef _MSC_VER - std::sort(wordsTemp, wordsTemp + lenTemp, cmpWords); -#else - SortWordList(wordsTemp, lenTemp); -#endif + std::unique_ptr<char[]> listTemp = std::make_unique<char[]>(lenS); + memcpy(listTemp.get(), s, lenS); + size_t lenTemp = 0; + std::unique_ptr<char *[]> wordsTemp = ArrayFromWordList(listTemp.get(), lenS - 1, &lenTemp, onlyLineEnds); + std::sort(wordsTemp.get(), wordsTemp.get() + lenTemp, cmpWords);
if (lenTemp == len) { bool changed = false; - for (int i = 0; i < lenTemp; i++) { + for (size_t i = 0; i < lenTemp; i++) { if (strcmp(words[i], wordsTemp[i]) != 0) { changed = true; break; } } if (!changed) { - delete []listTemp; - delete []wordsTemp; return false; } }
Clear(); - words = wordsTemp; - list = listTemp; + words = wordsTemp.release(); + list = listTemp.release(); len = lenTemp; std::fill(starts, std::end(starts), -1); - for (int l = len - 1; l >= 0; l--) { + for (int l = static_cast<int>(len - 1); l >= 0; l--) { unsigned char indexChar = words[l][0]; starts[indexChar] = l; }
Modified: scintilla/lexilla/lexlib/WordList.h 9 lines changed, 7 insertions(+), 2 deletions(-) =================================================================== @@ -16,11 +16,16 @@ class WordList { // Each word contains at least one character - a empty word acts as sentinel at the end. char **words; char *list; - int len; + size_t len; bool onlyLineEnds; ///< Delimited by any white space or only line ends int starts[256]; public: - explicit WordList(bool onlyLineEnds_ = false); + explicit WordList(bool onlyLineEnds_ = false) noexcept; + // Deleted so WordList objects can not be copied. + WordList(const WordList &) = delete; + WordList(WordList &&) = delete; + WordList &operator=(const WordList &) = delete; + WordList &operator=(WordList &&) = delete; ~WordList(); operator bool() const noexcept; bool operator!=(const WordList &other) const noexcept;
Modified: scintilla/lexilla/version.txt 2 lines changed, 1 insertions(+), 1 deletions(-) =================================================================== @@ -1 +1 @@ -511 +512
Modified: scintilla/src/AutoComplete.cxx 4 lines changed, 2 insertions(+), 2 deletions(-) =================================================================== @@ -211,7 +211,7 @@ void AutoComplete::Show(bool show) { lb->Select(0); }
-void AutoComplete::Cancel() { +void AutoComplete::Cancel() noexcept { if (lb->Created()) { lb->Clear(); lb->Destroy(); @@ -272,7 +272,7 @@ void AutoComplete::Select(const char *word) { } } else if (cond < 0) { end = pivot - 1; - } else if (cond > 0) { + } else { // cond > 0 start = pivot + 1; } }
Modified: scintilla/src/AutoComplete.h 7 lines changed, 6 insertions(+), 1 deletions(-) =================================================================== @@ -43,6 +43,11 @@ class AutoComplete { Scintilla::Ordering autoSort;
AutoComplete(); + // Deleted so AutoComplete objects can not be copied. + AutoComplete(const AutoComplete &) = delete; + AutoComplete(AutoComplete &&) = delete; + AutoComplete &operator=(const AutoComplete &) = delete; + AutoComplete &operator=(AutoComplete &&) = delete; ~AutoComplete();
/// Is the auto completion list displayed? @@ -79,7 +84,7 @@ class AutoComplete { std::string GetValue(int item) const;
void Show(bool show); - void Cancel(); + void Cancel() noexcept;
/// Move the current list element by delta, scrolling appropriately void Move(int delta);
Modified: scintilla/src/CallTip.cxx 4 lines changed, 2 insertions(+), 2 deletions(-) =================================================================== @@ -313,7 +313,7 @@ PRectangle CallTip::CallTipStart(Sci::Position pos, Point pt, int textHeight, co } }
-void CallTip::CallTipCancel() { +void CallTip::CallTipCancel() noexcept { inCallTipMode = false; if (wCallTip.Created()) { wCallTip.Destroy(); @@ -345,7 +345,7 @@ void CallTip::SetPosition(bool aboveText) noexcept { }
bool CallTip::UseStyleCallTip() const noexcept { - return useStyleCallTip; + return useStyleCallTip; }
// It might be better to have two access functions for this and to use
Modified: scintilla/src/CallTip.h 2 lines changed, 1 insertions(+), 1 deletions(-) =================================================================== @@ -75,7 +75,7 @@ class CallTip { Scintilla::CharacterSet characterSet, Scintilla::Technology technology, const char *localeName, const Window &wParent);
- void CallTipCancel(); + void CallTipCancel() noexcept;
/// Set a range of characters to be displayed in a highlight style. /// Commonly used to highlight the current parameter.
Modified: scintilla/src/CaseConvert.cxx 10 lines changed, 7 insertions(+), 3 deletions(-) =================================================================== @@ -607,9 +607,13 @@ class CaseConverter : public ICaseConverter { std::vector<ConversionString> conversions;
public: - CaseConverter() noexcept { - } - virtual ~CaseConverter() = default; + CaseConverter() = default; + // Deleted so CaseConverter objects can not be copied. + CaseConverter(const CaseConverter &) = delete; + CaseConverter(CaseConverter &&) = delete; + CaseConverter &operator=(const CaseConverter &) = delete; + CaseConverter &operator=(CaseConverter &&) = delete; + virtual ~CaseConverter() noexcept = default; bool Initialised() const noexcept { return !characters.empty(); }
Modified: scintilla/src/CaseFolder.cxx 3 lines changed, 0 insertions(+), 3 deletions(-) =================================================================== @@ -23,9 +23,6 @@ CaseFolderTable::CaseFolderTable() noexcept : mapping{} { } }
-CaseFolderTable::~CaseFolderTable() { -} - size_t CaseFolderTable::Fold(char *folded, size_t sizeFolded, const char *mixed, size_t lenMixed) { if (lenMixed > sizeFolded) { return 0;
Modified: scintilla/src/CaseFolder.h 1 lines changed, 0 insertions(+), 1 deletions(-) =================================================================== @@ -21,7 +21,6 @@ class CaseFolderTable : public CaseFolder { char mapping[256]; public: CaseFolderTable() noexcept; - ~CaseFolderTable() override; size_t Fold(char *folded, size_t sizeFolded, const char *mixed, size_t lenMixed) override; void SetTranslation(char ch, char chTranslation) noexcept; void StandardASCII() noexcept;
Modified: scintilla/src/CellBuffer.cxx 2 lines changed, 1 insertions(+), 1 deletions(-) =================================================================== @@ -523,7 +523,7 @@ void UndoHistory::TentativeCommit() { }
bool UndoHistory::TentativeActive() const noexcept { - return tentativePoint >= 0; + return tentativePoint >= 0; }
int UndoHistory::TentativeSteps() noexcept {
Modified: scintilla/src/ContractionState.cxx 2 lines changed, 1 insertions(+), 1 deletions(-) =================================================================== @@ -197,7 +197,7 @@ Sci::Line ContractionState<LINE>::DocFromDisplay(Sci::Line lineDisplay) const no if (OneToOne()) { return lineDisplay; } else { - if (lineDisplay <= 0) { + if (lineDisplay < 0) { return 0; } if (lineDisplay > LinesDisplayed()) {
Modified: scintilla/src/Decoration.cxx 12 lines changed, 2 insertions(+), 10 deletions(-) =================================================================== @@ -39,8 +39,6 @@ class Decoration : public IDecoration {
explicit Decoration(int indicator_) : indicator(indicator_) { } - ~Decoration() override { - }
bool Empty() const noexcept override { return (rs.Runs() == 1) && (rs.AllSameAs(0)); @@ -75,7 +73,7 @@ template <typename POS> class DecorationList : public IDecorationList { int currentIndicator; int currentValue; - Decoration<POS> *current; // Cached so FillRange doesn't have to search for each call. + Decoration<POS> *current; // Non-owning. Cached so FillRange doesn't have to search for each call. Sci::Position lengthDocument; // Ordered by indicator std::vector<std::unique_ptr<Decoration<POS>>> decorationList; @@ -90,7 +88,6 @@ class DecorationList : public IDecorationList { public:
DecorationList(); - ~DecorationList() override;
const std::vector<const IDecoration*> &View() const noexcept override { return decorationView; @@ -128,11 +125,6 @@ DecorationList<POS>::DecorationList() : currentIndicator(0), currentValue(1), cu lengthDocument(0), clickNotified(false) { }
-template <typename POS> -DecorationList<POS>::~DecorationList() { - current = nullptr; -} - template <typename POS> Decoration<POS> *DecorationList<POS>::DecorationFromIndicator(int indicator) noexcept { for (const std::unique_ptr<Decoration<POS>> &deco : decorationList) { @@ -263,7 +255,7 @@ int DecorationList<POS>::AllOnFor(Sci::Position position) const noexcept { for (const std::unique_ptr<Decoration<POS>> &deco : decorationList) { if (deco->rs.ValueAt(static_cast<POS>(position))) { if (deco->Indicator() < static_cast<int>(Scintilla::IndicatorNumbers::Ime)) { - mask |= 1 << deco->Indicator(); + mask |= 1u << deco->Indicator(); } } }
Modified: scintilla/src/Document.cxx 23 lines changed, 16 insertions(+), 7 deletions(-) =================================================================== @@ -51,6 +51,16 @@ using namespace Scintilla; using namespace Scintilla::Internal;
+LexInterface::LexInterface(Document *pdoc_) noexcept : pdoc(pdoc_), performingStyle(false) { +} + +LexInterface::~LexInterface() noexcept = default; + +void LexInterface::SetInstance(ILexer5 *instance_) { + instance.reset(instance_); + pdoc->LexerChanged(); +} + void LexInterface::Colourise(Sci::Position start, Sci::Position end) { if (pdoc && instance && !performingStyle) { // Protect against reentrance, which may occur, for example, when @@ -86,6 +96,10 @@ LineEndType LexInterface::LineEndTypesSupported() { return LineEndType::Default; }
+bool LexInterface::UseContainerLexing() const noexcept { + return !instance; +} + ActionDuration::ActionDuration(double duration_, double minDuration_, double maxDuration_) noexcept : duration(duration_), minDuration(minDuration_), maxDuration(maxDuration_) { } @@ -2067,7 +2081,7 @@ Sci::Position Document::FindText(Sci::Position minPos, Sci::Position maxPos, con const unsigned char charStartSearch = search[0]; if (forward && ((0 == dbcsCodePage) || (CpUtf8 == dbcsCodePage && !UTF8IsTrailByte(charStartSearch)))) { // This is a fast case where there is no need to test byte values to iterate - // so becomes the equivalent of a memchr+memcmp loop. + // so becomes the equivalent of a memchr+memcmp loop. // UTF-8 search will not be self-synchronizing when starts with trail byte const std::string_view suffix(search + 1, lengthFind - 1); while (pos < endSearch) { @@ -2798,11 +2812,6 @@ Sci::Position Document::BraceMatch(Sci::Position position, Sci::Position /*maxRe class BuiltinRegex : public RegexSearchBase { public: explicit BuiltinRegex(CharClassify *charClassTable) : search(charClassTable) {} - BuiltinRegex(const BuiltinRegex &) = delete; - BuiltinRegex(BuiltinRegex &&) = delete; - BuiltinRegex &operator=(const BuiltinRegex &) = delete; - BuiltinRegex &operator=(BuiltinRegex &&) = delete; - ~BuiltinRegex() override = default;
Sci::Position FindText(Document *doc, Sci::Position minPos, Sci::Position maxPos, const char *s, bool caseSensitive, bool word, bool wordStart, FindOption flags, @@ -3199,7 +3208,7 @@ bool MatchOnLines(const Document *doc, const Regex ®exp, const RESearchRange } #endif if (matched) { - for (size_t co = 0; co < match.size(); co++) { + for (size_t co = 0; co < match.size() && co < RESearch::MAXTAG; co++) { search.bopat[co] = match[co].first.Pos(); search.eopat[co] = match[co].second.PosRoundUp(); const Sci::Position lenMatch = search.eopat[co] - search.bopat[co];
Modified: scintilla/src/Document.h 38 lines changed, 29 insertions(+), 9 deletions(-) =================================================================== @@ -90,7 +90,7 @@ class Range { */ class RegexSearchBase { public: - virtual ~RegexSearchBase() {} + virtual ~RegexSearchBase() = default;
virtual Sci::Position FindText(Document *doc, Sci::Position minPos, Sci::Position maxPos, const char *s, bool caseSensitive, bool word, bool wordStart, Scintilla::FindOption flags, Sci::Position *length) = 0; @@ -164,21 +164,41 @@ class HighlightDelimiter { bool isEnabled; };
+struct LexerReleaser { + // Called by unique_ptr to destroy/free the Resource + void operator()(Scintilla::ILexer5 *pLexer) noexcept { + if (pLexer) { + try { + pLexer->Release(); + } catch (...) { + // ILexer5::Release must not throw, ignore if it does. + } + } + } +}; + +using LexerInstance = std::unique_ptr<Scintilla::ILexer5, LexerReleaser>; + +// LexInterface defines the interface to ILexer used in Document. +// The LexState subclass is actually created and that is used within ScintillaBase +// to provide more methods that are exposed through Scintilla's external API. class LexInterface { protected: Document *pdoc; - Scintilla::ILexer5 *instance; + LexerInstance instance; bool performingStyle; ///< Prevent reentrance public: - explicit LexInterface(Document *pdoc_) noexcept : pdoc(pdoc_), instance(nullptr), performingStyle(false) { - } - virtual ~LexInterface() { - } + explicit LexInterface(Document *pdoc_) noexcept; + // Deleted so LexInterface objects can not be copied. + LexInterface(const LexInterface &) = delete; + LexInterface(LexInterface &&) = delete; + LexInterface &operator=(const LexInterface &) = delete; + LexInterface &operator=(LexInterface &&) = delete; + virtual ~LexInterface() noexcept; + void SetInstance(ILexer5 *instance_); void Colourise(Sci::Position start, Sci::Position end); virtual Scintilla::LineEndType LineEndTypesSupported(); - bool UseContainerLexing() const noexcept { - return instance == nullptr; - } + bool UseContainerLexing() const noexcept; };
struct RegexError : public std::runtime_error {
Modified: scintilla/src/EditModel.cxx 1 lines changed, 1 insertions(+), 0 deletions(-) =================================================================== @@ -7,6 +7,7 @@
#include <cstddef> #include <cstdlib> +#include <cstdint> #include <cassert> #include <cstring> #include <cmath>
Modified: scintilla/src/EditModel.h 1 lines changed, 0 insertions(+), 1 deletions(-) =================================================================== @@ -64,7 +64,6 @@ class EditModel { virtual Sci::Line TopLineOfMain() const = 0; virtual Point GetVisibleOriginInMain() const = 0; virtual Sci::Line LinesOnScreen() const = 0; - virtual Range GetHotSpotRange() const noexcept = 0; bool BidirectionalEnabled() const noexcept; bool BidirectionalR2L() const noexcept; void SetDefaultFoldDisplayText(const char *text);
Modified: scintilla/src/EditView.cxx 95 lines changed, 54 insertions(+), 41 deletions(-) =================================================================== @@ -7,6 +7,7 @@
#include <cstddef> #include <cstdlib> +#include <cstdint> #include <cassert> #include <cstring> #include <cstdio> @@ -951,19 +952,19 @@ static void DrawCaretLineFramed(Surface *surface, const ViewStyle &vsDraw, const // Avoid double drawing the corners by removing the left and right sides when drawing top and bottom borders const PRectangle rcWithoutLeftRight = rcLine.Inset(Point(width, 0.0));
- if (subLine == 0 || ll->wrapIndent == 0 || vsDraw.caretLine.layer != Layer::Base) { + if (subLine == 0 || ll->wrapIndent == 0 || vsDraw.caretLine.layer != Layer::Base || vsDraw.caretLine.subLine) { // Left surface->FillRectangleAligned(Side(rcLine, Edge::left, width), colourFrame); } - if (subLine == 0) { + if (subLine == 0 || vsDraw.caretLine.subLine) { // Top surface->FillRectangleAligned(Side(rcWithoutLeftRight, Edge::top, width), colourFrame); } - if (subLine == ll->lines - 1 || vsDraw.caretLine.layer != Layer::Base) { + if (subLine == ll->lines - 1 || vsDraw.caretLine.layer != Layer::Base || vsDraw.caretLine.subLine) { // Right surface->FillRectangleAligned(Side(rcLine, Edge::right, width), colourFrame); } - if (subLine == ll->lines - 1) { + if (subLine == ll->lines - 1 || vsDraw.caretLine.subLine) { // Bottom surface->FillRectangleAligned(Side(rcWithoutLeftRight, Edge::bottom, width), colourFrame); } @@ -1458,7 +1459,7 @@ void EditView::DrawEOLAnnotationText(Surface *surface, const EditModel &model, c } }
- // For multi-phase drawing draw the text last as transparent over any box + // For multi-phase drawing draw the text last as transparent over any box if (FlagSet(phase, DrawPhase::text)) { if (phasesDraw != PhasesDraw::One) { surface->DrawTextTransparentUTF8(rcText, fontText, @@ -1603,7 +1604,7 @@ void EditView::DrawCarets(Surface *surface, const EditModel &model, const ViewSt for (size_t r = 0; (r<model.sel.Count()) || drawDrag; r++) { const bool mainCaret = r == model.sel.Main(); SelectionPosition posCaret = (drawDrag ? model.posDrag : model.sel.Range(r).caret); - if ((vsDraw.DrawCaretInsideSelection(model.inOverstrike, imeCaretBlockOverride)) && + if ((vsDraw.DrawCaretInsideSelection(model.inOverstrike, imeCaretBlockOverride)) && !drawDrag && posCaret > model.sel.Range(r).anchor) { if (posCaret.VirtualSpace() > 0) @@ -1766,7 +1767,7 @@ void EditView::DrawBackground(Surface *surface, const EditModel &model, const Vi rcSegment.right = rcLine.right;
const InSelection inSelection = hideSelection ? InSelection::inNone : model.sel.CharacterInSelection(iDoc); - const bool inHotspot = (ll->hotspot.Valid()) && ll->hotspot.ContainsCharacter(iDoc); + const bool inHotspot = model.hotspot.Valid() && model.hotspot.ContainsCharacter(iDoc); ColourRGBA textBack = TextBackground(model, vsDraw, ll, background, inSelection, inHotspot, ll->styles[i], i); if (ts.representation) { @@ -1977,7 +1978,7 @@ void EditView::DrawForeground(Surface *surface, const EditModel &model, const Vi ColourRGBA textFore = vsDraw.styles[styleMain].fore; const Font *textFont = vsDraw.styles[styleMain].font.get(); // Hot-spot foreground - const bool inHotspot = (ll->hotspot.Valid()) && ll->hotspot.ContainsCharacter(iDoc); + const bool inHotspot = model.hotspot.Valid() && model.hotspot.ContainsCharacter(iDoc); if (inHotspot) { if (vsDraw.ElementColour(Element::HotSpotActive)) textFore = *vsDraw.ElementColour(Element::HotSpotActive); @@ -2124,7 +2125,7 @@ void EditView::DrawForeground(Surface *surface, const EditModel &model, const Vi } } } - if (ll->hotspot.Valid() && vsDraw.hotspotUnderline && ll->hotspot.ContainsCharacter(iDoc)) { + if (inHotspot && vsDraw.hotspotUnderline) { PRectangle rcUL = rcSegment; rcUL.top = rcUL.top + vsDraw.maxAscent + 1; rcUL.bottom = rcUL.top + 1; @@ -2281,27 +2282,40 @@ void EditView::DrawLine(Surface *surface, const EditModel &model, const ViewStyl } }
-static void DrawFoldLines(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, Sci::Line line, PRectangle rcLine) { +static void DrawFoldLines(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, + Sci::Line line, PRectangle rcLine, int subLine) { + const bool lastSubLine = subLine == (ll->lines - 1); const bool expanded = model.pcs->GetExpanded(line); const FoldLevel level = model.pdoc->GetFoldLevel(line); const FoldLevel levelNext = model.pdoc->GetFoldLevel(line + 1); if (LevelIsHeader(level) && (LevelNumber(level) < LevelNumber(levelNext))) { + const ColourRGBA foldLineColour = vsDraw.ElementColour(Element::FoldLine).value_or( + vsDraw.styles[StyleDefault].fore); // Paint the line above the fold - if ((expanded && (FlagSet(model.foldFlags, FoldFlag::LineBeforeExpanded))) + if ((subLine == 0) && + ((expanded && (FlagSet(model.foldFlags, FoldFlag::LineBeforeExpanded))) || - (!expanded && (FlagSet(model.foldFlags, FoldFlag::LineBeforeContracted)))) { - PRectangle rcFoldLine = rcLine; - rcFoldLine.bottom = rcFoldLine.top + 1; - surface->FillRectangleAligned(rcFoldLine, Fill(vsDraw.styles[StyleDefault].fore)); + (!expanded && (FlagSet(model.foldFlags, FoldFlag::LineBeforeContracted))))) { + surface->FillRectangleAligned(Side(rcLine, Edge::top, 1.0), foldLineColour); } // Paint the line below the fold - if ((expanded && (FlagSet(model.foldFlags, FoldFlag::LineAfterExpanded))) + if (lastSubLine && + ((expanded && (FlagSet(model.foldFlags, FoldFlag::LineAfterExpanded))) || - (!expanded && (FlagSet(model.foldFlags, FoldFlag::LineAfterContracted)))) { - PRectangle rcFoldLine = rcLine; - rcFoldLine.top = rcFoldLine.bottom - 1; - surface->FillRectangleAligned(rcFoldLine, Fill(vsDraw.styles[StyleDefault].fore)); + (!expanded && (FlagSet(model.foldFlags, FoldFlag::LineAfterContracted))))) { + surface->FillRectangleAligned(Side(rcLine, Edge::bottom, 1.0), foldLineColour); + // If contracted fold line drawn then don't overwrite with hidden line + // as fold lines are more specific then hidden lines. + if (!expanded) { + return; + } + } + } + if (lastSubLine && model.pcs->GetVisible(line) && !model.pcs->GetVisible(line + 1)) { + std::optional<ColourRGBA> hiddenLineColour = vsDraw.ElementColour(Element::HiddenLine); + if (hiddenLineColour) { + surface->FillRectangleAligned(Side(rcLine, Edge::bottom, 1.0), *hiddenLineColour); } } } @@ -2327,10 +2341,9 @@ void EditView::PaintText(Surface *surfaceWindow, const EditModel &model, PRectan const int screenLinePaintFirst = static_cast<int>(rcArea.top) / vsDraw.lineHeight; const int xStart = vsDraw.textStart - model.xOffset + static_cast<int>(ptOrigin.x);
- SelectionPosition posCaret = model.sel.RangeMain().caret; - if (model.posDrag.IsValid()) - posCaret = model.posDrag; + const SelectionPosition posCaret = model.posDrag.IsValid() ? model.posDrag : model.sel.RangeMain().caret; const Sci::Line lineCaret = model.pdoc->SciLineFromPosition(posCaret.Position()); + const int caretOffset = static_cast<int>(posCaret.Position() - model.pdoc->LineStart(lineCaret));
PRectangle rcTextArea = rcClient; if (vsDraw.marginInside) { @@ -2397,8 +2410,8 @@ void EditView::PaintText(Surface *surfaceWindow, const EditModel &model, PRectan durLayout += ep.Duration(true); #endif if (ll) { - ll->containsCaret = !hideSelection && (lineDoc == lineCaret); - ll->hotspot = model.GetHotSpotRange(); + ll->containsCaret = !hideSelection && (lineDoc == lineCaret) + && (ll->lines == 1 || !vsDraw.caretLine.subLine || ll->InLine(caretOffset, subLine));
PRectangle rcLine = rcTextArea; rcLine.top = static_cast<XYPOSITION>(ypos); @@ -2432,7 +2445,7 @@ void EditView::PaintText(Surface *surfaceWindow, const EditModel &model, PRectan ll->RestoreBracesHighlight(rangeLine, model.braces, bracesIgnoreStyle);
if (FlagSet(phase, DrawPhase::foldLines)) { - DrawFoldLines(surface, model, vsDraw, lineDoc, rcLine); + DrawFoldLines(surface, model, vsDraw, ll.get(), lineDoc, rcLine, subLine); }
if (FlagSet(phase, DrawPhase::carets)) { @@ -2578,24 +2591,24 @@ Sci::Position EditView::FormatRange(bool draw, const RangeToFormat *pfr, Surface vsPrint.braceBadLightIndicatorSet = false;
// Set colours for printing according to users settings - for (size_t sty = 0; sty < vsPrint.styles.size(); sty++) { - if (printParameters.colourMode == PrintOption::InvertLight) { - vsPrint.styles[sty].fore = InvertedLight(vsPrint.styles[sty].fore); - vsPrint.styles[sty].back = InvertedLight(vsPrint.styles[sty].back); - } else if (printParameters.colourMode == PrintOption::BlackOnWhite) { - vsPrint.styles[sty].fore = ColourRGBA(0, 0, 0); - vsPrint.styles[sty].back = ColourRGBA(0xff, 0xff, 0xff); - } else if (printParameters.colourMode == PrintOption::ColourOnWhite) { - vsPrint.styles[sty].back = ColourRGBA(0xff, 0xff, 0xff); - } else if (printParameters.colourMode == PrintOption::ColourOnWhiteDefaultBG) { - if (sty <= StyleDefault) { - vsPrint.styles[sty].back = ColourRGBA(0xff, 0xff, 0xff); - } + const PrintOption colourMode = printParameters.colourMode; + const std::vector<Style>::iterator endStyles = (colourMode == PrintOption::ColourOnWhiteDefaultBG) ? + vsPrint.styles.begin() + StyleLineNumber : vsPrint.styles.end(); + for (std::vector<Style>::iterator it = vsPrint.styles.begin(); it != endStyles; ++it) { + if (colourMode == PrintOption::InvertLight) { + it->fore = InvertedLight(it->fore); + it->back = InvertedLight(it->back); + } else if (colourMode == PrintOption::BlackOnWhite) { + it->fore = ColourRGBA(0, 0, 0); + it->back = ColourRGBA(0xff, 0xff, 0xff); + } else if (colourMode == PrintOption::ColourOnWhite || colourMode == PrintOption::ColourOnWhiteDefaultBG) { + it->back = ColourRGBA(0xff, 0xff, 0xff); } } // White background for the line numbers if PrintOption::ScreenColours isn't used - if (printParameters.colourMode != PrintOption::ScreenColours) + if (colourMode != PrintOption::ScreenColours) { vsPrint.styles[StyleLineNumber].back = ColourRGBA(0xff, 0xff, 0xff); + }
// Printing uses different margins, so reset screen margins vsPrint.leftMarginWidth = 0; @@ -2688,7 +2701,7 @@ Sci::Position EditView::FormatRange(bool draw, const RangeToFormat *pfr, Surface vsPrint.styles[StyleLineNumber].font.get(), number); surface->FlushCachedState(); surface->DrawTextNoClip(rcNumber, vsPrint.styles[StyleLineNumber].font.get(), - static_cast<XYPOSITION>(ypos + vsPrint.maxAscent), number, + ypos + vsPrint.maxAscent, number, vsPrint.styles[StyleLineNumber].fore, vsPrint.styles[StyleLineNumber].back); }
Modified: scintilla/src/Editor.cxx 48 lines changed, 38 insertions(+), 10 deletions(-) =================================================================== @@ -7,6 +7,7 @@
#include <cstddef> #include <cstdlib> +#include <cstdint> #include <cassert> #include <cstring> #include <cstdio> @@ -117,7 +118,7 @@ static constexpr bool IsAllSpacesOrTabs(std::string_view sv) noexcept { return true; }
-Editor::Editor() : durationWrapOneByte(0.000001, 0.0000001, 0.00001) { +Editor::Editor() : durationWrapOneByte(0.000001, 0.00000001, 0.00001) { ctrlID = 0;
stylesValid = false; @@ -479,12 +480,17 @@ void Editor::DiscardOverdraw() { }
void Editor::Redraw() { + if (redrawPendingText) { + return; + } //Platform::DebugPrintf("Redraw all\n"); const PRectangle rcClient = GetClientRectangle(); wMain.InvalidateRectangle(rcClient); - if (wMargin.GetID()) + if (wMargin.GetID()) { wMargin.InvalidateAll(); - //wMain.InvalidateAll(); + } else if (paintState == PaintState::notPainting) { + redrawPendingText = true; + } }
void Editor::RedrawSelMargin(Sci::Line line, bool allAfter) { @@ -498,11 +504,15 @@ void Editor::RedrawSelMargin(Sci::Line line, bool allAfter) { Redraw(); return; } + if (redrawPendingMargin) { + return; + } PRectangle rcMarkers = GetClientRectangle(); if (!markersInText) { // Normal case: just draw the margin rcMarkers.right = rcMarkers.left + vs.fixedColumnWidth; } + const PRectangle rcMarkersFull = rcMarkers; if (line != -1) { PRectangle rcLine = RectangleFromRange(Range(pdoc->LineStart(line)), 0);
@@ -529,6 +539,9 @@ void Editor::RedrawSelMargin(Sci::Line line, bool allAfter) { wMargin.InvalidateRectangle(rcMarkers); } else { wMain.InvalidateRectangle(rcMarkers); + if (rcMarkers == rcMarkersFull) { + redrawPendingMargin = true; + } } }
@@ -552,6 +565,9 @@ PRectangle Editor::RectangleFromRange(Range r, int overlap) { }
void Editor::InvalidateRange(Sci::Position start, Sci::Position end) { + if (redrawPendingText) { + return; + } RedrawRect(RectangleFromRange(Range(start, end), view.LinesOverlap() ? vs.lineOverlap : 0)); }
@@ -1717,6 +1733,9 @@ void Editor::RefreshPixMaps(Surface *surfaceWindow) { }
void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { + redrawPendingText = false; + redrawPendingMargin = false; + //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n", // paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
@@ -4780,10 +4799,6 @@ void Editor::SetHotSpotRange(const Point *pt) { } }
-Range Editor::GetHotSpotRange() const noexcept { - return hotspot; -} - void Editor::ButtonMoveWithModifiers(Point pt, unsigned int, KeyMod modifiers) { if (ptMouseLast != pt) { DwellEnd(true); @@ -5748,6 +5763,9 @@ void Editor::StyleSetMessage(Message iMessage, uptr_t wParam, sptr_t lParam) { case Message::StyleSetHotSpot: vs.styles[wParam].hotspot = lParam != 0; break; + case Message::StyleSetCheckMonospaced: + vs.styles[wParam].checkMonospaced = lParam != 0; + break; default: break; } @@ -5787,6 +5805,8 @@ sptr_t Editor::StyleGetMessage(Message iMessage, uptr_t wParam, sptr_t lParam) { return vs.styles[wParam].changeable ? 1 : 0; case Message::StyleGetHotSpot: return vs.styles[wParam].hotspot ? 1 : 0; + case Message::StyleGetCheckMonospaced: + return vs.styles[wParam].checkMonospaced ? 1 : 0; default: break; } @@ -7202,6 +7222,7 @@ sptr_t Editor::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) { case Message::StyleSetVisible: case Message::StyleSetChangeable: case Message::StyleSetHotSpot: + case Message::StyleSetCheckMonospaced: StyleSetMessage(iMessage, wParam, lParam); break;
@@ -7220,6 +7241,7 @@ sptr_t Editor::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) { case Message::StyleGetVisible: case Message::StyleGetChangeable: case Message::StyleGetHotSpot: + case Message::StyleGetCheckMonospaced: return StyleGetMessage(iMessage, wParam, lParam);
case Message::StyleResetDefault: @@ -7300,6 +7322,13 @@ sptr_t Editor::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) { InvalidateStyleRedraw(); break;
+ case Message::GetCaretLineHighlightSubLine: + return vs.caretLine.subLine; + case Message::SetCaretLineHighlightSubLine: + vs.caretLine.subLine = wParam != 0; + InvalidateStyleRedraw(); + break; + case Message::GetCaretLineFrame: return vs.caretLine.frame; case Message::SetCaretLineFrame: @@ -7377,8 +7406,7 @@ sptr_t Editor::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) { break;
case Message::HideLines: - if (wParam > 0) - pcs->SetVisible(LineFromUPtr(wParam), lParam, false); + pcs->SetVisible(LineFromUPtr(wParam), lParam, false); SetScrollBars(); Redraw(); break; @@ -7903,7 +7931,7 @@ sptr_t Editor::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) { break;
case Message::MultiEdgeAddLine: - vs.AddMultiEdge(wParam, lParam); + vs.AddMultiEdge(static_cast<int>(wParam), ColourRGBA::FromIpRGB(lParam)); InvalidateStyleRedraw(); break;
Modified: scintilla/src/Editor.h 7 lines changed, 5 insertions(+), 2 deletions(-) =================================================================== @@ -188,6 +188,10 @@ class Editor : public EditModel, public DocWatcher { Window wMain; ///< The Scintilla parent window Window wMargin; ///< May be separate when using a scroll view for wMain
+ // Optimization that avoids superfluous invalidations + bool redrawPendingText = false; + bool redrawPendingMargin = false; + /** Style resources may be expensive to allocate so are cached between uses. * When a style attribute is changed, this cache is flushed. */ bool stylesValid; @@ -581,7 +585,6 @@ class Editor : public EditModel, public DocWatcher { bool PositionIsHotspot(Sci::Position position) const; bool PointIsHotspot(Point pt); void SetHotSpotRange(const Point *pt); - Range GetHotSpotRange() const noexcept override; void SetHoverIndicatorPosition(Sci::Position position); void SetHoverIndicatorPoint(Point pt);
@@ -637,7 +640,7 @@ class Editor : public EditModel, public DocWatcher { return Point(static_cast<XYPOSITION>(wParam) - vs.ExternalMarginWidth(), static_cast<XYPOSITION>(lParam)); }
- constexpr std::optional<FoldLevel> OptionalFoldLevel(Scintilla::sptr_t lParam) { + static constexpr std::optional<FoldLevel> OptionalFoldLevel(Scintilla::sptr_t lParam) { if (lParam >= 0) { return static_cast<FoldLevel>(lParam); }
Modified: scintilla/src/Geometry.cxx 24 lines changed, 24 insertions(+), 0 deletions(-) =================================================================== @@ -12,6 +12,14 @@
#include "Geometry.h"
+namespace { + +constexpr unsigned int Mixed(unsigned char a, unsigned char b, double proportion) noexcept { + return static_cast<unsigned int>(a + proportion * (b - a)); +} + +} + namespace Scintilla::Internal {
PRectangle Clamp(PRectangle rc, Edge edge, XYPOSITION position) noexcept { @@ -95,4 +103,20 @@ PRectangle PixelAlignOutside(const PRectangle &rc, int pixelDivisions) noexcept std::floor(rc.bottom * pixelDivisions) / pixelDivisions); }
+ColourRGBA ColourRGBA::MixedWith(ColourRGBA other) const noexcept { + const unsigned int red = (GetRed() + other.GetRed()) / 2; + const unsigned int green = (GetGreen() + other.GetGreen()) / 2; + const unsigned int blue = (GetBlue() + other.GetBlue()) / 2; + const unsigned int alpha = (GetAlpha() + other.GetAlpha()) / 2; + return ColourRGBA(red, green, blue, alpha); +} + +ColourRGBA ColourRGBA::MixedWith(ColourRGBA other, double proportion) const noexcept { + return ColourRGBA( + Mixed(GetRed(), other.GetRed(), proportion), + Mixed(GetGreen(), other.GetGreen(), proportion), + Mixed(GetBlue(), other.GetBlue(), proportion), + Mixed(GetAlpha(), other.GetAlpha(), proportion)); +} + }
Modified: scintilla/src/Geometry.h 28 lines changed, 6 insertions(+), 22 deletions(-) =================================================================== @@ -161,9 +161,6 @@ PRectangle PixelAlignOutside(const PRectangle &rc, int pixelDivisions) noexcept; constexpr const float componentMaximum = 255.0f; class ColourRGBA { int co; - constexpr static unsigned int Mixed(unsigned char a, unsigned char b, double proportion) noexcept { - return static_cast<unsigned int>(a + proportion * (b - a)); - } public: constexpr explicit ColourRGBA(int co_ = 0) noexcept : co(co_) { } @@ -236,21 +233,8 @@ class ColourRGBA { return GetAlpha() == 0xff; }
- constexpr ColourRGBA MixedWith(ColourRGBA other) const noexcept { - const unsigned int red = (GetRed() + other.GetRed()) / 2; - const unsigned int green = (GetGreen() + other.GetGreen()) / 2; - const unsigned int blue = (GetBlue() + other.GetBlue()) / 2; - const unsigned int alpha = (GetAlpha() + other.GetAlpha()) / 2; - return ColourRGBA(red, green, blue, alpha); - } - - constexpr ColourRGBA MixedWith(ColourRGBA other, double proportion) const noexcept { - return ColourRGBA( - Mixed(GetRed(), other.GetRed(), proportion), - Mixed(GetGreen(), other.GetGreen(), proportion), - Mixed(GetBlue(), other.GetBlue(), proportion), - Mixed(GetAlpha(), other.GetAlpha(), proportion)); - } + ColourRGBA MixedWith(ColourRGBA other) const noexcept; + ColourRGBA MixedWith(ColourRGBA other, double proportion) const noexcept; };
/** @@ -260,7 +244,7 @@ class Stroke { public: ColourRGBA colour; XYPOSITION width; - constexpr Stroke(ColourRGBA colour_, XYPOSITION width_=1.0) noexcept : + constexpr Stroke(ColourRGBA colour_, XYPOSITION width_=1.0) noexcept : colour(colour_), width(width_) { } constexpr float WidthF() const noexcept { @@ -274,7 +258,7 @@ class Stroke { class Fill { public: ColourRGBA colour; - constexpr Fill(ColourRGBA colour_) noexcept : + constexpr Fill(ColourRGBA colour_) noexcept : colour(colour_) { } }; @@ -286,10 +270,10 @@ class FillStroke { public: Fill fill; Stroke stroke; - constexpr FillStroke(ColourRGBA colourFill_, ColourRGBA colourStroke_, XYPOSITION widthStroke_=1.0) noexcept : + constexpr FillStroke(ColourRGBA colourFill_, ColourRGBA colourStroke_, XYPOSITION widthStroke_=1.0) noexcept : fill(colourFill_), stroke(colourStroke_, widthStroke_) { } - constexpr FillStroke(ColourRGBA colourBoth, XYPOSITION widthStroke_=1.0) noexcept : + constexpr FillStroke(ColourRGBA colourBoth, XYPOSITION widthStroke_=1.0) noexcept : fill(colourBoth), stroke(colourBoth, widthStroke_) { } };
Modified: scintilla/src/Indicator.cxx 4 lines changed, 2 insertions(+), 2 deletions(-) =================================================================== @@ -47,7 +47,7 @@ void Indicator::Draw(Surface *surface, const PRectangle &rc, const PRectangle &r
const XYPOSITION ymid = PixelAlign(rc.Centre().y, pixelDivisions);
- // This is a reasonable clip for indicators beneath text like underlines + // This is a reasonable clip for indicators beneath text like underlines PRectangle rcClip = rcAligned; rcClip.bottom = rcFullHeightAligned.bottom;
@@ -242,7 +242,7 @@ void Indicator::Draw(Surface *surface, const PRectangle &rc, const PRectangle &r const XYPOSITION widthDot = std::round(strokeWidth); XYPOSITION x = std::floor(rc.left); while (x < rc.right) { - const PRectangle rcDot = PRectangle(x, ymid, + const PRectangle rcDot = PRectangle(x, ymid, x + widthDot, ymid + widthDot); surface->FillRectangle(rcDot, sacDraw.fore); x += widthDot * 2;
Modified: scintilla/src/KeyMap.cxx 4 lines changed, 0 insertions(+), 4 deletions(-) =================================================================== @@ -32,10 +32,6 @@ KeyMap::KeyMap() { } }
-KeyMap::~KeyMap() { - Clear(); -} - void KeyMap::Clear() noexcept { kmap.clear(); }
Modified: scintilla/src/KeyMap.h 1 lines changed, 0 insertions(+), 1 deletions(-) =================================================================== @@ -52,7 +52,6 @@ class KeyMap {
public: KeyMap(); - ~KeyMap(); void Clear() noexcept; void AssignCmdKey(Scintilla::Keys key, Scintilla::KeyMod modifiers, Scintilla::Message msg); Scintilla::Message Find(Scintilla::Keys key, Scintilla::KeyMod modifiers) const; // 0 returned on failure
Modified: scintilla/src/LineMarker.cxx 2 lines changed, 1 insertions(+), 1 deletions(-) =================================================================== @@ -326,7 +326,7 @@ void LineMarker::DrawFoldingMark(Surface *surface, const PRectangle &rcWhole, Fo void LineMarker::AlignedPolygon(Surface *surface, const Point *pts, size_t npts) const { const XYPOSITION move = strokeWidth / 2.0; std::vector<Point> points; - std::transform(pts, pts + npts, std::back_inserter(points), [=](Point pt)->Point { + std::transform(pts, pts + npts, std::back_inserter(points), [=](Point pt) noexcept ->Point { return Point(pt.x + move, pt.y + move); }); surface->Polygon(points.data(), std::size(points), FillStroke(back, fore, strokeWidth));
Modified: scintilla/src/MarginView.cxx 528 lines changed, 274 insertions(+), 254 deletions(-) =================================================================== @@ -7,6 +7,7 @@
#include <cstddef> #include <cstdlib> +#include <cstdint> #include <cassert> #include <cstring> #include <cstdio> @@ -166,301 +167,320 @@ void MarginView::RefreshPixMaps(Surface *surfaceWindow, const ViewStyle &vsDraw) } }
-static MarkerOutline SubstituteMarkerIfEmpty(MarkerOutline markerCheck, MarkerOutline markerDefault, const ViewStyle &vs) noexcept { +namespace { + +MarkerOutline SubstituteMarkerIfEmpty(MarkerOutline markerCheck, MarkerOutline markerDefault, const ViewStyle &vs) noexcept { if (vs.markers[static_cast<size_t>(markerCheck)].markType == MarkerSymbol::Empty) return markerDefault; return markerCheck; }
+constexpr MarkerOutline TailFromNextLevel(FoldLevel levelNextNum) noexcept { + return (levelNextNum > FoldLevel::Base) ? MarkerOutline::FolderMidTail : MarkerOutline::FolderTail; +} + +int FoldingMark(FoldLevel level, FoldLevel levelNext, bool firstSubLine, bool lastSubLine, + bool isExpanded, bool needWhiteClosure, MarkerOutline folderOpenMid, MarkerOutline folderEnd) noexcept { + + const FoldLevel levelNum = LevelNumberPart(level); + const FoldLevel levelNextNum = LevelNumberPart(levelNext); + + if (LevelIsHeader(level)) { + if (firstSubLine) { + if (levelNum < levelNextNum) { + if (levelNum == FoldLevel::Base) { + return 1 << (isExpanded ? MarkerOutline::FolderOpen : MarkerOutline::Folder); + } else { + return 1 << (isExpanded ? folderOpenMid : folderEnd); + } + } else if (levelNum > FoldLevel::Base) { + return 1 << MarkerOutline::FolderSub; + } + } else { + if (levelNum < levelNextNum) { + if (isExpanded) { + return 1 << MarkerOutline::FolderSub; + } else if (levelNum > FoldLevel::Base) { + return 1 << MarkerOutline::FolderSub; + } + } else if (levelNum > FoldLevel::Base) { + return 1 << MarkerOutline::FolderSub; + } + } + } else if (LevelIsWhitespace(level)) { + if (needWhiteClosure) { + if (LevelIsWhitespace(levelNext)) { + return 1 << MarkerOutline::FolderSub; + } else { + return 1 << TailFromNextLevel(levelNextNum); + } + } else if (levelNum > FoldLevel::Base) { + if (levelNextNum < levelNum) { + return 1 << TailFromNextLevel(levelNextNum); + } else { + return 1 << MarkerOutline::FolderSub; + } + } + } else if (levelNum > FoldLevel::Base) { + if (levelNextNum < levelNum) { + if (LevelIsWhitespace(levelNext)) { + return 1 << MarkerOutline::FolderSub; + } else if (lastSubLine) { + return 1 << TailFromNextLevel(levelNextNum); + } else { + return 1 << MarkerOutline::FolderSub; + } + } else { + return 1 << MarkerOutline::FolderSub; + } + } + + // No folding mark on this line + return 0; +} + +} + +void MarginView::PaintOneMargin(Surface *surface, PRectangle rc, PRectangle rcOneMargin, const MarginStyle &marginStyle, + const EditModel &model, const ViewStyle &vs) { + const Point ptOrigin = model.GetVisibleOriginInMain(); + const Sci::Line lineStartPaint = static_castSci::Line(rcOneMargin.top + ptOrigin.y) / vs.lineHeight; + Sci::Line visibleLine = model.TopLineOfMain() + lineStartPaint; + XYPOSITION yposScreen = lineStartPaint * vs.lineHeight - ptOrigin.y; + // Work out whether the top line is whitespace located after a + // lessening of fold level which implies a 'fold tail' but which should not + // be displayed until the last of a sequence of whitespace. + bool needWhiteClosure = false; + if (marginStyle.ShowsFolding()) { + const FoldLevel level = model.pdoc->GetFoldLevel(model.pcs->DocFromDisplay(visibleLine)); + if (LevelIsWhitespace(level)) { + Sci::Line lineBack = model.pcs->DocFromDisplay(visibleLine); + FoldLevel levelPrev = level; + while ((lineBack > 0) && LevelIsWhitespace(levelPrev)) { + lineBack--; + levelPrev = model.pdoc->GetFoldLevel(lineBack); + } + if (!LevelIsHeader(levelPrev)) { + if (LevelNumber(level) < LevelNumber(levelPrev)) + needWhiteClosure = true; + } + } + } + + // Old code does not know about new markers needed to distinguish all cases + const MarkerOutline folderOpenMid = SubstituteMarkerIfEmpty(MarkerOutline::FolderOpenMid, + MarkerOutline::FolderOpen, vs); + const MarkerOutline folderEnd = SubstituteMarkerIfEmpty(MarkerOutline::FolderEnd, + MarkerOutline::Folder, vs); + + while ((visibleLine < model.pcs->LinesDisplayed()) && yposScreen < rc.bottom) { + + PLATFORM_ASSERT(visibleLine < model.pcs->LinesDisplayed()); + const Sci::Line lineDoc = model.pcs->DocFromDisplay(visibleLine); + PLATFORM_ASSERT((lineDoc == 0) || model.pcs->GetVisible(lineDoc)); + const Sci::Line firstVisibleLine = model.pcs->DisplayFromDoc(lineDoc); + const Sci::Line lastVisibleLine = model.pcs->DisplayLastFromDoc(lineDoc); + const bool firstSubLine = visibleLine == firstVisibleLine; + const bool lastSubLine = visibleLine == lastVisibleLine; + + int marks = firstSubLine ? model.pdoc->GetMark(lineDoc) : 0; + + bool headWithTail = false; + + if (marginStyle.ShowsFolding()) { + // Decide which fold indicator should be displayed + const FoldLevel level = model.pdoc->GetFoldLevel(lineDoc); + const FoldLevel levelNext = model.pdoc->GetFoldLevel(lineDoc + 1); + const FoldLevel levelNum = LevelNumberPart(level); + const FoldLevel levelNextNum = LevelNumberPart(levelNext); + const bool isExpanded = model.pcs->GetExpanded(lineDoc); + + marks |= FoldingMark(level, levelNext, firstSubLine, lastSubLine, + isExpanded, needWhiteClosure, folderOpenMid, folderEnd); + + // Change needWhiteClosure and headWithTail if needed + if (LevelIsHeader(level)) { + needWhiteClosure = false; + const Sci::Line firstFollowupLine = model.pcs->DocFromDisplay(model.pcs->DisplayFromDoc(lineDoc + 1)); + const FoldLevel firstFollowupLineLevel = model.pdoc->GetFoldLevel(firstFollowupLine); + const FoldLevel secondFollowupLineLevelNum = LevelNumberPart(model.pdoc->GetFoldLevel(firstFollowupLine + 1)); + if (!isExpanded) { + if (LevelIsWhitespace(firstFollowupLineLevel) && + (levelNum > secondFollowupLineLevelNum)) + needWhiteClosure = true; + + if (highlightDelimiter.IsFoldBlockHighlighted(firstFollowupLine)) + headWithTail = true; + } + } else if (LevelIsWhitespace(level)) { + if (needWhiteClosure) { + needWhiteClosure = LevelIsWhitespace(levelNext); + } + } else if (levelNum > FoldLevel::Base) { + if (levelNextNum < levelNum) { + needWhiteClosure = LevelIsWhitespace(levelNext); + } + } + } + + const PRectangle rcMarker( + rcOneMargin.left, + yposScreen, + rcOneMargin.right, + yposScreen + vs.lineHeight); + if (marginStyle.style == MarginType::Number) { + if (firstSubLine) { + std::string sNumber; + if (lineDoc >= 0) { + sNumber = std::to_string(lineDoc + 1); + } + if (FlagSet(model.foldFlags, (FoldFlag::LevelNumbers | FoldFlag::LineState))) { + char number[100] = ""; + if (FlagSet(model.foldFlags, FoldFlag::LevelNumbers)) { + const FoldLevel lev = model.pdoc->GetFoldLevel(lineDoc); + sprintf(number, "%c%c %03X %03X", + LevelIsHeader(lev) ? 'H' : '_', + LevelIsWhitespace(lev) ? 'W' : '_', + LevelNumber(lev), + static_cast<int>(lev) >> 16 + ); + } else { + const int state = model.pdoc->GetLineState(lineDoc); + sprintf(number, "%0X", state); + } + sNumber = number; + } + PRectangle rcNumber = rcMarker; + // Right justify + const XYPOSITION width = surface->WidthText(vs.styles[StyleLineNumber].font.get(), sNumber); + const XYPOSITION xpos = rcNumber.right - width - vs.marginNumberPadding; + rcNumber.left = xpos; + DrawTextNoClipPhase(surface, rcNumber, vs.styles[StyleLineNumber], + rcNumber.top + vs.maxAscent, sNumber, DrawPhase::all); + } else if (FlagSet(vs.wrap.visualFlags, WrapVisualFlag::Margin)) { + PRectangle rcWrapMarker = rcMarker; + rcWrapMarker.right -= wrapMarkerPaddingRight; + rcWrapMarker.left = rcWrapMarker.right - vs.styles[StyleLineNumber].aveCharWidth; + if (!customDrawWrapMarker) { + DrawWrapMarker(surface, rcWrapMarker, false, vs.styles[StyleLineNumber].fore); + } else { + customDrawWrapMarker(surface, rcWrapMarker, false, vs.styles[StyleLineNumber].fore); + } + } + } else if (marginStyle.style == MarginType::Text || marginStyle.style == MarginType::RText) { + const StyledText stMargin = model.pdoc->MarginStyledText(lineDoc); + if (stMargin.text && ValidStyledText(vs, vs.marginStyleOffset, stMargin)) { + if (firstSubLine) { + surface->FillRectangle(rcMarker, + vs.styles[stMargin.StyleAt(0) + vs.marginStyleOffset].back); + PRectangle rcText = rcMarker; + if (marginStyle.style == MarginType::RText) { + const int width = WidestLineWidth(surface, vs, vs.marginStyleOffset, stMargin); + rcText.left = rcText.right - width - 3; + } + DrawStyledText(surface, vs, vs.marginStyleOffset, rcText, + stMargin, 0, stMargin.length, DrawPhase::all); + } else { + // if we're displaying annotation lines, colour the margin to match the associated document line + const int annotationLines = model.pdoc->AnnotationLines(lineDoc); + if (annotationLines && (visibleLine > lastVisibleLine - annotationLines)) { + surface->FillRectangle(rcMarker, vs.styles[stMargin.StyleAt(0) + vs.marginStyleOffset].back); + } + } + } + } + + marks &= marginStyle.mask; + + if (marks) { + for (int markBit = 0; (markBit < 32) && marks; markBit++) { + if (marks & 1) { + LineMarker::FoldPart part = LineMarker::FoldPart::undefined; + if (marginStyle.ShowsFolding() && highlightDelimiter.IsFoldBlockHighlighted(lineDoc)) { + if (highlightDelimiter.IsBodyOfFoldBlock(lineDoc)) { + part = LineMarker::FoldPart::body; + } else if (highlightDelimiter.IsHeadOfFoldBlock(lineDoc)) { + if (firstSubLine) { + part = headWithTail ? LineMarker::FoldPart::headWithTail : LineMarker::FoldPart::head; + } else { + if (model.pcs->GetExpanded(lineDoc) || headWithTail) { + part = LineMarker::FoldPart::body; + } else { + part = LineMarker::FoldPart::undefined; + } + } + } else if (highlightDelimiter.IsTailOfFoldBlock(lineDoc)) { + part = LineMarker::FoldPart::tail; + } + } + vs.markers[markBit].Draw(surface, rcMarker, vs.styles[StyleLineNumber].font.get(), part, marginStyle.style); + } + marks >>= 1; + } + } + + visibleLine++; + yposScreen += vs.lineHeight; + } +} + void MarginView::PaintMargin(Surface *surface, Sci::Line topLine, PRectangle rc, PRectangle rcMargin, const EditModel &model, const ViewStyle &vs) {
- PRectangle rcSelMargin = rcMargin; - rcSelMargin.right = rcMargin.left; - if (rcSelMargin.bottom < rc.bottom) - rcSelMargin.bottom = rc.bottom; + PRectangle rcOneMargin = rcMargin; + rcOneMargin.right = rcMargin.left; + if (rcOneMargin.bottom < rc.bottom) + rcOneMargin.bottom = rc.bottom;
const Point ptOrigin = model.GetVisibleOriginInMain(); - const Font *fontLineNumber = vs.styles[StyleLineNumber].font.get(); - for (size_t margin = 0; margin < vs.ms.size(); margin++) { - if (vs.ms[margin].width > 0) { + for (const MarginStyle &marginStyle : vs.ms) { + if (marginStyle.width > 0) {
- rcSelMargin.left = rcSelMargin.right; - rcSelMargin.right = rcSelMargin.left + vs.ms[margin].width; + rcOneMargin.left = rcOneMargin.right; + rcOneMargin.right = rcOneMargin.left + marginStyle.width;
- if (vs.ms[margin].style != MarginType::Number) { - if (vs.ms[margin].ShowsFolding()) { + if (marginStyle.style != MarginType::Number) { + if (marginStyle.ShowsFolding()) { // Required because of special way brush is created for selection margin // Ensure patterns line up when scrolling with separate margin view // by choosing correctly aligned variant. const bool invertPhase = static_cast<int>(ptOrigin.y) & 1; - surface->FillRectangle(rcSelMargin, + surface->FillRectangle(rcOneMargin, invertPhase ? *pixmapSelPattern : *pixmapSelPatternOffset1); } else { ColourRGBA colour; - switch (vs.ms[margin].style) { + switch (marginStyle.style) { case MarginType::Back: colour = vs.styles[StyleDefault].back; break; case MarginType::Fore: colour = vs.styles[StyleDefault].fore; break; case MarginType::Colour: - colour = vs.ms[margin].back; + colour = marginStyle.back; break; default: colour = vs.styles[StyleLineNumber].back; break; } - surface->FillRectangle(rcSelMargin, colour); + surface->FillRectangle(rcOneMargin, colour); } } else { - surface->FillRectangle(rcSelMargin, vs.styles[StyleLineNumber].back); + surface->FillRectangle(rcOneMargin, vs.styles[StyleLineNumber].back); }
- const Sci::Line lineStartPaint = static_castSci::Line(rcMargin.top + ptOrigin.y) / vs.lineHeight; - Sci::Line visibleLine = model.TopLineOfMain() + lineStartPaint; - Sci::Position yposScreen = lineStartPaint * vs.lineHeight - static_castSci::Position(ptOrigin.y); - // Work out whether the top line is whitespace located after a - // lessening of fold level which implies a 'fold tail' but which should not - // be displayed until the last of a sequence of whitespace. - bool needWhiteClosure = false; - if (vs.ms[margin].ShowsFolding()) { - const FoldLevel level = model.pdoc->GetFoldLevel(model.pcs->DocFromDisplay(visibleLine)); - if (LevelIsWhitespace(level)) { - Sci::Line lineBack = model.pcs->DocFromDisplay(visibleLine); - FoldLevel levelPrev = level; - while ((lineBack > 0) && LevelIsWhitespace(levelPrev)) { - lineBack--; - levelPrev = model.pdoc->GetFoldLevel(lineBack); - } - if (!LevelIsHeader(levelPrev)) { - if (LevelNumber(level) < LevelNumber(levelPrev)) - needWhiteClosure = true; - } - } - if (highlightDelimiter.isEnabled) { - const Sci::Line lastLine = model.pcs->DocFromDisplay(topLine + model.LinesOnScreen()) + 1; - model.pdoc->GetHighlightDelimiters(highlightDelimiter, - model.pdoc->SciLineFromPosition(model.sel.MainCaret()), lastLine); - } + if (marginStyle.ShowsFolding() && highlightDelimiter.isEnabled) { + const Sci::Line lastLine = model.pcs->DocFromDisplay(topLine + model.LinesOnScreen()) + 1; + model.pdoc->GetHighlightDelimiters(highlightDelimiter, + model.pdoc->SciLineFromPosition(model.sel.MainCaret()), lastLine); }
- // Old code does not know about new markers needed to distinguish all cases - const MarkerOutline folderOpenMid = SubstituteMarkerIfEmpty(MarkerOutline::FolderOpenMid, - MarkerOutline::FolderOpen, vs); - const MarkerOutline folderEnd = SubstituteMarkerIfEmpty(MarkerOutline::FolderEnd, - MarkerOutline::Folder, vs); - - while ((visibleLine < model.pcs->LinesDisplayed()) && yposScreen < rc.bottom) { - - PLATFORM_ASSERT(visibleLine < model.pcs->LinesDisplayed()); - const Sci::Line lineDoc = model.pcs->DocFromDisplay(visibleLine); - PLATFORM_ASSERT(model.pcs->GetVisible(lineDoc)); - const Sci::Line firstVisibleLine = model.pcs->DisplayFromDoc(lineDoc); - const Sci::Line lastVisibleLine = model.pcs->DisplayLastFromDoc(lineDoc); - const bool firstSubLine = visibleLine == firstVisibleLine; - const bool lastSubLine = visibleLine == lastVisibleLine; - - int marks = model.pdoc->GetMark(lineDoc); - if (!firstSubLine) - marks = 0; - - bool headWithTail = false; - - if (vs.ms[margin].ShowsFolding()) { - // Decide which fold indicator should be displayed - const FoldLevel level = model.pdoc->GetFoldLevel(lineDoc); - const FoldLevel levelNext = model.pdoc->GetFoldLevel(lineDoc + 1); - const FoldLevel levelNum = LevelNumberPart(level); - const FoldLevel levelNextNum = LevelNumberPart(levelNext); - if (LevelIsHeader(level)) { - if (firstSubLine) { - if (levelNum < levelNextNum) { - if (model.pcs->GetExpanded(lineDoc)) { - if (levelNum == FoldLevel::Base) - marks |= 1 << MarkerOutline::FolderOpen; - else - marks |= 1 << folderOpenMid; - } else { - if (levelNum == FoldLevel::Base) - marks |= 1 << MarkerOutline::Folder; - else - marks |= 1 << folderEnd; - } - } else if (levelNum > FoldLevel::Base) { - marks |= 1 << MarkerOutline::FolderSub; - } - } else { - if (levelNum < levelNextNum) { - if (model.pcs->GetExpanded(lineDoc)) { - marks |= 1 << MarkerOutline::FolderSub; - } else if (levelNum > FoldLevel::Base) { - marks |= 1 << MarkerOutline::FolderSub; - } - } else if (levelNum > FoldLevel::Base) { - marks |= 1 << MarkerOutline::FolderSub; - } - } - needWhiteClosure = false; - const Sci::Line firstFollowupLine = model.pcs->DocFromDisplay(model.pcs->DisplayFromDoc(lineDoc + 1)); - const FoldLevel firstFollowupLineLevel = model.pdoc->GetFoldLevel(firstFollowupLine); - const FoldLevel secondFollowupLineLevelNum = LevelNumberPart(model.pdoc->GetFoldLevel(firstFollowupLine + 1)); - if (!model.pcs->GetExpanded(lineDoc)) { - if (LevelIsWhitespace(firstFollowupLineLevel) && - (levelNum > secondFollowupLineLevelNum)) - needWhiteClosure = true; - - if (highlightDelimiter.IsFoldBlockHighlighted(firstFollowupLine)) - headWithTail = true; - } - } else if (LevelIsWhitespace(level)) { - if (needWhiteClosure) { - if (LevelIsWhitespace(levelNext)) { - marks |= 1 << MarkerOutline::FolderSub; - } else if (levelNextNum > FoldLevel::Base) { - marks |= 1 << MarkerOutline::FolderMidTail; - needWhiteClosure = false; - } else { - marks |= 1 << MarkerOutline::FolderTail; - needWhiteClosure = false; - } - } else if (levelNum > FoldLevel::Base) { - if (levelNextNum < levelNum) { - if (levelNextNum > FoldLevel::Base) { - marks |= 1 << MarkerOutline::FolderMidTail; - } else { - marks |= 1 << MarkerOutline::FolderTail; - } - } else { - marks |= 1 << MarkerOutline::FolderSub; - } - } - } else if (levelNum > FoldLevel::Base) { - if (levelNextNum < levelNum) { - needWhiteClosure = false; - if (LevelIsWhitespace(levelNext)) { - marks |= 1 << MarkerOutline::FolderSub; - needWhiteClosure = true; - } else if (lastSubLine) { - if (levelNextNum > FoldLevel::Base) { - marks |= 1 << MarkerOutline::FolderMidTail; - } else { - marks |= 1 << MarkerOutline::FolderTail; - } - } else { - marks |= 1 << MarkerOutline::FolderSub; - } - } else { - marks |= 1 << MarkerOutline::FolderSub; - } - } - } - - marks &= vs.ms[margin].mask; - - const PRectangle rcMarker( - rcSelMargin.left, - static_cast<XYPOSITION>(yposScreen), - rcSelMargin.right, - static_cast<XYPOSITION>(yposScreen + vs.lineHeight)); - if (vs.ms[margin].style == MarginType::Number) { - if (firstSubLine) { - std::string sNumber; - if (lineDoc >= 0) { - sNumber = std::to_string(lineDoc + 1); - } - if (FlagSet(model.foldFlags, (FoldFlag::LevelNumbers | FoldFlag::LineState))) { - char number[100] = ""; - if (FlagSet(model.foldFlags, FoldFlag::LevelNumbers)) { - const FoldLevel lev = model.pdoc->GetFoldLevel(lineDoc); - sprintf(number, "%c%c %03X %03X", - LevelIsHeader(lev) ? 'H' : '_', - LevelIsWhitespace(lev) ? 'W' : '_', - LevelNumber(lev), - static_cast<int>(lev) >> 16 - ); - } else { - const int state = model.pdoc->GetLineState(lineDoc); - sprintf(number, "%0X", state); - } - sNumber = number; - } - PRectangle rcNumber = rcMarker; - // Right justify - const XYPOSITION width = surface->WidthText(fontLineNumber, sNumber); - const XYPOSITION xpos = rcNumber.right - width - vs.marginNumberPadding; - rcNumber.left = xpos; - DrawTextNoClipPhase(surface, rcNumber, vs.styles[StyleLineNumber], - rcNumber.top + vs.maxAscent, sNumber, DrawPhase::all); - } else if (FlagSet(vs.wrap.visualFlags, WrapVisualFlag::Margin)) { - PRectangle rcWrapMarker = rcMarker; - rcWrapMarker.right -= wrapMarkerPaddingRight; - rcWrapMarker.left = rcWrapMarker.right - vs.styles[StyleLineNumber].aveCharWidth; - if (!customDrawWrapMarker) { - DrawWrapMarker(surface, rcWrapMarker, false, vs.styles[StyleLineNumber].fore); - } else { - customDrawWrapMarker(surface, rcWrapMarker, false, vs.styles[StyleLineNumber].fore); - } - } - } else if (vs.ms[margin].style == MarginType::Text || vs.ms[margin].style == MarginType::RText) { - const StyledText stMargin = model.pdoc->MarginStyledText(lineDoc); - if (stMargin.text && ValidStyledText(vs, vs.marginStyleOffset, stMargin)) { - if (firstSubLine) { - surface->FillRectangle(rcMarker, - vs.styles[stMargin.StyleAt(0) + vs.marginStyleOffset].back); - PRectangle rcText = rcMarker; - if (vs.ms[margin].style == MarginType::RText) { - const int width = WidestLineWidth(surface, vs, vs.marginStyleOffset, stMargin); - rcText.left = rcText.right - width - 3; - } - DrawStyledText(surface, vs, vs.marginStyleOffset, rcText, - stMargin, 0, stMargin.length, DrawPhase::all); - } else { - // if we're displaying annotation lines, colour the margin to match the associated document line - const int annotationLines = model.pdoc->AnnotationLines(lineDoc); - if (annotationLines && (visibleLine > lastVisibleLine - annotationLines)) { - surface->FillRectangle(rcMarker, vs.styles[stMargin.StyleAt(0) + vs.marginStyleOffset].back); - } - } - } - } - - if (marks) { - for (int markBit = 0; (markBit < 32) && marks; markBit++) { - if (marks & 1) { - LineMarker::FoldPart part = LineMarker::FoldPart::undefined; - if (vs.ms[margin].ShowsFolding() && highlightDelimiter.IsFoldBlockHighlighted(lineDoc)) { - if (highlightDelimiter.IsBodyOfFoldBlock(lineDoc)) { - part = LineMarker::FoldPart::body; - } else if (highlightDelimiter.IsHeadOfFoldBlock(lineDoc)) { - if (firstSubLine) { - part = headWithTail ? LineMarker::FoldPart::headWithTail : LineMarker::FoldPart::head; - } else { - if (model.pcs->GetExpanded(lineDoc) || headWithTail) { - part = LineMarker::FoldPart::body; - } else { - part = LineMarker::FoldPart::undefined; - } - } - } else if (highlightDelimiter.IsTailOfFoldBlock(lineDoc)) { - part = LineMarker::FoldPart::tail; - } - } - vs.markers[markBit].Draw(surface, rcMarker, fontLineNumber, part, vs.ms[margin].style); - } - marks >>= 1; - } - } - - visibleLine++; - yposScreen += vs.lineHeight; - } + PaintOneMargin(surface, rc, rcOneMargin, marginStyle, model, vs); } }
PRectangle rcBlankMargin = rcMargin; - rcBlankMargin.left = rcSelMargin.right; + rcBlankMargin.left = rcOneMargin.right; surface->FillRectangle(rcBlankMargin, vs.styles[StyleDefault].back); }
Modified: scintilla/src/MarginView.h 2 lines changed, 2 insertions(+), 0 deletions(-) =================================================================== @@ -36,6 +36,8 @@ class MarginView {
void DropGraphics() noexcept; void RefreshPixMaps(Surface *surfaceWindow, const ViewStyle &vsDraw); + void PaintOneMargin(Surface *surface, PRectangle rc, PRectangle rcMargin, const MarginStyle &marginStyle, + const EditModel &model, const ViewStyle &vs); void PaintMargin(Surface *surface, Sci::Line topLine, PRectangle rc, PRectangle rcMargin, const EditModel &model, const ViewStyle &vs); };
Modified: scintilla/src/PositionCache.cxx 98 lines changed, 72 insertions(+), 26 deletions(-) =================================================================== @@ -7,6 +7,7 @@
#include <cstddef> #include <cstdlib> +#include <cstdint> #include <cstring> #include <cmath>
@@ -71,7 +72,6 @@ LineLayout::LineLayout(Sci::Line lineNumber_, int maxLineLength_) : containsCaret(false), edgeColumn(0), bracePreviousStyles{}, - hotspot(0,0), widthLine(wrapWidthInfinite), lines(1), wrapIndent(0) { @@ -377,6 +377,14 @@ constexpr size_t AlignUp(size_t value, size_t alignment) noexcept {
constexpr size_t alignmentLLC = 20;
+constexpr bool GraphicASCII(char ch) noexcept { + return ch >= ' ' && ch <= '~'; +} + +bool AllGraphicASCII(std::string_view text) noexcept { + return std::all_of(text.cbegin(), text.cend(), GraphicASCII); +} + }
@@ -533,8 +541,10 @@ std::shared_ptr<LineLayout> LineLayoutCache::Retrieve(Sci::Line lineNumber, Sci: return std::make_shared<LineLayout>(lineNumber, maxChars); }
+namespace { + // Simply pack the (maximum 4) character bytes into an int -static unsigned int KeyFromString(std::string_view charBytes) noexcept { +constexpr unsigned int KeyFromString(std::string_view charBytes) noexcept { PLATFORM_ASSERT(charBytes.length() <= 4); unsigned int k=0; for (size_t i=0; i < charBytes.length(); i++) { @@ -545,14 +555,21 @@ static unsigned int KeyFromString(std::string_view charBytes) noexcept { return k; }
+constexpr unsigned int representationKeyCrLf = KeyFromString("\r\n"); + +} + void SpecialRepresentations::SetRepresentation(std::string_view charBytes, std::string_view value) { if ((charBytes.length() <= 4) && (value.length() <= Representation::maxLength)) { const unsigned int key = KeyFromString(charBytes); - MapRepresentation::iterator it = mapReprs.find(key); + const MapRepresentation::iterator it = mapReprs.find(key); if (it == mapReprs.end()) { // New entry so increment for first byte const unsigned char ucStart = charBytes.empty() ? 0 : charBytes[0]; startByteHasReprs[ucStart]++; + if (key == representationKeyCrLf) { + crlf = true; + } } mapReprs[key] = Representation(value); } @@ -561,7 +578,7 @@ void SpecialRepresentations::SetRepresentation(std::string_view charBytes, std:: void SpecialRepresentations::SetRepresentationAppearance(std::string_view charBytes, RepresentationAppearance appearance) { if (charBytes.length() <= 4) { const unsigned int key = KeyFromString(charBytes); - MapRepresentation::iterator it = mapReprs.find(key); + const MapRepresentation::iterator it = mapReprs.find(key); if (it == mapReprs.end()) { // Not present so fail return; @@ -573,7 +590,7 @@ void SpecialRepresentations::SetRepresentationAppearance(std::string_view charBy void SpecialRepresentations::SetRepresentationColour(std::string_view charBytes, ColourRGBA colour) { if (charBytes.length() <= 4) { const unsigned int key = KeyFromString(charBytes); - MapRepresentation::iterator it = mapReprs.find(key); + const MapRepresentation::iterator it = mapReprs.find(key); if (it == mapReprs.end()) { // Not present so fail return; @@ -585,24 +602,33 @@ void SpecialRepresentations::SetRepresentationColour(std::string_view charBytes,
void SpecialRepresentations::ClearRepresentation(std::string_view charBytes) { if (charBytes.length() <= 4) { - MapRepresentation::iterator it = mapReprs.find(KeyFromString(charBytes)); + const unsigned int key = KeyFromString(charBytes); + const MapRepresentation::iterator it = mapReprs.find(key); if (it != mapReprs.end()) { mapReprs.erase(it); const unsigned char ucStart = charBytes.empty() ? 0 : charBytes[0]; startByteHasReprs[ucStart]--; + if (key == representationKeyCrLf) { + crlf = false; + } } } }
+const Representation *SpecialRepresentations::GetRepresentation(std::string_view charBytes) const { + const MapRepresentation::const_iterator it = mapReprs.find(KeyFromString(charBytes)); + if (it != mapReprs.end()) { + return &(it->second); + } + return nullptr; +} + const Representation *SpecialRepresentations::RepresentationFromCharacter(std::string_view charBytes) const { if (charBytes.length() <= 4) { const unsigned char ucStart = charBytes.empty() ? 0 : charBytes[0]; if (!startByteHasReprs[ucStart]) return nullptr; - MapRepresentation::const_iterator it = mapReprs.find(KeyFromString(charBytes)); - if (it != mapReprs.end()) { - return &(it->second); - } + return GetRepresentation(charBytes); } return nullptr; } @@ -612,14 +638,15 @@ bool SpecialRepresentations::Contains(std::string_view charBytes) const { const unsigned char ucStart = charBytes.empty() ? 0 : charBytes[0]; if (!startByteHasReprs[ucStart]) return false; - MapRepresentation::const_iterator it = mapReprs.find(KeyFromString(charBytes)); + const MapRepresentation::const_iterator it = mapReprs.find(KeyFromString(charBytes)); return it != mapReprs.end(); }
void SpecialRepresentations::Clear() { mapReprs.clear(); constexpr short none = 0; std::fill(startByteHasReprs, std::end(startByteHasReprs), none); + crlf = false; }
void BreakFinder::Insert(Sci::Position val) { @@ -694,16 +721,23 @@ TextSegment BreakFinder::Next() { const int prev = nextBreak; while (nextBreak < lineRange.end) { int charWidth = 1; - if (encodingFamily == EncodingFamily::unicode) - charWidth = UTF8DrawBytes(reinterpret_cast<unsigned char *>(&ll->chars[nextBreak]), - static_cast<int>(lineRange.end - nextBreak)); - else if (encodingFamily == EncodingFamily::dbcs) - charWidth = pdoc->DBCSDrawBytes( - std::string_view(&ll->chars[nextBreak], lineRange.end - nextBreak)); - // Special case \r\n line ends if there is a representation - if (preprs->Contains("\r\n") && ll->chars[nextBreak] == '\r' && ll->chars[nextBreak + 1] == '\n') - charWidth = 2; - const Representation *repr = preprs->RepresentationFromCharacter(std::string_view(&ll->chars[nextBreak], charWidth)); + const char * const chars = &ll->chars[nextBreak]; + const unsigned char ch = chars[0]; + if (!UTF8IsAscii(ch) && encodingFamily != EncodingFamily::eightBit) { + if (encodingFamily == EncodingFamily::unicode) { + charWidth = UTF8DrawBytes(reinterpret_cast<const unsigned char *>(chars), static_cast<int>(lineRange.end - nextBreak)); + } else { + charWidth = pdoc->DBCSDrawBytes(std::string_view(chars, lineRange.end - nextBreak)); + } + } + const Representation *repr = nullptr; + if (preprs->MayContain(ch)) { + // Special case \r\n line ends if there is a representation + if (ch == '\r' && preprs->ContainsCrLf() && chars[1] == '\n') { + charWidth = 2; + } + repr = preprs->GetRepresentation(std::string_view(chars, charWidth)); + } if (((nextBreak > 0) && (ll->styles[nextBreak] != ll->styles[nextBreak - 1])) || repr || (nextBreak == saeNext)) { @@ -768,10 +802,10 @@ PositionCacheEntry::PositionCacheEntry(const PositionCacheEntry &other) : }
void PositionCacheEntry::Set(unsigned int styleNumber_, std::string_view sv, - const XYPOSITION *positions_, unsigned int clock_) { + const XYPOSITION *positions_, uint16_t clock_) { Clear(); - styleNumber = styleNumber_; - len = static_cast<unsigned int>(sv.length()); + styleNumber = static_cast<uint16_t>(styleNumber_); + len = static_cast<uint16_t>(sv.length()); clock = clock_; if (sv.data() && positions_) { positions = std::make_unique<XYPOSITION[]>(len + (len / sizeof(XYPOSITION)) + 1); @@ -848,7 +882,17 @@ size_t PositionCache::GetSize() const noexcept {
void PositionCache::MeasureWidths(Surface *surface, const ViewStyle &vstyle, unsigned int styleNumber, std::string_view sv, XYPOSITION *positions) { - allClear = false; + const Style &style = vstyle.styles[styleNumber]; + if (style.monospaceASCII) { + if (AllGraphicASCII(sv)) { + const XYPOSITION monospaceCharacterWidth = style.monospaceCharacterWidth; + for (size_t i = 0; i < sv.length(); i++) { + positions[i] = monospaceCharacterWidth * (i+1); + } + return; + } + } + size_t probe = pces.size(); // Out of bounds if ((!pces.empty()) && (sv.length() < 30)) { // Only store short strings in the cache so it doesn't churn with @@ -869,7 +913,8 @@ void PositionCache::MeasureWidths(Surface *surface, const ViewStyle &vstyle, uns probe = probe2; } } - const Font *fontStyle = vstyle.styles[styleNumber].font.get(); + + const Font *fontStyle = style.font.get(); surface->MeasureWidths(fontStyle, sv, positions); if (probe < pces.size()) { // Store into cache @@ -882,6 +927,7 @@ void PositionCache::MeasureWidths(Surface *surface, const ViewStyle &vstyle, uns } clock = 2; } + allClear = false; pces[probe].Set(styleNumber, sv, positions, clock); } }
Modified: scintilla/src/PositionCache.h 21 lines changed, 13 insertions(+), 8 deletions(-) =================================================================== @@ -79,9 +79,6 @@ class LineLayout {
std::unique_ptr<BidiData> bidiData;
- // Hotspot support - Range hotspot; - // Wrapped line support int widthLine; int lines; @@ -175,9 +172,9 @@ class LineLayoutCache { };
class PositionCacheEntry { - unsigned int styleNumber:8; - unsigned int len:8; - unsigned int clock:16; + uint16_t styleNumber; + uint16_t len; + uint16_t clock; std::unique_ptr<XYPOSITION []> positions; public: PositionCacheEntry() noexcept; @@ -188,7 +185,7 @@ class PositionCacheEntry { void operator=(const PositionCacheEntry &) = delete; void operator=(PositionCacheEntry &&) = delete; ~PositionCacheEntry(); - void Set(unsigned int styleNumber_, std::string_view sv, const XYPOSITION *positions_, unsigned int clock_); + void Set(unsigned int styleNumber_, std::string_view sv, const XYPOSITION *positions_, uint16_t clock_); void Clear() noexcept; bool Retrieve(unsigned int styleNumber_, std::string_view sv, XYPOSITION *positions_) const noexcept; static size_t Hash(unsigned int styleNumber_, std::string_view sv) noexcept; @@ -212,13 +209,21 @@ typedef std::map<unsigned int, Representation> MapRepresentation; class SpecialRepresentations { MapRepresentation mapReprs; short startByteHasReprs[0x100] {}; + bool crlf = false; public: void SetRepresentation(std::string_view charBytes, std::string_view value); void SetRepresentationAppearance(std::string_view charBytes, RepresentationAppearance appearance); void SetRepresentationColour(std::string_view charBytes, ColourRGBA colour); void ClearRepresentation(std::string_view charBytes); + const Representation *GetRepresentation(std::string_view charBytes) const; const Representation *RepresentationFromCharacter(std::string_view charBytes) const; bool Contains(std::string_view charBytes) const; + bool ContainsCrLf() const noexcept { + return crlf; + } + bool MayContain(unsigned char ch) const noexcept { + return startByteHasReprs[ch] != 0; + } void Clear(); };
@@ -268,7 +273,7 @@ class BreakFinder {
class PositionCache { std::vector<PositionCacheEntry> pces; - unsigned int clock; + uint16_t clock; bool allClear; public: PositionCache();
Modified: scintilla/src/RESearch.cxx 4 lines changed, 0 insertions(+), 4 deletions(-) =================================================================== @@ -260,10 +260,6 @@ RESearch::RESearch(CharClassify *charClassTable) { Clear(); }
-RESearch::~RESearch() { - Clear(); -} - void RESearch::Clear() noexcept { for (int i = 0; i < MAXTAG; i++) { pat[i].clear();
Modified: scintilla/src/RESearch.h 1 lines changed, 0 insertions(+), 1 deletions(-) =================================================================== @@ -23,7 +23,6 @@ class RESearch { public: explicit RESearch(CharClassify *charClassTable); // No dynamic allocation so default copy constructor and assignment operator are OK. - ~RESearch(); void Clear() noexcept; void GrabMatches(const CharacterIndexer &ci); const char *Compile(const char *pattern, Sci::Position length, bool caseSensitive, bool posix) noexcept;
Modified: scintilla/src/ScintillaBase.cxx 34 lines changed, 3 insertions(+), 31 deletions(-) =================================================================== @@ -7,6 +7,7 @@
#include <cstddef> #include <cstdlib> +#include <cstdint> #include <cassert> #include <cstring>
@@ -550,13 +551,8 @@ namespace Scintilla::Internal { class LexState : public LexInterface { public: explicit LexState(Document *pdoc_) noexcept; - void SetInstance(ILexer5 *instance_); - // Deleted so LexState objects can not be copied. - LexState(const LexState &) = delete; - LexState(LexState &&) = delete; - LexState &operator=(const LexState &) = delete; - LexState &operator=(LexState &&) = delete; - ~LexState() override; + + // LexInterface deleted the standard operators and defined the virtual destructor so don't need to here.
const char *DescribeWordListSets(); void SetWordList(int n, const char *wl); @@ -592,30 +588,6 @@ class LexState : public LexInterface { LexState::LexState(Document *pdoc_) noexcept : LexInterface(pdoc_) { }
-LexState::~LexState() { - if (instance) { - try { - instance->Release(); - } catch (...) { - // ILexer5::Release must not throw, ignore if it does. - } - instance = nullptr; - } -} - -void LexState::SetInstance(ILexer5 *instance_) { - if (instance) { - try { - instance->Release(); - } catch (...) { - // ILexer5::Release must not throw, ignore if it does. - } - instance = nullptr; - } - instance = instance_; - pdoc->LexerChanged(); -} - LexState *ScintillaBase::DocumentLexState() { if (!pdoc->GetLexInterface()) { pdoc->SetLexInterface(std::make_unique<LexState>(pdoc));
Modified: scintilla/src/Selection.cxx 3 lines changed, 0 insertions(+), 3 deletions(-) =================================================================== @@ -194,9 +194,6 @@ Selection::Selection() : mainRange(0), moveExtends(false), tentativeMai@@ Diff output truncated at 100000 characters. @@
-------------- This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).