Branch: refs/heads/master Author: Thomas Martitz thomas.martitz@mailbox.org Committer: GitHub noreply@github.com Date: Wed, 17 Nov 2021 15:12:03 UTC Commit: 5d4e7cfd5b12647b4cab9bda7278abd7f63e9c2f https://github.com/geany/geany/commit/5d4e7cfd5b12647b4cab9bda7278abd7f63e9c...
Log Message: ----------- Merge pull request #2930
Update to Scintilla 5.1.4 and Lexilla 5.1.3
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/lexers/LexPython.cxx scintilla/lexilla/lexers/LexRust.cxx scintilla/lexilla/lexlib/Accessor.h scintilla/lexilla/lexlib/LexerBase.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/CharClassify.cxx scintilla/src/CharacterType.h 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/PerLine.cxx 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/src/XPM.cxx scintilla/src/XPM.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 6 lines changed, 3 insertions(+), 3 deletions(-) =================================================================== @@ -114,7 +114,7 @@ class FontHandle : public Font { FontHandle(FontHandle &&) = delete; FontHandle &operator=(const FontHandle &) = delete; FontHandle &operator=(FontHandle &&) = delete; - ~FontHandle() { + ~FontHandle() override { if (pfd) pango_font_description_free(pfd); pfd = nullptr; @@ -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 70 lines changed, 48 insertions(+), 22 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,9 @@ ScintillaGTK::~ScintillaGTK() { } ClearPrimarySelection(); wPreedit.Destroy(); + if (settingsHandlerId) { + g_signal_handler_disconnect(settings, settingsHandlerId); + } }
void ScintillaGTK::RealizeThis(GtkWidget *widget) { @@ -341,6 +359,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 +696,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; } @@ -1277,7 +1300,7 @@ struct CaseMapper { }
std::string ScintillaGTK::CaseMapString(const std::string &s, CaseMapping caseMapping) { - if ((s.size() == 0) || (caseMapping == CaseMapping::same)) + if (s.empty() || (caseMapping == CaseMapping::same)) return s;
if (IsUnicodeMode()) { @@ -1540,20 +1563,26 @@ void ScintillaGTK::GetGtkSelectionText(GtkSelectionData *selectionData, Selectio
void ScintillaGTK::InsertSelection(GtkClipboard *clipBoard, GtkSelectionData *selectionData) { const gint length = gtk_selection_data_get_length(selectionData); + const GdkAtom selection = gtk_selection_data_get_selection(selectionData); if (length >= 0) { - GdkAtom selection = gtk_selection_data_get_selection(selectionData); SelectionText selText; GetGtkSelectionText(selectionData, selText);
UndoGroup ug(pdoc); if (selection == GDK_SELECTION_CLIPBOARD) { ClearSelection(multiPasteMode == MultiPaste::Each); } + if (selection == GDK_SELECTION_PRIMARY) { + SetSelection(posPrimary, posPrimary); + }
InsertPasteShape(selText.Data(), selText.Length(), selText.rectangular ? PasteShape::rectangular : PasteShape::stream); EnsureCaretVisible(); } else { + if (selection == GDK_SELECTION_PRIMARY) { + SetSelection(posPrimary, posPrimary); + } GdkAtom target = gtk_selection_data_get_target(selectionData); if (target == atomUTF8) { // In case data is actually only stored as text/plain;charset=utf-8 not UTF8_STRING @@ -1627,7 +1656,7 @@ void ScintillaGTK::GetSelection(GtkSelectionData *selection_data, guint info, Se std::unique_ptr<SelectionText> newline_normalized; { std::string tmpstr = Document::TransformLineEnds(text->Data(), text->Length(), EndOfLine::Lf); - newline_normalized.reset(new SelectionText()); + newline_normalized = std::make_unique<SelectionText>(); newline_normalized->Copy(tmpstr, CpUtf8, CharacterSet::Ansi, text->rectangular, false); text = newline_normalized.get(); } @@ -1854,12 +1883,11 @@ gint ScintillaGTK::PressThis(GdkEventButton *event) { ButtonDownWithModifiers(pt, event->time, ModifierFlags(shift, ctrl, alt, meta)); } else if (event->button == 2) { // Grab the primary selection if it exists - const SelectionPosition pos = SPositionFromLocation(pt, false, false, UserVirtualSpace()); + posPrimary = SPositionFromLocation(pt, false, false, UserVirtualSpace()); if (OwnPrimarySelection() && primary.Empty()) CopySelectionRange(&primary);
sel.Clear(); - SetSelection(pos, pos); RequestSelection(GDK_SELECTION_PRIMARY); } else if (event->button == 3) { if (!PointInSelection(pt)) @@ -2423,7 +2451,7 @@ std::vector<int> MapImeIndicators(PangoAttrList *attrs, const char *u8Str) { void ScintillaGTK::SetCandidateWindowPos() { // Composition box accompanies candidate box. const Point pt = PointMainCaret(); - GdkRectangle imeBox = {0}; // No need to set width + GdkRectangle imeBox {}; imeBox.x = static_cast<gint>(pt.x); imeBox.y = static_cast<gint>(pt.y + std::max(4, vs.lineHeight/4)); // prevent overlapping with current line @@ -2985,7 +3013,7 @@ gboolean ScintillaGTK::IdleCallback(gpointer pSci) { // Idler will be automatically stopped, if there is nothing // to do while idle. const bool ret = sciThis->Idle(); - if (ret == false) { + if (!ret) { // FIXME: This will remove the idler from GTK, we don't want to // remove it as it is removed automatically when this function // returns false (although, it should be harmless). @@ -3021,9 +3049,7 @@ void ScintillaGTK::SetDocPointer(Document *document) { sciAccessible = ScintillaGTKAccessible::FromAccessible(accessible); if (sciAccessible && pdoc) { oldDoc = pdoc; - if (oldDoc) { - oldDoc->AddRef(); - } + oldDoc->AddRef(); } }
Modified: scintilla/gtk/ScintillaGTK.h 6 lines changed, 5 insertions(+), 1 deletions(-) =================================================================== @@ -34,6 +34,7 @@ class ScintillaGTK : public ScintillaBase { int horizontalScrollBarHeight;
SelectionText primary; + SelectionPosition posPrimary;
GdkEvent *evbtn; guint buttonMouse; @@ -62,6 +63,9 @@ class ScintillaGTK : public ScintillaBase { GtkIMContext *im_context; GUnicodeScript lastNonCommonScript;
+ GtkSettings *settings; + gulong settingsHandlerId; + // Wheel mouse support unsigned int linesPerScroll; gint64 lastWheelMouseTime; @@ -89,7 +93,7 @@ class ScintillaGTK : public ScintillaBase { ScintillaGTK(ScintillaGTK &&) = delete; ScintillaGTK &operator=(const ScintillaGTK &) = delete; ScintillaGTK &operator=(ScintillaGTK &&) = delete; - virtual ~ScintillaGTK(); + ~ScintillaGTK() override; static ScintillaGTK *FromWidget(GtkWidget *widget) noexcept; static void ClassInit(OBJECT_CLASS *object_class, GtkWidgetClass *widget_class, GtkContainerClass *container_class); private:
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 7 lines changed, 7 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 @@ -901,6 +907,7 @@ typedef sptr_t (*SciFnDirectStatus)(sptr_t ptr, unsigned int iMessage, uptr_t wP #define CARETSTYLE_BLOCK 2 #define CARETSTYLE_OVERSTRIKE_BAR 0 #define CARETSTYLE_OVERSTRIKE_BLOCK 0x10 +#define CARETSTYLE_CURSES 0x20 #define CARETSTYLE_INS_MASK 0xF #define CARETSTYLE_BLOCK_AFTER 0x100 #define SCI_SETCARETSTYLE 2512
Modified: scintilla/include/Scintilla.iface 17 lines changed, 16 insertions(+), 1 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,)
@@ -2475,6 +2489,7 @@ val CARETSTYLE_LINE=1 val CARETSTYLE_BLOCK=2 val CARETSTYLE_OVERSTRIKE_BAR=0 val CARETSTYLE_OVERSTRIKE_BLOCK=0x10 +val CARETSTYLE_CURSES=0x20 val CARETSTYLE_INS_MASK=0xF val CARETSTYLE_BLOCK_AFTER=0x100
@@ -3113,7 +3128,7 @@ fun int DescribeKeyWordSets=4017(, stringresult descriptions)
# Bit set of LineEndType enumertion for which line ends beyond the standard # LF, CR, and CRLF are supported by the lexer. -get int GetLineEndTypesSupported=4018(,) +get LineEndType GetLineEndTypesSupported=4018(,)
# Allocate a set of sub styles for a particular base style, returning start of range fun int AllocateSubStyles=4020(int styleBase, int numberStyles)
Modified: scintilla/include/ScintillaCall.h 6 lines changed, 5 insertions(+), 1 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); @@ -850,7 +854,7 @@ class ScintillaCall { std::string DescribeProperty(const char *name); int DescribeKeyWordSets(char *descriptions); std::string DescribeKeyWordSets(); - int LineEndTypesSupported(); + Scintilla::LineEndType LineEndTypesSupported(); int AllocateSubStyles(int styleBase, int numberStyles); int SubStylesStart(int styleBase); int SubStylesLength(int styleBase);
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 3 lines changed, 3 insertions(+), 0 deletions(-) =================================================================== @@ -180,6 +180,8 @@ enum class Element { WhiteSpaceBack = 61, HotSpotActive = 70, HotSpotActiveBack = 71, + FoldLine = 80, + HiddenLine = 81, };
enum class Layer { @@ -437,6 +439,7 @@ enum class CaretStyle { Block = 2, OverstrikeBar = 0, OverstrikeBlock = 0x10, + Curses = 0x20, InsMask = 0xF, BlockAfter = 0x100, };
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/lexers/LexPython.cxx 21 lines changed, 11 insertions(+), 10 deletions(-) =================================================================== @@ -71,7 +71,7 @@ bool IsPyComment(Accessor &styler, Sci_Position pos, Sci_Position len) { return len > 0 && styler[pos] == '#'; }
-bool IsPyStringTypeChar(int ch, literalsAllowed allowed) noexcept { +constexpr bool IsPyStringTypeChar(int ch, literalsAllowed allowed) noexcept { return ((allowed & litB) && (ch == 'b' || ch == 'B')) || ((allowed & litU) && (ch == 'u' || ch == 'U')) || @@ -93,17 +93,17 @@ bool IsPyStringStart(int ch, int chNext, int chNext2, literalsAllowed allowed) n return false; }
-bool IsPyFStringState(int st) noexcept { +constexpr bool IsPyFStringState(int st) noexcept { return ((st == SCE_P_FCHARACTER) || (st == SCE_P_FSTRING) || (st == SCE_P_FTRIPLE) || (st == SCE_P_FTRIPLEDOUBLE)); }
-bool IsPySingleQuoteStringState(int st) noexcept { +constexpr bool IsPySingleQuoteStringState(int st) noexcept { return ((st == SCE_P_CHARACTER) || (st == SCE_P_STRING) || (st == SCE_P_FCHARACTER) || (st == SCE_P_FSTRING)); }
-bool IsPyTripleQuoteStringState(int st) noexcept { +constexpr bool IsPyTripleQuoteStringState(int st) noexcept { return ((st == SCE_P_TRIPLE) || (st == SCE_P_TRIPLEDOUBLE) || (st == SCE_P_FTRIPLE) || (st == SCE_P_FTRIPLEDOUBLE)); } @@ -232,7 +232,7 @@ struct OptionsPython { bool foldCompact; bool unicodeIdentifiers;
- OptionsPython() { + OptionsPython() noexcept { whingeLevel = 0; base2or8Literals = true; stringsU = true; @@ -436,6 +436,8 @@ Sci_Position SCI_METHOD LexerPython::WordListSet(int n, const char *wl) { case 1: wordListN = &keywords2; break; + default: + break; } Sci_Position firstModification = -1; if (wordListN) { @@ -635,7 +637,7 @@ void SCI_METHOD LexerPython::Lex(Sci_PositionU startPos, Sci_Position length, in style = SCE_P_WORD2; } } else { - int subStyle = classifierIdentifiers.ValueFor(s); + const int subStyle = classifierIdentifiers.ValueFor(s); if (subStyle >= 0) { style = subStyle; } @@ -895,8 +897,8 @@ void SCI_METHOD LexerPython::Fold(Sci_PositionU startPos, Sci_Position length, i const int style = styler.StyleAt(lookAtPos) & 31; quote = options.foldQuotes && IsPyTripleQuoteStringState(style); } - const int quote_start = (quote && !prevQuote); - const int quote_continue = (quote && prevQuote); + const bool quote_start = (quote && !prevQuote); + const bool quote_continue = (quote && prevQuote); if (!quote || !prevQuote) indentCurrentLevel = indentCurrent & SC_FOLDLEVELNUMBERMASK; if (quote) @@ -921,8 +923,7 @@ void SCI_METHOD LexerPython::Fold(Sci_PositionU startPos, Sci_Position length, i int minCommentLevel = indentCurrentLevel; while (!quote && (lineNext < docLines) && - ((indentNext & SC_FOLDLEVELWHITEFLAG) || - (lineNext <= docLines && IsCommentLine(lineNext, styler)))) { + ((indentNext & SC_FOLDLEVELWHITEFLAG) || (IsCommentLine(lineNext, styler)))) {
if (IsCommentLine(lineNext, styler) && indentNext < minCommentLevel) { minCommentLevel = indentNext;
Modified: scintilla/lexilla/lexers/LexRust.cxx 12 lines changed, 5 insertions(+), 7 deletions(-) =================================================================== @@ -286,6 +286,8 @@ static void ScanNumber(Accessor& styler, Sci_Position& pos) { pos += 2; } else if (c == '6' && n == '4') { pos += 2; + } else if (styler.Match(pos, "128")) { + pos += 3; } else if (styler.Match(pos, "size")) { pos += 4; } else { @@ -524,7 +526,7 @@ static void ResumeBlockComment(Accessor &styler, Sci_Position& pos, Sci_Position level++; } } - else { + else if (pos < max) { pos++; } if (pos >= max) { @@ -557,12 +559,8 @@ static void ResumeLineComment(Accessor &styler, Sci_Position& pos, Sci_Position maybe_doc_comment = true; }
- while (pos < max && c != '\n') { - if (pos == styler.LineEnd(styler.GetLine(pos))) - styler.SetLineState(styler.GetLine(pos), 0); - pos++; - c = styler.SafeGetCharAt(pos, '\0'); - } + pos = styler.LineEnd(styler.GetLine(pos)); + styler.SetLineState(styler.GetLine(pos), SCE_RUST_DEFAULT);
if (state == DocComment || (state == UnknownComment && maybe_doc_comment)) styler.ColourTo(pos - 1, SCE_RUST_COMMENTLINEDOC);
Modified: scintilla/lexilla/lexlib/Accessor.h 2 lines changed, 1 insertions(+), 1 deletions(-) =================================================================== @@ -23,7 +23,7 @@ class Accessor : public LexAccessor { PropSetSimple *pprops; Accessor(Scintilla::IDocument *pAccess_, PropSetSimple *pprops_); int GetPropertyInt(std::string_view key, int defaultValue=0) const; - int IndentAmount(Sci_Position line, int *flags, PFNIsCommentLeader pfnIsCommentLeader = 0); + int IndentAmount(Sci_Position line, int *flags, PFNIsCommentLeader pfnIsCommentLeader = nullptr); };
}
Modified: scintilla/lexilla/lexlib/LexerBase.cxx 6 lines changed, 3 insertions(+), 3 deletions(-) =================================================================== @@ -31,15 +31,15 @@ LexerBase::LexerBase(const LexicalClass *lexClasses_, size_t nClasses_) : lexClasses(lexClasses_), nClasses(nClasses_) { for (int wl = 0; wl < numWordLists; wl++) keyWordLists[wl] = new WordList; - keyWordLists[numWordLists] = 0; + keyWordLists[numWordLists] = nullptr; }
LexerBase::~LexerBase() { for (int wl = 0; wl < numWordLists; wl++) { delete keyWordLists[wl]; - keyWordLists[wl] = 0; + keyWordLists[wl] = nullptr; } - keyWordLists[numWordLists] = 0; + keyWordLists[numWordLists] = nullptr; }
void SCI_METHOD LexerBase::Release() {
Modified: scintilla/lexilla/lexlib/WordList.cxx 93 lines changed, 38 insertions(+), 55 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; } @@ -71,84 +80,58 @@ WordList::~WordList() { }
WordList::operator bool() const noexcept { - return len ? true : false; + return len != 0; }
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; } @@ -161,7 +144,7 @@ bool WordList::Set(const char *s) { * so '^GTK_' matches 'GTK_X', 'GTK_MAJOR_VERSION', and 'GTK_'. */ bool WordList::InList(const char *s) const noexcept { - if (0 == words) + if (!words) return false; const unsigned char firstChar = s[0]; int j = starts[firstChar]; @@ -203,7 +186,7 @@ bool WordList::InList(const char *s) const noexcept { * The marker is ~ in this case. */ bool WordList::InListAbbreviated(const char *s, const char marker) const noexcept { - if (0 == words) + if (!words) return false; const unsigned char firstChar = s[0]; int j = starts[firstChar]; @@ -257,7 +240,7 @@ bool WordList::InListAbbreviated(const char *s, const char marker) const noexcep * No multiple markers check is done and wont work. */ bool WordList::InListAbridged(const char *s, const char marker) const noexcept { - if (0 == words) + if (!words) return false; const unsigned char firstChar = s[0]; int j = starts[firstChar];
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 +513
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 6 lines changed, 3 insertions(+), 3 deletions(-) =================================================================== @@ -37,7 +37,7 @@ struct CountWidths { // from the Base Multilingual Plane and those from other planes. Sci::Position countBasePlane; Sci::Position countOtherPlanes; - CountWidths(Sci::Position countBasePlane_=0, Sci::Position countOtherPlanes_=0) noexcept : + explicit CountWidths(Sci::Position countBasePlane_=0, Sci::Position countOtherPlanes_=0) noexcept : countBasePlane(countBasePlane_), countOtherPlanes(countOtherPlanes_) { } @@ -523,7 +523,7 @@ void UndoHistory::TentativeCommit() { }
bool UndoHistory::TentativeActive() const noexcept { - return tentativePoint >= 0; + return tentativePoint >= 0; }
int UndoHistory::TentativeSteps() noexcept { @@ -1286,7 +1286,7 @@ void CellBuffer::EndUndoAction() { }
void CellBuffer::AddUndoAction(Sci::Position token, bool mayCoalesce) { - bool startSequence; + bool startSequence = false; uh.AppendAction(ActionType::container, token, nullptr, 0, startSequence, mayCoalesce); }
Modified: scintilla/src/CharClassify.cxx 2 lines changed, 1 insertions(+), 1 deletions(-) =================================================================== @@ -24,7 +24,7 @@ void CharClassify::SetDefaultCharClasses(bool includeWordClass) { for (int ch = 0; ch < maxChar; ch++) { if (ch == '\r' || ch == '\n') charClass[ch] = CharacterClass::newLine; - else if (ch < 0x20 || ch == ' ') + else if (IsControl(ch) || ch == ' ') charClass[ch] = CharacterClass::space; else if (includeWordClass && (ch >= 0x80 || IsAlphaNumeric(ch) || ch == '_')) charClass[ch] = CharacterClass::word;
Modified: scintilla/src/CharacterType.h 84 lines changed, 57 insertions(+), 27 deletions(-) =================================================================== @@ -12,14 +12,33 @@ namespace Scintilla::Internal {
// Functions for classifying characters
+/** + * Check if a character is a space. + * This is ASCII specific but is safe with chars >= 0x80. + */ constexpr bool IsASpace(int ch) noexcept { return (ch == ' ') || ((ch >= 0x09) && (ch <= 0x0d)); }
-constexpr bool IsASpaceOrTab(int ch) noexcept { +constexpr bool IsSpaceOrTab(int ch) noexcept { return (ch == ' ') || (ch == '\t'); }
+constexpr bool IsControl(int ch) noexcept { + return ((ch >= 0) && (ch <= 0x1F)) || (ch == 0x7F); +} + +constexpr bool IsEOLCharacter(int ch) noexcept { + return ch == '\r' || ch == '\n'; +} + +constexpr bool IsBreakSpace(int ch) noexcept { + // used for text breaking, treat C0 control character as space. + // by default C0 control character is handled as special representation, + // so not appears in normal text. 0x7F DEL is omitted to simplify the code. + return ch >= 0 && ch <= ' '; +} + constexpr bool IsADigit(int ch) noexcept { return (ch >= '0') && (ch <= '9'); } @@ -57,33 +76,44 @@ constexpr bool IsAlphaNumeric(int ch) noexcept { ((ch >= 'A') && (ch <= 'Z')); }
-/** - * Check if a character is a space. - * This is ASCII specific but is safe with chars >= 0x80. - */ -constexpr bool isspacechar(int ch) noexcept { - return (ch == ' ') || ((ch >= 0x09) && (ch <= 0x0d)); -} - -constexpr bool iswordchar(int ch) noexcept { - return IsAlphaNumeric(ch) || ch == '.' || ch == '_'; -} - -constexpr bool iswordstart(int ch) noexcept { - return IsAlphaNumeric(ch) || ch == '_'; -} - -constexpr bool isoperator(int ch) noexcept { - if (IsAlphaNumeric(ch)) - return false; - if (ch == '%' || ch == '^' || ch == '&' || ch == '*' || - ch == '(' || ch == ')' || ch == '-' || ch == '+' || - ch == '=' || ch == '|' || ch == '{' || ch == '}' || - ch == '[' || ch == ']' || ch == ':' || ch == ';' || - ch == '<' || ch == '>' || ch == ',' || ch == '/' || - ch == '?' || ch == '!' || ch == '.' || ch == '~') +constexpr bool IsPunctuation(int ch) noexcept { + switch (ch) { + case '!': + case '"': + case '#': + case '$': + case '%': + case '&': + case ''': + case '(': + case ')': + case '*': + case '+': + case ',': + case '-': + case '.': + case '/': + case ':': + case ';': + case '<': + case '=': + case '>': + case '?': + case '@': + case '[': + case '\': + case ']': + case '^': + case '_': + case '`': + case '{': + case '|': + case '}': + case '~': return true; - return false; + default: + return false; + } }
// Simple case functions for ASCII supersets.
Modified: scintilla/src/ContractionState.cxx 6 lines changed, 2 insertions(+), 4 deletions(-) =================================================================== @@ -95,9 +95,7 @@ ContractionState<LINE>::ContractionState() noexcept : linesInDocument(1) { }
template <typename LINE> -ContractionState<LINE>::~ContractionState() { - Clear(); -} +ContractionState<LINE>::~ContractionState() = default;
template <typename LINE> void ContractionState<LINE>::EnsureData() { @@ -197,7 +195,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 211 lines changed, 98 insertions(+), 113 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_) { } @@ -1113,53 +1127,74 @@ bool Document::IsDBCSDualByteAt(Sci::Position pos) const noexcept { && IsDBCSTrailByteNoExcept(cb.CharAt(pos + 1)); }
-static constexpr bool IsSpaceOrTab(int ch) noexcept { - return ch == ' ' || ch == '\t'; -} - -// Need to break text into segments near lengthSegment but taking into -// account the encoding to not break inside a UTF-8 or DBCS character -// and also trying to avoid breaking inside a pair of combining characters. +// Need to break text into segments near end but taking into account the +// encoding to not break inside a UTF-8 or DBCS character and also trying +// to avoid breaking inside a pair of combining characters, or inside +// ligatures. +// TODO: implement grapheme cluster boundaries, +// see https://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries. +// // The segment length must always be long enough (more than 4 bytes) // so that there will be at least one whole character to make a segment. // For UTF-8, text must consist only of valid whole characters. // In preference order from best to worst: -// 1) Break after space -// 2) Break before punctuation -// 3) Break after whole character - -int Document::SafeSegment(const char *text, int length, int lengthSegment) const noexcept { - if (length <= lengthSegment) - return length; - int lastSpaceBreak = -1; - int lastPunctuationBreak = -1; - int lastEncodingAllowedBreak = 0; - for (int j=0; j < lengthSegment;) { - const unsigned char ch = text[j]; - if (j > 0) { - if (IsSpaceOrTab(text[j - 1]) && !IsSpaceOrTab(text[j])) { - lastSpaceBreak = j; +// 1) Break before or after spaces or controls +// 2) Break at word and punctuation boundary for better kerning and ligature support +// 3) Break after whole character, this may break combining characters + +size_t Document::SafeSegment(std::string_view text) const noexcept { + // check space first as most written language use spaces. + for (std::string_view::iterator it = text.end() - 1; it != text.begin(); --it) { + if (IsBreakSpace(*it)) { + return it - text.begin(); + } + } + + if (!dbcsCodePage || dbcsCodePage == CpUtf8) { + // backward iterate for UTF-8 and single byte encoding to find word and punctuation boundary. + std::string_view::iterator it = text.end() - 1; + const bool punctuation = IsPunctuation(*it); + do { + --it; + if (punctuation != IsPunctuation(*it)) { + return it - text.begin() + 1; } - if (ch < 'A') { - lastPunctuationBreak = j; + } while (it != text.begin()); + + it = text.end() - 1; + if (dbcsCodePage) { + // for UTF-8 go back to the start of last character. + for (int trail = 0; trail < UTF8MaxBytes - 1 && UTF8IsTrailByte(*it); trail++) { + --it; } } - lastEncodingAllowedBreak = j; + return it - text.begin(); + }
- if (dbcsCodePage == CpUtf8) { - j += UTF8BytesOfLead[ch]; - } else if (dbcsCodePage) { - j += IsDBCSLeadByteNoExcept(ch) ? 2 : 1; - } else { - j++; + { + // forward iterate for DBCS to find word and punctuation boundary. + size_t lastPunctuationBreak = 0; + size_t lastEncodingAllowedBreak = 0; + CharacterClass ccPrev = CharacterClass::space; + for (size_t j = 0; j < text.length();) { + const unsigned char ch = text[j]; + lastEncodingAllowedBreak = j++; + + CharacterClass cc = CharacterClass::word; + if (UTF8IsAscii(ch)) { + if (IsPunctuation(ch)) { + cc = CharacterClass::punctuation; + } + } else { + j += IsDBCSLeadByteNoExcept(ch); + } + if (cc != ccPrev) { + ccPrev = cc; + lastPunctuationBreak = lastEncodingAllowedBreak; + } } + return lastPunctuationBreak ? lastPunctuationBreak : lastEncodingAllowedBreak; } - if (lastSpaceBreak >= 0) { - return lastSpaceBreak; - } else if (lastPunctuationBreak >= 0) { - return lastPunctuationBreak; - } - return lastEncodingAllowedBreak; }
EncodingFamily Document::CodePageFamily() const noexcept { @@ -1204,7 +1239,7 @@ bool Document::DeleteChars(Sci::Position pos, Sci::Position len) { DocModification( ModificationFlags::BeforeDelete | ModificationFlags::User, pos, len, - 0, 0)); + 0, nullptr)); const Sci::Line prevLinesTotal = LinesTotal(); const bool startSavePoint = cb.IsSavePoint(); bool startSequence = false; @@ -2067,7 +2102,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) { @@ -2405,7 +2440,7 @@ Sci::Line Document::GetMaxLineState() const noexcept {
void SCI_METHOD Document::ChangeLexerState(Sci_Position start, Sci_Position end) { const DocModification mh(ModificationFlags::LexerState, start, - end-start, 0, 0, 0); + end-start, 0, nullptr, 0); NotifyModified(mh); }
@@ -2418,20 +2453,20 @@ StyledText Document::MarginStyledText(Sci::Line line) const noexcept { void Document::MarginSetText(Sci::Line line, const char *text) { Margins()->SetText(line, text); const DocModification mh(ModificationFlags::ChangeMargin, LineStart(line), - 0, 0, 0, line); + 0, 0, nullptr, line); NotifyModified(mh); }
void Document::MarginSetStyle(Sci::Line line, int style) { Margins()->SetStyle(line, style); NotifyModified(DocModification(ModificationFlags::ChangeMargin, LineStart(line), - 0, 0, 0, line)); + 0, 0, nullptr, line)); }
void Document::MarginSetStyles(Sci::Line line, const unsigned char *styles) { Margins()->SetStyles(line, styles); NotifyModified(DocModification(ModificationFlags::ChangeMargin, LineStart(line), - 0, 0, 0, line)); + 0, 0, nullptr, line)); }
void Document::MarginClearAll() { @@ -2454,7 +2489,7 @@ void Document::AnnotationSetText(Sci::Line line, const char *text) { Annotations()->SetText(line, text); const int linesAfter = AnnotationLines(line); DocModification mh(ModificationFlags::ChangeAnnotation, LineStart(line), - 0, 0, 0, line); + 0, 0, nullptr, line); mh.annotationLinesAdded = linesAfter - linesBefore; NotifyModified(mh); } @@ -2464,7 +2499,7 @@ void Document::AnnotationSetStyle(Sci::Line line, int style) { if (line >= 0 && line < LinesTotal()) { Annotations()->SetStyle(line, style); const DocModification mh(ModificationFlags::ChangeAnnotation, LineStart(line), - 0, 0, 0, line); + 0, 0, nullptr, line); NotifyModified(mh); } } @@ -2497,7 +2532,7 @@ void Document::EOLAnnotationSetText(Sci::Line line, const char *text) { if (line >= 0 && line < LinesTotal()) { EOLAnnotations()->SetText(line, text); const DocModification mh(ModificationFlags::ChangeEOLAnnotation, LineStart(line), - 0, 0, 0, line); + 0, 0, nullptr, line); NotifyModified(mh); } } @@ -2506,7 +2541,7 @@ void Document::EOLAnnotationSetStyle(Sci::Line line, int style) { if (line >= 0 && line < LinesTotal()) { EOLAnnotations()->SetStyle(line, style); const DocModification mh(ModificationFlags::ChangeEOLAnnotation, LineStart(line), - 0, 0, 0, line); + 0, 0, nullptr, line); NotifyModified(mh); } } @@ -2586,49 +2621,8 @@ void Document::NotifyModified(DocModification mh) { } }
-// Used for word part navigation. -static bool IsASCIIPunctuationCharacter(unsigned int ch) noexcept { - switch (ch) { - case '!': - case '"': - case '#': - case '$': - case '%': - case '&': - case ''': - case '(': - case ')': - case '*': - case '+': - case ',': - case '-': - case '.': - case '/': - case ':': - case ';': - case '<': - case '=': - case '>': - case '?': - case '@': - case '[': - case '\': - case ']': - case '^': - case '_': - case '`': - case '{': - case '|': - case '}': - case '~': - return true; - default: - return false; - } -} - bool Document::IsWordPartSeparator(unsigned int ch) const { - return (WordCharacterClass(ch) == CharacterClass::word) && IsASCIIPunctuationCharacter(ch); + return (WordCharacterClass(ch) == CharacterClass::word) && IsPunctuation(ch); }
Sci::Position Document::WordPartLeft(Sci::Position pos) const { @@ -2658,15 +2652,15 @@ Sci::Position Document::WordPartLeft(Sci::Position pos) const { pos -= CharacterBefore(pos).widthBytes; if (!IsADigit(CharacterAfter(pos).character)) pos += CharacterAfter(pos).widthBytes; - } else if (IsASCIIPunctuationCharacter(ceStart.character)) { - while (pos > 0 && IsASCIIPunctuationCharacter(CharacterAfter(pos).character)) + } else if (IsPunctuation(ceStart.character)) { + while (pos > 0 && IsPunctuation(CharacterAfter(pos).character)) pos -= CharacterBefore(pos).widthBytes; - if (!IsASCIIPunctuationCharacter(CharacterAfter(pos).character)) + if (!IsPunctuation(CharacterAfter(pos).character)) pos += CharacterAfter(pos).widthBytes; - } else if (isspacechar(ceStart.character)) { - while (pos > 0 && isspacechar(CharacterAfter(pos).character)) + } else if (IsASpace(ceStart.character)) { + while (pos > 0 && IsASpace(CharacterAfter(pos).character)) pos -= CharacterBefore(pos).widthBytes; - if (!isspacechar(CharacterAfter(pos).character)) + if (!IsASpace(CharacterAfter(pos).character)) pos += CharacterAfter(pos).widthBytes; } else if (!IsASCII(ceStart.character)) { while (pos > 0 && !IsASCII(CharacterAfter(pos).character)) @@ -2709,30 +2703,26 @@ Sci::Position Document::WordPartRight(Sci::Position pos) const { } else if (IsADigit(ceStart.character)) { while (pos < length && IsADigit(CharacterAfter(pos).character)) pos += CharacterAfter(pos).widthBytes; - } else if (IsASCIIPunctuationCharacter(ceStart.character)) { - while (pos < length && IsASCIIPunctuationCharacter(CharacterAfter(pos).character)) + } else if (IsPunctuation(ceStart.character)) { + while (pos < length && IsPunctuation(CharacterAfter(pos).character)) pos += CharacterAfter(pos).widthBytes; - } else if (isspacechar(ceStart.character)) { - while (pos < length && isspacechar(CharacterAfter(pos).character)) + } else if (IsASpace(ceStart.character)) { + while (pos < length && IsASpace(CharacterAfter(pos).character)) pos += CharacterAfter(pos).widthBytes; } else { pos += CharacterAfter(pos).widthBytes; } return pos; }
-static constexpr bool IsLineEndChar(char c) noexcept { - return (c == '\n' || c == '\r'); -} - Sci::Position Document::ExtendStyleRange(Sci::Position pos, int delta, bool singleLine) noexcept { - const int sStart = cb.StyleAt(pos); + const char sStart = cb.StyleAt(pos); if (delta < 0) { - while (pos > 0 && (cb.StyleAt(pos) == sStart) && (!singleLine || !IsLineEndChar(cb.CharAt(pos)))) + while (pos > 0 && (cb.StyleAt(pos) == sStart) && (!singleLine || !IsEOLCharacter(cb.CharAt(pos)))) pos--; pos++; } else { - while (pos < (LengthNoExcept()) && (cb.StyleAt(pos) == sStart) && (!singleLine || !IsLineEndChar(cb.CharAt(pos)))) + while (pos < (LengthNoExcept()) && (cb.StyleAt(pos) == sStart) && (!singleLine || !IsEOLCharacter(cb.CharAt(pos)))) pos++; } return pos; @@ -2798,11 +2788,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, @@ -2977,7 +2962,7 @@ class UTF8Iterator { typedef wchar_t* pointer; typedef wchar_t& reference;
- UTF8Iterator(const Document *doc_=nullptr, Sci::Position position_=0) noexcept : + explicit UTF8Iterator(const Document *doc_=nullptr, Sci::Position position_=0) noexcept : doc(doc_), position(position_), characterIndex(0), lenBytes(0), lenCharacters(0), buffered{} { buffered[0] = 0; buffered[1] = 0; @@ -3199,7 +3184,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 40 lines changed, 30 insertions(+), 10 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 { @@ -332,7 +352,7 @@ class Document : PerLine, public Scintilla::IDocument, public Scintilla::ILoader bool IsDBCSTrailByteNoExcept(char ch) const noexcept; int DBCSDrawBytes(std::string_view text) const noexcept; bool IsDBCSDualByteAt(Sci::Position pos) const noexcept; - int SafeSegment(const char *text, int length, int lengthSegment) const noexcept; + size_t SafeSegment(std::string_view text) const noexcept; EncodingFamily CodePageFamily() const noexcept;
// Gateways to modifying document
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 202 lines changed, 120 insertions(+), 82 deletions(-) =================================================================== @@ -7,6 +7,7 @@
#include <cstddef> #include <cstdlib> +#include <cstdint> #include <cassert> #include <cstring> #include <cstdio> @@ -367,12 +368,6 @@ inline char CaseForce(Style::CaseForce caseForce, char chDoc, char chPrevious) n } }
-constexpr bool IsControlCharacter(int ch) noexcept { - // iscntrl returns true for lots of chars > 127 which are displayable, - // currently only check C0 control characters. - return (ch >= 0 && ch < ' ') || (ch == 127); -} - bool ViewIsASCII(std::string_view text) { return std::all_of(text.cbegin(), text.cend(), IsASCII); } @@ -469,7 +464,7 @@ void EditView::LayoutLine(const EditModel &model, Surface *surface, const ViewSt ll->positions[0] = 0; bool lastSegItalics = false;
- BreakFinder bfLayout(ll, nullptr, Range(0, numCharsInLine), posLineStart, 0, false, model.pdoc, &model.reprs, nullptr); + BreakFinder bfLayout(ll, nullptr, Range(0, numCharsInLine), posLineStart, 0, BreakFinder::BreakFor::Text, model.pdoc, &model.reprs, nullptr); while (bfLayout.More()) {
const TextSegment ts = bfLayout.Next(); @@ -569,46 +564,55 @@ void EditView::LayoutLine(const EditModel &model, Surface *surface, const ViewSt ll->wrapIndent = vstyle.aveCharWidth; // Indent to show start visual ll->lines = 0; // Calculate line start positions based upon width. - Sci::Position lastGoodBreak = 0; Sci::Position lastLineStart = 0; - XYACCUMULATOR startOffset = 0; + XYACCUMULATOR startOffset = width; Sci::Position p = 0; - while (p < ll->numCharsInLine) { - if ((ll->positions[p + 1] - startOffset) >= width) { + const Wrap wrapState = vstyle.wrap.state; + const Sci::Position numCharsInLine = ll->numCharsInLine; + while (p < numCharsInLine) { + while (p < numCharsInLine && ll->positions[p + 1] < startOffset) { + p++; + } + if (p < numCharsInLine) { + // backtrack to find lastGoodBreak + Sci::Position lastGoodBreak = p; + if (p > 0) { + lastGoodBreak = model.pdoc->MovePositionOutsideChar(p + posLineStart, -1) - posLineStart; + } + if (wrapState != Wrap::Char) { + Sci::Position pos = lastGoodBreak; + while (pos > lastLineStart) { + // style boundary and space + if (wrapState != Wrap::WhiteSpace && (ll->styles[pos - 1] != ll->styles[pos])) { + break; + } + if (IsBreakSpace(ll->chars[pos - 1]) && !IsBreakSpace(ll->chars[pos])) { + break; + } + pos = model.pdoc->MovePositionOutsideChar(pos + posLineStart - 1, -1) - posLineStart; + } + if (pos > lastLineStart) { + lastGoodBreak = pos; + } + } if (lastGoodBreak == lastLineStart) { // Try moving to start of last character if (p > 0) { - lastGoodBreak = model.pdoc->MovePositionOutsideChar(p + posLineStart, -1) - - posLineStart; + lastGoodBreak = model.pdoc->MovePositionOutsideChar(p + posLineStart, -1) - posLineStart; } if (lastGoodBreak == lastLineStart) { // Ensure at least one character on line. - lastGoodBreak = model.pdoc->MovePositionOutsideChar(lastGoodBreak + posLineStart + 1, 1) - - posLineStart; + lastGoodBreak = model.pdoc->MovePositionOutsideChar(lastGoodBreak + posLineStart + 1, 1) - posLineStart; } } lastLineStart = lastGoodBreak; ll->lines++; - ll->SetLineStart(ll->lines, static_cast<int>(lastGoodBreak)); - startOffset = ll->positions[lastGoodBreak]; + ll->SetLineStart(ll->lines, static_cast<int>(lastLineStart)); + startOffset = ll->positions[lastLineStart]; // take into account the space for start wrap mark and indent - startOffset -= ll->wrapIndent; - p = lastGoodBreak + 1; - continue; + startOffset += width - ll->wrapIndent; + p = lastLineStart + 1; } - if (p > 0) { - if (vstyle.wrap.state == Wrap::Char) { - lastGoodBreak = model.pdoc->MovePositionOutsideChar(p + posLineStart, -1) - - posLineStart; - p = model.pdoc->MovePositionOutsideChar(p + 1 + posLineStart, 1) - posLineStart; - continue; - } else if ((vstyle.wrap.state == Wrap::Word) && (ll->styles[p] != ll->styles[p - 1])) { - lastGoodBreak = p; - } else if (IsSpaceOrTab(ll->chars[p - 1]) && !IsSpaceOrTab(ll->chars[p])) { - lastGoodBreak = p; - } - } - p++; } ll->lines++; } @@ -951,19 +955,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 +1462,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 +1607,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) @@ -1635,7 +1639,7 @@ void EditView::DrawCarets(Surface *surface, const EditModel &model, const ViewSt } const bool caretBlinkState = (model.caret.active && model.caret.on) || (!additionalCaretsBlink && !mainCaret); const bool caretVisibleState = additionalCaretsVisible || mainCaret; - if ((xposCaret >= 0) && vsDraw.IsCaretVisible() && + if ((xposCaret >= 0) && vsDraw.IsCaretVisible(mainCaret) && (drawDrag || (caretBlinkState && caretVisibleState))) { bool canDrawBlockCaret = true; bool drawBlockCaret = false; @@ -1659,7 +1663,8 @@ void EditView::DrawCarets(Surface *surface, const EditModel &model, const ViewSt if (xposCaret > 0) caretWidthOffset = 0.51f; // Move back so overlaps both character cells. xposCaret += xStart; - const ViewStyle::CaretShape caretShape = drawDrag ? ViewStyle::CaretShape::line : vsDraw.CaretShapeForMode(model.inOverstrike); + const ViewStyle::CaretShape caretShape = drawDrag ? ViewStyle::CaretShape::line : + vsDraw.CaretShapeForMode(model.inOverstrike, mainCaret); if (drawDrag) { /* Dragging text, use a line caret */ rcCaret.left = std::round(xposCaret - caretWidthOffset); @@ -1672,7 +1677,7 @@ void EditView::DrawCarets(Surface *surface, const EditModel &model, const ViewSt } else if ((caretShape == ViewStyle::CaretShape::block) || imeCaretBlockOverride) { /* Block caret */ rcCaret.left = xposCaret; - if (canDrawBlockCaret && !(IsControlCharacter(ll->chars[offset]))) { + if (canDrawBlockCaret && !(IsControl(ll->chars[offset]))) { drawBlockCaret = true; rcCaret.right = xposCaret + widthOverstrikeCaret; } else { @@ -1732,6 +1737,21 @@ static void DrawWrapIndentAndMarker(Surface *surface, const ViewStyle &vsDraw, c } }
+// On the curses platform, the terminal is drawing its own caret, so if the caret is within +// the main selection, do not draw the selection at that position. +// Use iDoc from DrawBackground and DrawForeground here because TextSegment has been adjusted +// such that, if the caret is inside the main selection, the beginning or end of that selection +// is at the end of a text segment. +// This function should only be called if iDoc is within the main selection. +static InSelection CharacterInCursesSelection(Sci::Position iDoc, const EditModel &model, const ViewStyle &vsDraw) { + const SelectionPosition &posCaret = model.sel.RangeMain().caret; + const bool caretAtStart = posCaret < model.sel.RangeMain().anchor && posCaret.Position() == iDoc; + const bool caretAtEnd = posCaret > model.sel.RangeMain().anchor && + vsDraw.DrawCaretInsideSelection(false, false) && + model.pdoc->MovePositionOutsideChar(posCaret.Position() - 1, -1) == iDoc; + return (caretAtStart || caretAtEnd) ? InSelection::inNone : InSelection::inMain; +} + void EditView::DrawBackground(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, PRectangle rcLine, Range lineRange, Sci::Position posLineStart, int xStart, int subLine, std::optional<ColourRGBA> background) const { @@ -1742,7 +1762,8 @@ void EditView::DrawBackground(Surface *surface, const EditModel &model, const Vi // Does not take margin into account but not significant const XYPOSITION xStartVisible = static_cast<XYPOSITION>(subLineStart-xStart);
- BreakFinder bfBack(ll, &model.sel, lineRange, posLineStart, xStartVisible, selBackDrawn, model.pdoc, &model.reprs, nullptr); + const BreakFinder::BreakFor breakFor = selBackDrawn ? BreakFinder::BreakFor::Selection : BreakFinder::BreakFor::Text; + BreakFinder bfBack(ll, &model.sel, lineRange, posLineStart, xStartVisible, breakFor, model.pdoc, &model.reprs, &vsDraw);
const bool drawWhitespaceBackground = vsDraw.WhitespaceBackgroundDrawn() && !background;
@@ -1765,8 +1786,10 @@ void EditView::DrawBackground(Surface *surface, const EditModel &model, const Vi if (rcSegment.right > rcLine.right) rcSegment.right = rcLine.right;
- const InSelection inSelection = hideSelection ? InSelection::inNone : model.sel.CharacterInSelection(iDoc); - const bool inHotspot = (ll->hotspot.Valid()) && ll->hotspot.ContainsCharacter(iDoc); + InSelection inSelection = hideSelection ? InSelection::inNone : model.sel.CharacterInSelection(iDoc); + if (FlagSet(vsDraw.caret.style, CaretStyle::Curses) && (inSelection == InSelection::inMain)) + inSelection = CharacterInCursesSelection(iDoc, model, vsDraw); + 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) { @@ -1958,8 +1981,9 @@ void EditView::DrawForeground(Surface *surface, const EditModel &model, const Vi const XYPOSITION xStartVisible = static_cast<XYPOSITION>(subLineStart-xStart);
// Foreground drawing loop - BreakFinder bfFore(ll, &model.sel, lineRange, posLineStart, xStartVisible, - (((phasesDraw == PhasesDraw::One) && selBackDrawn) || vsDraw.SelectionTextDrawn()), model.pdoc, &model.reprs, &vsDraw); + const BreakFinder::BreakFor breakFor = (((phasesDraw == PhasesDraw::One) && selBackDrawn) || vsDraw.SelectionTextDrawn()) + ? BreakFinder::BreakFor::ForegroundAndSelection : BreakFinder::BreakFor::Foreground; + BreakFinder bfFore(ll, &model.sel, lineRange, posLineStart, xStartVisible, breakFor, model.pdoc, &model.reprs, &vsDraw);
while (bfFore.More()) {
@@ -1977,7 +2001,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); @@ -2009,7 +2033,9 @@ void EditView::DrawForeground(Surface *surface, const EditModel &model, const Vi } } } - const InSelection inSelection = hideSelection ? InSelection::inNone : model.sel.CharacterInSelection(iDoc); + InSelection inSelection = hideSelection ? InSelection::inNone : model.sel.CharacterInSelection(iDoc); + if (FlagSet(vsDraw.caret.style, CaretStyle::Curses) && (inSelection == InSelection::inMain)) + inSelection = CharacterInCursesSelection(iDoc, model, vsDraw); const std::optional<ColourRGBA> selectionFore = SelectionForeground(model, vsDraw, inSelection); if (selectionFore) { textFore = *selectionFore; @@ -2124,7 +2150,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 +2307,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 +2366,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 +2435,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 +2470,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 +2616,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 +2726,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 60 lines changed, 44 insertions(+), 16 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)); }
@@ -756,9 +772,9 @@ void Editor::MultipleSelectAdd(AddNumber addNumber) { searchRanges.push_back(rangeTarget); }
- for (std::vector<Range>::const_iterator it = searchRanges.begin(); it != searchRanges.end(); ++it) { - Sci::Position searchStart = it->start; - const Sci::Position searchEnd = it->end; + for (const Range range : searchRanges) { + Sci::Position searchStart = range.start; + const Sci::Position searchEnd = range.end; for (;;) { Sci::Position lengthFound = selectedText.length(); const Sci::Position pos = pdoc->FindText(searchStart, searchEnd, @@ -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);
@@ -2174,10 +2193,10 @@ void Editor::PasteRectangular(SelectionPosition pos, const char *ptr, Sci::Posit sel.RangeMain().caret = RealizeVirtualSpace(sel.RangeMain().caret); const int xInsert = XFromPosition(sel.RangeMain().caret); bool prevCr = false; - while ((len > 0) && IsEOLChar(ptr[len-1])) + while ((len > 0) && IsEOLCharacter(ptr[len-1])) len--; for (Sci::Position i = 0; i < len; i++) { - if (IsEOLChar(ptr[i])) { + if (IsEOLCharacter(ptr[i])) { if ((ptr[i] == '\r') || (!prevCr)) line++; if (line >= pdoc->LinesTotal()) { @@ -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; @@ -7564,7 +7592,7 @@ sptr_t Editor::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) { return vs.ElementColour(Element::Caret)->OpaqueRGB();
case Message::SetCaretStyle: - if (static_cast<CaretStyle>(wParam) <= (CaretStyle::Block | CaretStyle::OverstrikeBlock | CaretStyle::BlockAfter)) + if (static_cast<CaretStyle>(wParam) <= (CaretStyle::Block | CaretStyle::OverstrikeBlock | CaretStyle::Curses | CaretStyle::BlockAfter)) vs.caret.style = static_cast<CaretStyle>(wParam); else /* Default to the line caret */ @@ -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 inse@@ Diff output truncated at 100000 characters. @@
-------------- This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).