[geany/geany] fb7ab2: Update to Scintilla 5.1.4 and Lexilla 5.1.3

Thomas Martitz git-noreply at xxxxx
Mon Nov 15 06:46:40 UTC 2021


Branch:      refs/heads/master
Author:      Thomas Martitz <thomas.martitz at mailbox.org>
Committer:   Thomas Martitz <thomas.martitz at mailbox.org>
Date:        Mon, 15 Nov 2021 06:46:40 UTC
Commit:      fb7ab270d9e20b2d39f1d14b9a45c6967e691a84
             https://github.com/geany/geany/commit/fb7ab270d9e20b2d39f1d14b9a45c6967e691a84

Log Message:
-----------
Update to Scintilla 5.1.4 and Lexilla 5.1.3

Scintilla:
- On GTK, fix primary selection paste within same instance. Bug #2287.
- On GTK, fix potential crash when closing Scintilla instances due to releasing global settings object.

Lexilla:
- Various Rust fixes


Modified Paths:
--------------
    scintilla/gtk/PlatGTK.cxx
    scintilla/gtk/ScintillaGTK.cxx
    scintilla/gtk/ScintillaGTK.h
    scintilla/include/Scintilla.h
    scintilla/include/Scintilla.iface
    scintilla/include/ScintillaCall.h
    scintilla/include/ScintillaTypes.h
    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/version.txt
    scintilla/src/CellBuffer.cxx
    scintilla/src/CharClassify.cxx
    scintilla/src/CharacterType.h
    scintilla/src/ContractionState.cxx
    scintilla/src/Document.cxx
    scintilla/src/Document.h
    scintilla/src/EditView.cxx
    scintilla/src/Editor.cxx
    scintilla/src/KeyMap.cxx
    scintilla/src/MarginView.cxx
    scintilla/src/MarginView.h
    scintilla/src/PerLine.cxx
    scintilla/src/PositionCache.cxx
    scintilla/src/PositionCache.h
    scintilla/src/ViewStyle.cxx
    scintilla/src/ViewStyle.h
    scintilla/src/XPM.cxx
    scintilla/src/XPM.h
    scintilla/version.txt

Modified: scintilla/gtk/PlatGTK.cxx
2 lines changed, 1 insertions(+), 1 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;


Modified: scintilla/gtk/ScintillaGTK.cxx
26 lines changed, 13 insertions(+), 13 deletions(-)
===================================================================
@@ -282,9 +282,6 @@ ScintillaGTK::~ScintillaGTK() {
 	if (settingsHandlerId) {
 		g_signal_handler_disconnect(settings, settingsHandlerId);
 	}
-	if (settings) {
-		g_object_unref(settings);
-	}
 }
 
 void ScintillaGTK::RealizeThis(GtkWidget *widget) {
@@ -1303,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()) {
@@ -1566,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
@@ -1653,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();
 	}
@@ -1880,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))
@@ -2449,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
@@ -3011,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).
@@ -3047,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
3 lines changed, 2 insertions(+), 1 deletions(-)
===================================================================
@@ -34,6 +34,7 @@ class ScintillaGTK : public ScintillaBase {
 	int horizontalScrollBarHeight;
 
 	SelectionText primary;
+	SelectionPosition posPrimary;
 
 	GdkEvent *evbtn;
 	guint buttonMouse;
@@ -92,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/include/Scintilla.h
1 lines changed, 1 insertions(+), 0 deletions(-)
===================================================================
@@ -907,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
3 lines changed, 2 insertions(+), 1 deletions(-)
===================================================================
@@ -2489,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
 
@@ -3127,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
2 lines changed, 1 insertions(+), 1 deletions(-)
===================================================================
@@ -854,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/ScintillaTypes.h
1 lines changed, 1 insertions(+), 0 deletions(-)
===================================================================
@@ -439,6 +439,7 @@ enum class CaretStyle {
 	Block = 2,
 	OverstrikeBar = 0,
 	OverstrikeBlock = 0x10,
+	Curses = 0x20,
 	InsMask = 0xF,
 	BlockAfter = 0x100,
 };


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
8 lines changed, 4 insertions(+), 4 deletions(-)
===================================================================
@@ -80,7 +80,7 @@ WordList::~WordList() {
 }
 
 WordList::operator bool() const noexcept {
-	return len ? true : false;
+	return len != 0;
 }
 
 bool WordList::operator!=(const WordList &other) const noexcept {
@@ -144,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];
@@ -186,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];
@@ -240,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/version.txt
2 lines changed, 1 insertions(+), 1 deletions(-)
===================================================================
@@ -1 +1 @@
-512
+513


Modified: scintilla/src/CellBuffer.cxx
4 lines changed, 2 insertions(+), 2 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_) {
 	}
@@ -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
4 lines changed, 1 insertions(+), 3 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() {


Modified: scintilla/src/Document.cxx
188 lines changed, 82 insertions(+), 106 deletions(-)
===================================================================
@@ -1127,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 {
@@ -1218,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;
@@ -2419,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);
 }
 
@@ -2432,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() {
@@ -2468,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);
 	}
@@ -2478,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);
 	}
 }
@@ -2511,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);
 	}
 }
@@ -2520,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);
 	}
 }
@@ -2600,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 {
@@ -2672,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))
@@ -2723,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;
@@ -2986,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;


Modified: scintilla/src/Document.h
2 lines changed, 1 insertions(+), 1 deletions(-)
===================================================================
@@ -352,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/EditView.cxx
107 lines changed, 66 insertions(+), 41 deletions(-)
===================================================================
@@ -368,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);
 }
@@ -470,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();
@@ -570,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;
-				}
-				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;
-					}
+					startOffset += width - ll->wrapIndent;
+					p = lastLineStart + 1;
 				}
-				p++;
 			}
 			ll->lines++;
 		}
@@ -1636,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;
@@ -1660,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);
@@ -1673,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 {
@@ -1733,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 {
@@ -1743,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;
 
@@ -1766,7 +1786,9 @@ 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);
+			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);
@@ -1959,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()) {
 
@@ -2010,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;


Modified: scintilla/src/Editor.cxx
12 lines changed, 6 insertions(+), 6 deletions(-)
===================================================================
@@ -772,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,
@@ -2193,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()) {
@@ -7592,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 */


Modified: scintilla/src/KeyMap.cxx
2 lines changed, 1 insertions(+), 1 deletions(-)
===================================================================
@@ -67,7 +67,7 @@ const std::map<KeyModifiers, Message> &KeyMap::GetKeyMap() const noexcept {
 
 namespace {
 
-constexpr Keys Key(char ch) {
+constexpr Keys Key(char ch) noexcept {
     return static_cast<Keys>(ch);
 }
 


Modified: scintilla/src/MarginView.cxx
2 lines changed, 1 insertions(+), 1 deletions(-)
===================================================================
@@ -87,7 +87,7 @@ void DrawWrapMarker(Surface *surface, PRectangle rcPlace,
 		XYPOSITION yBase;
 		int yDir;
 		XYPOSITION halfWidth;
-		Point At(XYPOSITION xRelative, XYPOSITION yRelative) noexcept {
+		Point At(XYPOSITION xRelative, XYPOSITION yRelative) const noexcept {
 			return Point(xBase + xDir * xRelative + halfWidth, yBase + yDir * yRelative + halfWidth);
 		}
 	};


Modified: scintilla/src/MarginView.h
2 lines changed, 1 insertions(+), 1 deletions(-)
===================================================================
@@ -36,7 +36,7 @@ class MarginView {
 
 	void DropGraphics() noexcept;
 	void RefreshPixMaps(Surface *surfaceWindow, const ViewStyle &vsDraw);
-	void PaintOneMargin(Surface *surface, PRectangle rc, PRectangle rcMargin, const MarginStyle &marginStyle,
+	void PaintOneMargin(Surface *surface, PRectangle rc, PRectangle rcOneMargin, const MarginStyle &marginStyle,
 		const EditModel &model, const ViewStyle &vs);
 	void PaintMargin(Surface *surface, Sci::Line topLine, PRectangle rc, PRectangle rcMargin,
 		const EditModel &model, const ViewStyle &vs);


Modified: scintilla/src/PerLine.cxx
2 lines changed, 1 insertions(+), 1 deletions(-)
===================================================================
@@ -102,7 +102,7 @@ void LineMarkers::Init() {
 
 void LineMarkers::InsertLine(Sci::Line line) {
 	if (markers.Length()) {
-		markers.Insert(line, 0);
+		markers.Insert(line, nullptr);
 	}
 }
 


Modified: scintilla/src/PositionCache.cxx
98 lines changed, 55 insertions(+), 43 deletions(-)
===================================================================
@@ -31,6 +31,7 @@
 #include "Geometry.h"
 #include "Platform.h"
 
+#include "CharacterType.h"
 #include "CharacterCategoryMap.h"
 #include "Position.h"
 #include "UniqueString.h"
@@ -547,10 +548,8 @@ namespace {
 constexpr unsigned int KeyFromString(std::string_view charBytes) noexcept {
 	PLATFORM_ASSERT(charBytes.length() <= 4);
 	unsigned int k=0;
-	for (size_t i=0; i < charBytes.length(); i++) {
-		k = k * 0x100;
-		const unsigned char uc = charBytes[i];
-		k += uc;
+	for (const unsigned char uc : charBytes) {
+		k = k * 0x100 + uc;
 	}
 	return k;
 }
@@ -562,16 +561,18 @@ constexpr unsigned int representationKeyCrLf = KeyFromString("\r\n");
 void SpecialRepresentations::SetRepresentation(std::string_view charBytes, std::string_view value) {
 	if ((charBytes.length() <= 4) && (value.length() <= Representation::maxLength)) {
 		const unsigned int key = KeyFromString(charBytes);
-		const MapRepresentation::iterator it = mapReprs.find(key);
-		if (it == mapReprs.end()) {
+		const bool inserted = mapReprs.insert_or_assign(key, Representation(value)).second;
+		if (inserted) {
 			// New entry so increment for first byte
 			const unsigned char ucStart = charBytes.empty() ? 0 : charBytes[0];
 			startByteHasReprs[ucStart]++;
+			if (key > maxKey) {
+				maxKey = key;
+			}
 			if (key == representationKeyCrLf) {
 				crlf = true;
 			}
 		}
-		mapReprs[key] = Representation(value);
 	}
 }
 
@@ -608,6 +609,9 @@ void SpecialRepresentations::ClearRepresentation(std::string_view charBytes) {
 			mapReprs.erase(it);
 			const unsigned char ucStart = charBytes.empty() ? 0 : charBytes[0];
 			startByteHasReprs[ucStart]--;
+			if (key == maxKey && startByteHasReprs[ucStart] == 0) {
+				maxKey = mapReprs.empty() ? 0 : mapReprs.crbegin()->first;
+			}
 			if (key == representationKeyCrLf) {
 				crlf = false;
 			}
@@ -616,7 +620,11 @@ void SpecialRepresentations::ClearRepresentation(std::string_view charBytes) {
 }
 
 const Representation *SpecialRepresentations::GetRepresentation(std::string_view charBytes) const {
-	const MapRepresentation::const_iterator it = mapReprs.find(KeyFromString(charBytes));
+	const unsigned int key = KeyFromString(charBytes);
+	if (key > maxKey) {
+		return nullptr;
+	}
+	const MapRepresentation::const_iterator it = mapReprs.find(key);
 	if (it != mapReprs.end()) {
 		return &(it->second);
 	}
@@ -633,19 +641,11 @@ const Representation *SpecialRepresentations::RepresentationFromCharacter(std::s
 	return nullptr;
 }
 
-bool SpecialRepresentations::Contains(std::string_view charBytes) const {
-	PLATFORM_ASSERT(charBytes.length() <= 4);
-	const unsigned char ucStart = charBytes.empty() ? 0 : charBytes[0];
-	if (!startByteHasReprs[ucStart])
-		return false;
-	const MapRepresentation::const_iterator it = mapReprs.find(KeyFromString(charBytes));
-	return it != mapReprs.end();
-}
-
 void SpecialRepresentations::Clear() {
 	mapReprs.clear();
-	constexpr short none = 0;
+	constexpr unsigned short none = 0;
 	std::fill(startByteHasReprs, std::end(startByteHasReprs), none);
+	maxKey = 0;
 	crlf = false;
 }
 
@@ -662,7 +662,7 @@ void BreakFinder::Insert(Sci::Position val) {
 }
 
 BreakFinder::BreakFinder(const LineLayout *ll_, const Selection *psel, Range lineRange_, Sci::Position posLineStart_,
-	XYPOSITION xStart, bool breakForSelection, const Document *pdoc_, const SpecialRepresentations *preprs_, const ViewStyle *pvsDraw) :
+	XYPOSITION xStart, BreakFor breakFor, const Document *pdoc_, const SpecialRepresentations *preprs_, const ViewStyle *pvsDraw) :
 	ll(ll_),
 	lineRange(lineRange_),
 	posLineStart(posLineStart_),
@@ -683,7 +683,7 @@ BreakFinder::BreakFinder(const LineLayout *ll_, const Selection *psel, Range lin
 		nextBreak--;
 	}
 
-	if (breakForSelection) {
+	if (FlagSet(breakFor, BreakFor::Selection)) {
 		const SelectionPosition posStart(posLineStart);
 		const SelectionPosition posEnd(posLineStart + lineRange.end);
 		const SelectionSegment segmentLine(posStart, posEnd);
@@ -696,8 +696,23 @@ BreakFinder::BreakFinder(const LineLayout *ll_, const Selection *psel, Range lin
 					Insert(portion.end.Position() - posLineStart);
 			}
 		}
+		// On the curses platform, the terminal is drawing its own caret, so add breaks around the
+		// caret in the main selection in order to help prevent the selection from being drawn in
+		// the caret's cell.
+		if (FlagSet(pvsDraw->caret.style, CaretStyle::Curses) && !psel->RangeMain().Empty()) {
+			const Sci::Position caretPos = psel->RangeMain().caret.Position();
+			const Sci::Position anchorPos = psel->RangeMain().anchor.Position();
+			if (caretPos < anchorPos) {
+				const Sci::Position nextPos = pdoc->MovePositionOutsideChar(caretPos + 1, 1);
+				Insert(nextPos - posLineStart);
+			} else if (caretPos > anchorPos && pvsDraw->DrawCaretInsideSelection(false, false)) {
+				const Sci::Position prevPos = pdoc->MovePositionOutsideChar(caretPos - 1, -1);
+				if (prevPos > anchorPos)
+					Insert(prevPos - posLineStart);
+			}
+		}
 	}
-	if (pvsDraw && pvsDraw->indicatorsSetFore) {
+	if (FlagSet(breakFor, BreakFor::Foreground) && pvsDraw->indicatorsSetFore) {
 		for (const IDecoration *deco : pdoc->decorations->View()) {
 			if (pvsDraw->indicators[deco->Indicator()].OverridesTextFore()) {
 				Sci::Position startPos = deco->EndRun(posLineStart);
@@ -713,12 +728,12 @@ BreakFinder::BreakFinder(const LineLayout *ll_, const Selection *psel, Range lin
 	saeNext = (!selAndEdge.empty()) ? selAndEdge[0] : -1;
 }
 
-BreakFinder::~BreakFinder() {
-}
+BreakFinder::~BreakFinder() noexcept = default;
 
 TextSegment BreakFinder::Next() {
-	if (subBreak == -1) {
+	if (subBreak < 0) {
 		const int prev = nextBreak;
+		const Representation *repr = nullptr;
 		while (nextBreak < lineRange.end) {
 			int charWidth = 1;
 			const char * const chars = &ll->chars[nextBreak];
@@ -730,7 +745,7 @@ TextSegment BreakFinder::Next() {
 					charWidth = pdoc->DBCSDrawBytes(std::string_view(chars, lineRange.end - nextBreak));
 				}
 			}
-			const Representation *repr = nullptr;
+			repr = nullptr;
 			if (preprs->MayContain(ch)) {
 				// Special case \r\n line ends if there is a representation
 				if (ch == '\r' && preprs->ContainsCrLf() && chars[1] == '\n') {
@@ -752,35 +767,32 @@ TextSegment BreakFinder::Next() {
 					} else {
 						repr = nullptr;	// Optimize -> should remember repr
 					}
-					if ((nextBreak - prev) < lengthStartSubdivision) {
-						return TextSegment(prev, nextBreak - prev, repr);
-					} else {
-						break;
-					}
+					break;
 				}
 			}
 			nextBreak += charWidth;
 		}
-		if ((nextBreak - prev) < lengthStartSubdivision) {
-			return TextSegment(prev, nextBreak - prev);
+
+		const int lengthSegment = nextBreak - prev;
+		if (lengthSegment < lengthStartSubdivision) {
+			return TextSegment(prev, lengthSegment, repr);
 		}
 		subBreak = prev;
 	}
+
 	// Splitting up a long run from prev to nextBreak in lots of approximately lengthEachSubdivision.
-	// For very long runs add extra breaks after spaces or if no spaces before low punctuation.
 	const int startSegment = subBreak;
-	if ((nextBreak - subBreak) <= lengthEachSubdivision) {
-		subBreak = -1;
-		return TextSegment(startSegment, nextBreak - startSegment);
+	const int remaining = nextBreak - startSegment;
+	int lengthSegment = remaining;
+	if (lengthSegment > lengthEachSubdivision) {
+		lengthSegment = static_cast<int>(pdoc->SafeSegment(std::string_view(&ll->chars[startSegment], lengthEachSubdivision)));
+	}
+	if (lengthSegment < remaining) {
+		subBreak += lengthSegment;
 	} else {
-		subBreak += pdoc->SafeSegment(&ll->chars[subBreak], nextBreak-subBreak, lengthEachSubdivision);
-		if (subBreak >= nextBreak) {
-			subBreak = -1;
-			return TextSegment(startSegment, nextBreak - startSegment);
-		} else {
-			return TextSegment(startSegment, subBreak - startSegment);
-		}
+		subBreak = -1;
 	}
+	return TextSegment(startSegment, lengthSegment);
 }
 
 bool BreakFinder::More() const noexcept {


Modified: scintilla/src/PositionCache.h
24 lines changed, 11 insertions(+), 13 deletions(-)
===================================================================
@@ -10,14 +10,6 @@
 
 namespace Scintilla::Internal {
 
-inline constexpr bool IsEOLChar(int ch) noexcept {
-	return (ch == '\r') || (ch == '\n');
-}
-
-inline constexpr bool IsSpaceOrTab(int ch) noexcept {
-	return ch == ' ' || ch == '\t';
-}
-
 /**
 * A point in document space.
 * Uses double for sufficient resolution in large (>20,000,000 line) documents.
@@ -208,7 +200,8 @@ typedef std::map<unsigned int, Representation> MapRepresentation;
 
 class SpecialRepresentations {
 	MapRepresentation mapReprs;
-	short startByteHasReprs[0x100] {};
+	unsigned short startByteHasReprs[0x100] {};
+	unsigned int maxKey = 0;
 	bool crlf = false;
 public:
 	void SetRepresentation(std::string_view charBytes, std::string_view value);
@@ -217,7 +210,6 @@ class SpecialRepresentations {
 	void ClearRepresentation(std::string_view charBytes);
 	const Representation *GetRepresentation(std::string_view charBytes) const;
 	const Representation *RepresentationFromCharacter(std::string_view charBytes) const;
-	bool Contains(std::string_view charBytes) const;
 	bool ContainsCrLf() const noexcept {
 		return crlf;
 	}
@@ -250,7 +242,7 @@ class BreakFinder {
 	int saeNext;
 	int subBreak;
 	const Document *pdoc;
-	EncodingFamily encodingFamily;
+	const EncodingFamily encodingFamily;
 	const SpecialRepresentations *preprs;
 	void Insert(Sci::Position val);
 public:
@@ -259,14 +251,20 @@ class BreakFinder {
 	enum { lengthStartSubdivision = 300 };
 	// Try to make each subdivided run lengthEachSubdivision or shorter.
 	enum { lengthEachSubdivision = 100 };
+	enum class BreakFor {
+		Text = 0,
+		Selection = 1,
+		Foreground = 2,
+		ForegroundAndSelection = 3,
+	};
 	BreakFinder(const LineLayout *ll_, const Selection *psel, Range lineRange_, Sci::Position posLineStart_,
-		XYPOSITION xStart, bool breakForSelection, const Document *pdoc_, const SpecialRepresentations *preprs_, const ViewStyle *pvsDraw);
+		XYPOSITION xStart, BreakFor breakFor, const Document *pdoc_, const SpecialRepresentations *preprs_, const ViewStyle *pvsDraw);
 	// Deleted so BreakFinder objects can not be copied.
 	BreakFinder(const BreakFinder &) = delete;
 	BreakFinder(BreakFinder &&) = delete;
 	void operator=(const BreakFinder &) = delete;
 	void operator=(BreakFinder &&) = delete;
-	~BreakFinder();
+	~BreakFinder() noexcept;
 	TextSegment Next();
 	bool More() const noexcept;
 };


Modified: scintilla/src/ViewStyle.cxx
32 lines changed, 13 insertions(+), 19 deletions(-)
===================================================================
@@ -136,8 +136,6 @@ ViewStyle::ViewStyle(size_t stylesSize_) :
 		Element::SelectionBack,
 		Element::SelectionInactiveBack,
 		});
-	selection.layer = Layer::Base;
-	selection.eolFilled = false;
 
 	foldmarginColour.reset();
 	foldmarginHighlightColour.reset();
@@ -155,15 +153,9 @@ ViewStyle::ViewStyle(size_t stylesSize_) :
 		Element::Caret,
 		Element::CaretAdditional,
 		});
-	caret.style = CaretStyle::Line;
-	caret.width = 1;
 
 	elementColours.erase(Element::CaretLineBack);
 	elementAllowsTranslucent.insert(Element::CaretLineBack);
-	caretLine.alwaysShow = false;
-	caretLine.subLine = false;
-	caretLine.layer = Layer::Base;
-	caretLine.frame = 0;
 
 	someStylesProtected = false;
 	someStylesForceCase = false;
@@ -210,12 +202,6 @@ ViewStyle::ViewStyle(size_t stylesSize_) :
 	ctrlCharPadding = 3; // +3 For a blank on front and rounded edge each side
 	lastSegItalicsOffset = 2;
 
-	wrap.state = Wrap::None;
-	wrap.visualFlags = WrapVisualFlag::None;
-	wrap.visualFlagsLocation = WrapVisualLocation::Default;
-	wrap.visualStartIndent = 0;
-	wrap.indentMode = WrapIndentMode::Fixed;
-
 	localeName = localeNameDefault;
 }
 
@@ -661,26 +647,34 @@ bool ViewStyle::SetWrapIndentMode(WrapIndentMode wrapIndentMode_) noexcept {
 
 bool ViewStyle::IsBlockCaretStyle() const noexcept {
 	return ((caret.style & CaretStyle::InsMask) == CaretStyle::Block) ||
-		FlagSet(caret.style, CaretStyle::OverstrikeBlock);
+		FlagSet(caret.style, CaretStyle::OverstrikeBlock) ||
+		FlagSet(caret.style, CaretStyle::Curses);
 }
 
-bool ViewStyle::IsCaretVisible() const noexcept {
-	return caret.width > 0 && caret.style != CaretStyle::Invisible;
+bool ViewStyle::IsCaretVisible(bool isMainSelection) const noexcept {
+	return caret.width > 0 &&
+		((caret.style & CaretStyle::InsMask) != CaretStyle::Invisible ||
+		(FlagSet(caret.style, CaretStyle::Curses) && !isMainSelection)); // only draw additional selections in curses mode
 }
 
 bool ViewStyle::DrawCaretInsideSelection(bool inOverstrike, bool imeCaretBlockOverride) const noexcept {
 	if (FlagSet(caret.style, CaretStyle::BlockAfter))
 		return false;
 	return ((caret.style & CaretStyle::InsMask) == CaretStyle::Block) ||
 		(inOverstrike && FlagSet(caret.style, CaretStyle::OverstrikeBlock)) ||
-		imeCaretBlockOverride;
+		imeCaretBlockOverride ||
+		FlagSet(caret.style, CaretStyle::Curses);
 }
 
-ViewStyle::CaretShape ViewStyle::CaretShapeForMode(bool inOverstrike) const noexcept {
+ViewStyle::CaretShape ViewStyle::CaretShapeForMode(bool inOverstrike, bool isMainSelection) const noexcept {
 	if (inOverstrike) {
 		return (FlagSet(caret.style, CaretStyle::OverstrikeBlock)) ? CaretShape::block : CaretShape::bar;
 	}
 
+	if (FlagSet(caret.style, CaretStyle::Curses) && !isMainSelection) {
+		return CaretShape::block;
+	}
+
 	const CaretStyle caretStyle = caret.style & CaretStyle::InsMask;
 	return (caretStyle <= CaretStyle::Block) ? static_cast<CaretShape>(caretStyle) : CaretShape::line;
 }


Modified: scintilla/src/ViewStyle.h
38 lines changed, 19 insertions(+), 19 deletions(-)
===================================================================
@@ -47,40 +47,40 @@ inline std::optional<ColourRGBA> OptionalColour(Scintilla::uptr_t wParam, Scinti
 
 struct SelectionAppearance {
 	// Whether to draw on base layer or over text
-	Scintilla::Layer layer;
+	Scintilla::Layer layer = Layer::Base;
 	// Draw selection past line end characters up to right border
-	bool eolFilled;
+	bool eolFilled = false;
 };
 
 struct CaretLineAppearance {
 	// Whether to draw on base layer or over text
-	Scintilla::Layer layer;
+	Scintilla::Layer layer = Layer::Base;
 	// Also show when non-focused
-	bool alwaysShow;
+	bool alwaysShow = false;
 	// highlight sub line instead of whole line
-	bool subLine;
+	bool subLine = false;
 	// Non-0: draw a rectangle around line instead of filling line. Value is pixel width of frame
-	int frame;
+	int frame = 0;
 };
 
 struct CaretAppearance {
 	// Line, block, over-strike bar ...
-	Scintilla::CaretStyle style;
+	Scintilla::CaretStyle style = CaretStyle::Line;
 	// Width in pixels
-	int width;
+	int width = 1;
 };
 
 struct WrapAppearance {
 	// No wrapping, word, character, whitespace appearance
-	Scintilla::Wrap state;
+	Scintilla::Wrap state = Wrap::None;
 	// Show indication of wrap at line end, line start, or in margin
-	Scintilla::WrapVisualFlag visualFlags;
+	Scintilla::WrapVisualFlag visualFlags = WrapVisualFlag::None;
 	// Show indication near margin or near text
-	Scintilla::WrapVisualLocation visualFlagsLocation;
+	Scintilla::WrapVisualLocation visualFlagsLocation = WrapVisualLocation::Default;
 	// How much indentation to show wrapping
-	int visualStartIndent;
-	// WrapIndentMode::Fixed, _SAME, _INDENT, _DEEPINDENT
-	Scintilla::WrapIndentMode indentMode;
+	int visualStartIndent = 0;
+	// WrapIndentMode::Fixed, Same, Indent, DeepIndent
+	Scintilla::WrapIndentMode indentMode = WrapIndentMode::Fixed;
 };
 
 struct EdgeProperties {
@@ -137,10 +137,10 @@ class ViewStyle {
 	/// Margins are ordered: Line Numbers, Selection Margin, Spacing Margin
 	int leftMarginWidth;	///< Spacing margin on left of text
 	int rightMarginWidth;	///< Spacing margin on right of text
-	int maskInLine;	///< Mask for markers to be put into text because there is nowhere for them to go in margin
-	int maskDrawInText;	///< Mask for markers that always draw in text
+	int maskInLine = 0;	///< Mask for markers to be put into text because there is nowhere for them to go in margin
+	int maskDrawInText = 0;	///< Mask for markers that always draw in text
 	std::vector<MarginStyle> ms;
-	int fixedColumnWidth;	///< Total width of margins
+	int fixedColumnWidth = 0;	///< Total width of margins
 	bool marginInside;	///< true: margin included in text view, false: separate views
 	int textStart;	///< Starting x position of text within the view
 	int zoomLevel;
@@ -235,9 +235,9 @@ class ViewStyle {
 
 	enum class CaretShape { invisible, line, block, bar };
 	bool IsBlockCaretStyle() const noexcept;
-	bool IsCaretVisible() const noexcept;
+	bool IsCaretVisible(bool isMainSelection) const noexcept;
 	bool DrawCaretInsideSelection(bool inOverstrike, bool imeCaretBlockOverride) const noexcept;
-	CaretShape CaretShapeForMode(bool inOverstrike) const noexcept;
+	CaretShape CaretShapeForMode(bool inOverstrike, bool isMainSelection) const noexcept;
 
 private:
 	void AllocStyles(size_t sizeNew);


Modified: scintilla/src/XPM.cxx
29 lines changed, 10 insertions(+), 19 deletions(-)
===================================================================
@@ -7,6 +7,7 @@
 
 #include <cstdlib>
 #include <cstring>
+#include <climits>
 
 #include <stdexcept>
 #include <string_view>
@@ -92,17 +93,14 @@ XPM::XPM(const char *const *linesForm) {
 	Init(linesForm);
 }
 
-XPM::~XPM() {
-}
-
 void XPM::Init(const char *textForm) {
 	// Test done is two parts to avoid possibility of overstepping the memory
 	// if memcmp implemented strangely. Must be 4 bytes at least at destination.
 	if ((0 == memcmp(textForm, "/* X", 4)) && (0 == memcmp(textForm, "/* XPM */", 9))) {
 		// Build the lines form out of the text form
 		std::vector<const char *> linesForm = LinesFormFromTextForm(textForm);
 		if (!linesForm.empty()) {
-			Init(&linesForm[0]);
+			Init(linesForm.data());
 		}
 	} else {
 		// It is really in line form
@@ -146,7 +144,7 @@ void XPM::Init(const char *const *linesForm) {
 		colourCodeTable[static_cast<unsigned char>(code)] = colour;
 	}
 
-	for (int y=0; y<height; y++) {
+	for (ptrdiff_t y=0; y<height; y++) {
 		const char *lform = linesForm[y+nColours+1];
 		const size_t len = MeasureLength(lform);
 		for (size_t x = 0; x<len; x++)
@@ -241,19 +239,16 @@ RGBAImage::RGBAImage(const XPM &xpm) {
 	}
 }
 
-RGBAImage::~RGBAImage() {
-}
-
 int RGBAImage::CountBytes() const noexcept {
 	return width * height * 4;
 }
 
 const unsigned char *RGBAImage::Pixels() const noexcept {
-	return &pixelBytes[0];
+	return pixelBytes.data();
 }
 
 void RGBAImage::SetPixel(int x, int y, ColourRGBA colour) noexcept {
-	unsigned char *pixel = &pixelBytes[0] + (y * width + x) * 4;
+	unsigned char *pixel = pixelBytes.data() + (y * width + x) * 4;
 	// RGBA
 	pixel[0] = colour.GetRed();
 	pixel[1] = colour.GetGreen();
@@ -267,9 +262,9 @@ void RGBAImage::BGRAFromRGBA(unsigned char *pixelsBGRA, const unsigned char *pix
 	for (size_t i = 0; i < count; i++) {
 		const unsigned char alpha = pixelsRGBA[3];
 		// Input is RGBA, output is BGRA with premultiplied alpha
-		pixelsBGRA[2] = pixelsRGBA[0] * alpha / 255;
-		pixelsBGRA[1] = pixelsRGBA[1] * alpha / 255;
-		pixelsBGRA[0] = pixelsRGBA[2] * alpha / 255;
+		pixelsBGRA[2] = pixelsRGBA[0] * alpha / UCHAR_MAX;
+		pixelsBGRA[1] = pixelsRGBA[1] * alpha / UCHAR_MAX;
+		pixelsBGRA[0] = pixelsRGBA[2] * alpha / UCHAR_MAX;
 		pixelsBGRA[3] = alpha;
 		pixelsRGBA += bytesPerPixel;
 		pixelsBGRA += bytesPerPixel;
@@ -279,10 +274,6 @@ void RGBAImage::BGRAFromRGBA(unsigned char *pixelsBGRA, const unsigned char *pix
 RGBAImageSet::RGBAImageSet() : height(-1), width(-1) {
 }
 
-RGBAImageSet::~RGBAImageSet() {
-	Clear();
-}
-
 /// Remove all images.
 void RGBAImageSet::Clear() noexcept {
 	images.clear();
@@ -307,7 +298,7 @@ RGBAImage *RGBAImageSet::Get(int ident) {
 }
 
 /// Give the largest height of the set.
-int RGBAImageSet::GetHeight() const {
+int RGBAImageSet::GetHeight() const noexcept {
 	if (height < 0) {
 		for (const std::pair<const int, std::unique_ptr<RGBAImage>> &image : images) {
 			if (height < image.second->GetHeight()) {
@@ -319,7 +310,7 @@ int RGBAImageSet::GetHeight() const {
 }
 
 /// Give the largest width of the set.
-int RGBAImageSet::GetWidth() const {
+int RGBAImageSet::GetWidth() const noexcept {
 	if (width < 0) {
 		for (const std::pair<const int, std::unique_ptr<RGBAImage>> &image : images) {
 			if (width < image.second->GetWidth()) {


Modified: scintilla/src/XPM.h
20 lines changed, 2 insertions(+), 18 deletions(-)
===================================================================
@@ -25,11 +25,6 @@ class XPM {
 public:
 	explicit XPM(const char *textForm);
 	explicit XPM(const char *const *linesForm);
-	XPM(const XPM &) = default;
-	XPM(XPM &&) noexcept = default;
-	XPM &operator=(const XPM &) = default;
-	XPM &operator=(XPM &&) noexcept = default;
-	~XPM();
 	void Init(const char *textForm);
 	void Init(const char *const *linesForm);
 	/// Decompose image into runs and use FillRectangle for each run
@@ -53,11 +48,6 @@ class RGBAImage {
 	static constexpr size_t bytesPerPixel = 4;
 	RGBAImage(int width_, int height_, float scale_, const unsigned char *pixels_);
 	explicit RGBAImage(const XPM &xpm);
-	RGBAImage(const RGBAImage &) = default;
-	RGBAImage(RGBAImage &&) noexcept = default;
-	RGBAImage &operator=(const RGBAImage &) = default;
-	RGBAImage &operator=(RGBAImage &&) noexcept = default;
-	virtual ~RGBAImage();
 	int GetHeight() const noexcept { return height; }
 	int GetWidth() const noexcept { return width; }
 	float GetScale() const noexcept { return scale; }
@@ -79,22 +69,16 @@ class RGBAImageSet {
 	mutable int width;	///< Memorize largest width of the set.
 public:
 	RGBAImageSet();
-	// Deleted so RGBAImageSet objects can not be copied.
-	RGBAImageSet(const RGBAImageSet &) = delete;
-	RGBAImageSet(RGBAImageSet &&) = delete;
-	RGBAImageSet &operator=(const RGBAImageSet &) = delete;
-	RGBAImageSet &operator=(RGBAImageSet &&) = delete;
-	~RGBAImageSet();
 	/// Remove all images.
 	void Clear() noexcept;
 	/// Add an image.
 	void AddImage(int ident, std::unique_ptr<RGBAImage> image);
 	/// Get image by id.
 	RGBAImage *Get(int ident);
 	/// Give the largest height of the set.
-	int GetHeight() const;
+	int GetHeight() const noexcept;
 	/// Give the largest width of the set.
-	int GetWidth() const;
+	int GetWidth() const noexcept;
 };
 
 }


Modified: scintilla/version.txt
2 lines changed, 1 insertions(+), 1 deletions(-)
===================================================================
@@ -1 +1 @@
-513
+514



--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).


More information about the Commits mailing list