[geany/geany] a8a6ef: Merge branch 'scintilla-update-350-pre'

Colomban Wendling git-noreply at xxxxx
Sun Aug 10 00:23:21 UTC 2014


Branch:      refs/heads/master
Author:      Colomban Wendling <ban at herbesfolles.org>
Committer:   Colomban Wendling <ban at herbesfolles.org>
Date:        Sun, 10 Aug 2014 00:23:21 UTC
Commit:      a8a6ef7d131e49e1cc5ed843ebec3167fd7b018b
             https://github.com/geany/geany/commit/a8a6ef7d131e49e1cc5ed843ebec3167fd7b018b

Log Message:
-----------
Merge branch 'scintilla-update-350-pre'


Modified Paths:
--------------
    data/filetypes.rust
    scintilla/Makefile.am
    scintilla/gtk/PlatGTK.cxx
    scintilla/gtk/ScintillaGTK.cxx
    scintilla/include/SciLexer.h
    scintilla/include/Scintilla.h
    scintilla/include/Scintilla.iface
    scintilla/lexers/LexHTML.cxx
    scintilla/lexers/LexMatlab.cxx
    scintilla/lexers/LexRuby.cxx
    scintilla/lexers/LexRust.cxx
    scintilla/lexlib/LexerModule.h
    scintilla/makefile.win32
    scintilla/scintilla_changes.patch
    scintilla/src/CellBuffer.cxx
    scintilla/src/CellBuffer.h
    scintilla/src/ContractionState.cxx
    scintilla/src/ContractionState.h
    scintilla/src/Document.cxx
    scintilla/src/Document.h
    scintilla/src/EditModel.cxx
    scintilla/src/EditModel.h
    scintilla/src/EditView.cxx
    scintilla/src/EditView.h
    scintilla/src/Editor.cxx
    scintilla/src/Editor.h
    scintilla/src/LineMarker.cxx
    scintilla/src/MarginView.cxx
    scintilla/src/MarginView.h
    scintilla/src/PerLine.cxx
    scintilla/src/PerLine.h
    scintilla/src/PositionCache.cxx
    scintilla/src/PositionCache.h
    scintilla/src/RESearch.cxx
    scintilla/src/RESearch.h
    scintilla/src/ScintillaBase.cxx
    scintilla/src/ScintillaBase.h
    scintilla/src/Selection.cxx
    scintilla/src/Selection.h
    scintilla/src/ViewStyle.cxx
    scintilla/src/ViewStyle.h
    scintilla/version.txt
    src/highlighting.c
    src/highlightingmappings.h

Modified: data/filetypes.rust
3 lines changed, 3 insertions(+), 0 deletions(-)
===================================================================
@@ -14,6 +14,9 @@ word4=type
 string=string_1
 stringraw=string_2
 character=character
+bytestring=string_1
+bytestringraw=string_2
+bytecharacter=character
 operator=operator
 identifier=identifier_1
 lifetime=parameter


Modified: scintilla/Makefile.am
6 lines changed, 6 insertions(+), 0 deletions(-)
===================================================================
@@ -97,6 +97,10 @@ src/Document.cxx \
 src/Document.h \
 src/Editor.cxx \
 src/Editor.h \
+src/EditModel.cxx \
+src/EditModel.h \
+src/EditView.cxx \
+src/EditView.h \
 src/ExternalLexer.cxx \
 src/ExternalLexer.h \
 src/FontQuality.h \
@@ -106,6 +110,8 @@ src/KeyMap.cxx \
 src/KeyMap.h \
 src/LineMarker.cxx \
 src/LineMarker.h \
+src/MarginView.cxx \
+src/MarginView.h \
 src/Partitioning.h \
 src/PerLine.cxx \
 src/PerLine.h \


Modified: scintilla/gtk/PlatGTK.cxx
12 lines changed, 10 insertions(+), 2 deletions(-)
===================================================================
@@ -527,6 +527,7 @@ void SurfaceImpl::Release() {
 }
 
 bool SurfaceImpl::Initialised() {
+#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 8, 0)
 	if (inited && context) {
 		if (cairo_status(context) == CAIRO_STATUS_SUCCESS) {
 			// Even when status is success, the target surface may have been
@@ -543,6 +544,7 @@ bool SurfaceImpl::Initialised() {
 		}
 		return cairo_status(context) == CAIRO_STATUS_SUCCESS;
 	}
+#endif
 	return inited;
 }
 
@@ -1086,6 +1088,10 @@ void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, XYPOSITION
 						}
 						clusterStart = clusterEnd;
 					}
+					while (i < lenPositions) {
+						// If something failed, fill in rest of the positions
+						positions[i++] = clusterStart;
+					}
 					PLATFORM_ASSERT(i == lenPositions);
 				}
 			}
@@ -1799,6 +1805,7 @@ void ListBoxX::Select(int n) {
 }
 
 int ListBoxX::GetSelection() {
+	int index = -1;
 	GtkTreeIter iter;
 	GtkTreeModel *model;
 	GtkTreeSelection *selection;
@@ -1808,9 +1815,10 @@ int ListBoxX::GetSelection() {
 		int *indices = gtk_tree_path_get_indices(path);
 		// Don't free indices.
 		if (indices)
-			return indices[0];
+			index = indices[0];
+		gtk_tree_path_free(path);
 	}
-	return -1;
+	return index;
 }
 
 int ListBoxX::Find(const char *prefix) {


Modified: scintilla/gtk/ScintillaGTK.cxx
284 lines changed, 208 insertions(+), 76 deletions(-)
===================================================================
@@ -57,9 +57,13 @@
 #include "UniConversion.h"
 #include "Selection.h"
 #include "PositionCache.h"
+#include "EditModel.h"
+#include "MarginView.h"
+#include "EditView.h"
 #include "Editor.h"
 #include "AutoComplete.h"
 #include "ScintillaBase.h"
+#include "UnicodeFromUTF8.h"
 
 #ifdef SCI_LEXER
 #include "ExternalLexer.h"
@@ -186,13 +190,23 @@ class ScintillaGTK : public ScintillaBase {
 	virtual sptr_t WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
 private:
 	virtual sptr_t DefWndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
-	virtual void SetTicking(bool on);
+	struct TimeThunk {
+		TickReason reason;
+		ScintillaGTK *scintilla;
+		guint timer;
+		TimeThunk() : reason(tickCaret), scintilla(NULL), timer(0) {}
+	};
+	TimeThunk timers[tickDwell+1];
+	virtual bool FineTickerAvailable();
+	virtual bool FineTickerRunning(TickReason reason);
+	virtual void FineTickerStart(TickReason reason, int millis, int tolerance);
+	virtual void FineTickerCancel(TickReason reason);
 	virtual bool SetIdle(bool on);
 	virtual void SetMouseCapture(bool on);
 	virtual bool HaveMouseCapture();
 	virtual bool PaintContains(PRectangle rc);
 	void FullPaint();
-	virtual PRectangle GetClientRectangle();
+	virtual PRectangle GetClientRectangle() const;
 	virtual void ScrollText(int linesToMove);
 	virtual void SetVerticalScrollPos();
 	virtual void SetHorizontalScrollPos();
@@ -280,6 +294,9 @@ class ScintillaGTK : public ScintillaBase {
 	static void Commit(GtkIMContext *context, char *str, ScintillaGTK *sciThis);
 	void PreeditChangedThis();
 	static void PreeditChanged(GtkIMContext *context, ScintillaGTK *sciThis);
+
+	bool KoreanIME();
+
 	static void StyleSetText(GtkWidget *widget, GtkStyle *previous, void*);
 	static void RealizeText(GtkWidget *widget, void*);
 	static void Destroy(GObject *object);
@@ -300,7 +317,7 @@ class ScintillaGTK : public ScintillaBase {
 	                             gint x, gint y, GtkSelectionData *selection_data, guint info, guint time);
 	static void DragDataGet(GtkWidget *widget, GdkDragContext *context,
 	                        GtkSelectionData *selection_data, guint info, guint time);
-	static gboolean TimeOut(ScintillaGTK *sciThis);
+	static gboolean TimeOut(TimeThunk *tt);
 	static gboolean IdleCallback(ScintillaGTK *sciThis);
 	static gboolean StyleIdle(ScintillaGTK *sciThis);
 	virtual void QueueIdleWork(WorkNeeded::workItems items, int upTo);
@@ -624,22 +641,37 @@ void ScintillaGTK::MainForAll(GtkContainer *container, gboolean include_internal
 	}
 }
 
+namespace {
+
+class PreEditString {
+public:
+	gchar *str;
+	gint cursor_pos;
+	PangoAttrList *attrs;
+
+	PreEditString(GtkIMContext *im_context) {
+		gtk_im_context_get_preedit_string(im_context, &str, &attrs, &cursor_pos);
+	}
+	~PreEditString() {
+		g_free(str);
+		pango_attr_list_unref(attrs);
+	}
+};
+
+}
+
 gint ScintillaGTK::FocusInThis(GtkWidget *widget) {
 	try {
 		SetFocusState(true);
 		if (im_context != NULL) {
-			gchar *str = NULL;
-			gint cursor_pos;
-
-			gtk_im_context_get_preedit_string(im_context, &str, NULL, &cursor_pos);
+			PreEditString pes(im_context);
 			if (PWidget(wPreedit) != NULL) {
-				if (strlen(str) > 0) {
+				if (strlen(pes.str) > 0) {
 					gtk_widget_show(PWidget(wPreedit));
 				} else {
 					gtk_widget_hide(PWidget(wPreedit));
 				}
 			}
-			g_free(str);
 			gtk_im_context_focus_in(im_context);
 		}
 
@@ -829,11 +861,16 @@ void ScintillaGTK::Initialise() {
 		caret.period = 0;
 	}
 
-	SetTicking(true);
+	for (TickReason tr = tickCaret; tr <= tickDwell; tr = static_cast<TickReason>(tr + 1)) {
+		timers[tr].reason = tr;
+		timers[tr].scintilla = this;
+	}
 }
 
 void ScintillaGTK::Finalise() {
-	SetTicking(false);
+	for (TickReason tr = tickCaret; tr <= tickDwell; tr = static_cast<TickReason>(tr + 1)) {
+		FineTickerCancel(tr);
+	}
 	ScintillaBase::Finalise();
 }
 
@@ -1024,17 +1061,27 @@ sptr_t ScintillaGTK::DefWndProc(unsigned int, uptr_t, sptr_t) {
 	return 0;
 }
 
-void ScintillaGTK::SetTicking(bool on) {
-	if (timer.ticking != on) {
-		timer.ticking = on;
-		if (timer.ticking) {
-			timer.tickerID = reinterpret_cast<TickerID>(g_timeout_add(timer.tickSize,
-				reinterpret_cast<GSourceFunc>(TimeOut), this));
-		} else {
-			g_source_remove(GPOINTER_TO_UINT(timer.tickerID));
-		}
+/**
+* Report that this Editor subclass has a working implementation of FineTickerStart.
+*/
+bool ScintillaGTK::FineTickerAvailable() {
+	return true;
+}
+
+bool ScintillaGTK::FineTickerRunning(TickReason reason) {
+	return timers[reason].timer != 0;
+}
+
+void ScintillaGTK::FineTickerStart(TickReason reason, int millis, int /* tolerance */) {
+	FineTickerCancel(reason);
+	timers[reason].timer = g_timeout_add(millis, reinterpret_cast<GSourceFunc>(TimeOut), &timers[reason]);
+}
+
+void ScintillaGTK::FineTickerCancel(TickReason reason) {
+	if (timers[reason].timer) {
+		g_source_remove(timers[reason].timer);
+		timers[reason].timer = 0;
 	}
-	timer.ticksToWait = caret.period;
 }
 
 bool ScintillaGTK::SetIdle(bool on) {
@@ -1121,8 +1168,9 @@ void ScintillaGTK::FullPaint() {
 	wText.InvalidateAll();
 }
 
-PRectangle ScintillaGTK::GetClientRectangle() {
-	PRectangle rc = wMain.GetClientPosition();
+PRectangle ScintillaGTK::GetClientRectangle() const {
+	Window &win = const_cast<Window &>(wMain);
+	PRectangle rc = win.GetClientPosition();
 	if (verticalScrollBarVisible)
 		rc.right -= verticalScrollBarWidth;
 	if (horizontalScrollBarVisible && !Wrapping())
@@ -2220,19 +2268,13 @@ gboolean ScintillaGTK::KeyRelease(GtkWidget *widget, GdkEventKey *event) {
 
 gboolean ScintillaGTK::DrawPreeditThis(GtkWidget *widget, cairo_t *cr) {
 	try {
-		gchar *str;
-		gint cursor_pos;
-		PangoAttrList *attrs;
-
-		gtk_im_context_get_preedit_string(im_context, &str, &attrs, &cursor_pos);
-		PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), str);
-		pango_layout_set_attributes(layout, attrs);
+		PreEditString pes(im_context);
+		PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), pes.str);
+		pango_layout_set_attributes(layout, pes.attrs);
 
 		cairo_move_to(cr, 0, 0);
 		pango_cairo_show_layout(cr, layout);
 
-		g_free(str);
-		pango_attr_list_unref(attrs);
 		g_object_unref(layout);
 	} catch (...) {
 		errorStatus = SC_STATUS_FAILURE;
@@ -2248,20 +2290,14 @@ gboolean ScintillaGTK::DrawPreedit(GtkWidget *widget, cairo_t *cr, ScintillaGTK
 
 gboolean ScintillaGTK::ExposePreeditThis(GtkWidget *widget, GdkEventExpose *ose) {
 	try {
-		gchar *str;
-		gint cursor_pos;
-		PangoAttrList *attrs;
-
-		gtk_im_context_get_preedit_string(im_context, &str, &attrs, &cursor_pos);
-		PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), str);
-		pango_layout_set_attributes(layout, attrs);
+		PreEditString pes(im_context);
+		PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), pes.str);
+		pango_layout_set_attributes(layout, pes.attrs);
 
 		cairo_t *context = gdk_cairo_create(reinterpret_cast<GdkDrawable *>(WindowFromWidget(widget)));
 		cairo_move_to(context, 0, 0);
 		pango_cairo_show_layout(context, layout);
 		cairo_destroy(context);
-		g_free(str);
-		pango_attr_list_unref(attrs);
 		g_object_unref(layout);
 	} catch (...) {
 		errorStatus = SC_STATUS_FAILURE;
@@ -2275,9 +2311,43 @@ gboolean ScintillaGTK::ExposePreedit(GtkWidget *widget, GdkEventExpose *ose, Sci
 
 #endif
 
+bool ScintillaGTK::KoreanIME() {
+	// Warn : for KoreanIME use only.
+	if (pdoc->TentativeActive()) {
+		return true;
+	}
+
+	bool koreanIME = false;
+	PreEditString utfval(im_context);
+
+	// Only need to check if the first preedit char is Korean.
+	// The rest will be handled in TentativeActive()
+	// which can handle backspace and CJK commons and so forth.
+
+	if (strlen(utfval.str) == 3) {  // One hangul char has 3byte.
+		int unicode = UnicodeFromUTF8(reinterpret_cast<unsigned char *>(utfval.str));
+		// Korean character ranges which are used for the first preedit chars.
+		// http://www.programminginkorean.com/programming/hangul-in-unicode/
+		bool HangulJamo = (0x1100 <= unicode && unicode <= 0x11FF);
+		bool HangulCompatibleJamo = (0x3130 <= unicode && unicode <= 0x318F);
+		bool HangulJamoExtendedA = (0xA960 <= unicode && unicode <= 0xA97F);
+		bool HangulJamoExtendedB = (0xD7B0 <= unicode && unicode <= 0xD7FF);
+		bool HangulSyllable = (0xAC00 <= unicode && unicode <= 0xD7A3);
+		koreanIME = (HangulJamo | HangulCompatibleJamo  | HangulSyllable
+					| HangulJamoExtendedA | HangulJamoExtendedB);
+	}
+	return koreanIME;
+}
+
 void ScintillaGTK::CommitThis(char *utfVal) {
 	try {
 		//~ fprintf(stderr, "Commit '%s'\n", utfVal);
+		if (pdoc->TentativeActive()) {
+			pdoc->TentativeUndo();
+		}
+
+		view.imeCaretBlockOverride = false;
+
 		if (IsUnicodeMode()) {
 			AddCharUTF(utfVal, strlen(utfVal));
 		} else {
@@ -2285,7 +2355,7 @@ void ScintillaGTK::CommitThis(char *utfVal) {
 			if (*source) {
 				Converter conv(source, "UTF-8", true);
 				if (conv) {
-					char localeVal[4] = "\0\0\0";
+					char localeVal[maxLenInputIME * 2];
 					char *pin = utfVal;
 					size_t inLeft = strlen(utfVal);
 					char *pout = localeVal;
@@ -2293,15 +2363,14 @@ void ScintillaGTK::CommitThis(char *utfVal) {
 					size_t conversions = conv.Convert(&pin, &inLeft, &pout, &outLeft);
 					if (conversions != ((size_t)(-1))) {
 						*pout = '\0';
-						for (int i = 0; localeVal[i]; i++) {
-							AddChar(localeVal[i]);
-						}
+						AddCharUTF(localeVal, strlen(localeVal));
 					} else {
 						fprintf(stderr, "Conversion failed '%s'\n", utfVal);
 					}
 				}
 			}
 		}
+		ShowCaretAtCurrentPosition();
 	} catch (...) {
 		errorStatus = SC_STATUS_FAILURE;
 	}
@@ -2313,36 +2382,99 @@ void ScintillaGTK::Commit(GtkIMContext *, char  *str, ScintillaGTK *sciThis) {
 
 void ScintillaGTK::PreeditChangedThis() {
 	try {
-		gchar *str;
-		PangoAttrList *attrs;
-		gint cursor_pos;
-		gtk_im_context_get_preedit_string(im_context, &str, &attrs, &cursor_pos);
-		if (strlen(str) > 0) {
-			PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), str);
-			pango_layout_set_attributes(layout, attrs);
-
-			gint w, h;
-			pango_layout_get_pixel_size(layout, &w, &h);
-			g_object_unref(layout);
-
-			gint x, y;
-			gdk_window_get_origin(PWindow(wText), &x, &y);
-
-			Point pt = PointMainCaret();
-			if (pt.x < 0)
-				pt.x = 0;
-			if (pt.y < 0)
-				pt.y = 0;
-
-			gtk_window_move(GTK_WINDOW(PWidget(wPreedit)), x + pt.x, y + pt.y);
-			gtk_window_resize(GTK_WINDOW(PWidget(wPreedit)), w, h);
-			gtk_widget_show(PWidget(wPreedit));
-			gtk_widget_queue_draw_area(PWidget(wPreeditDraw), 0, 0, w, h);
-		} else {
-			gtk_widget_hide(PWidget(wPreedit));
+		if (KoreanIME()) {
+			// Copy & paste by johnsonj.
+			// Great thanks to
+			// jiniya from http://www.jiniya.net/tt/494  for DBCS input with AddCharUTF().
+			// BLUEnLIVE from http://zockr.tistory.com/1118 for UNDO and inOverstrike.
+			view.imeCaretBlockOverride = false; // If backspace.
+
+			if (pdoc->TentativeActive()) {
+				pdoc->TentativeUndo();
+			} else {
+				// No tentative undo means start of this composition so
+				// fill in any virtual spaces.
+				bool tmpOverstrike = inOverstrike;
+				inOverstrike = false;   // Not allowed to be deleted twice.
+				AddCharUTF("", 0);
+				inOverstrike = tmpOverstrike;
+			}
+
+			PreEditString utfval(im_context);
+
+			if (strlen(utfval.str) >  maxLenInputIME * 3) {
+				return; // Do not allow over 200 chars.
+			}
+
+			char localeVal[maxLenInputIME * 2];
+			char *hanval = (char *)"";
+
+			if (IsUnicodeMode()) {
+				hanval = utfval.str;
+			} else {
+				const char *source = CharacterSetID();
+				if (*source) {
+					Converter conv(source, "UTF-8", true);
+					if (conv) {
+						char *pin = utfval.str;
+						size_t inLeft = strlen(utfval.str);
+						char *pout = localeVal;
+						size_t outLeft = sizeof(localeVal);
+						size_t conversions = conv.Convert(&pin, &inLeft, &pout, &outLeft);
+						if (conversions != ((size_t)(-1))) {
+							*pout = '\0';
+							hanval = localeVal;
+						} else {
+							fprintf(stderr, "Conversion failed '%s'\n", utfval.str);
+						}
+					}
+				}
+			}
+
+			if (!pdoc->TentativeActive()) {
+				pdoc->TentativeStart();
+			}
+
+			bool tmpRecordingMacro = recordingMacro;
+			recordingMacro = false;
+			int hanlen = strlen(hanval);
+			AddCharUTF(hanval, hanlen);
+			recordingMacro = tmpRecordingMacro;
+
+			// For block caret which means KoreanIME is in composition.
+			view.imeCaretBlockOverride = true;
+			for (size_t r = 0; r < sel.Count(); r++) {
+				int positionInsert = sel.Range(r).Start().Position();
+				sel.Range(r).caret.SetPosition(positionInsert - hanlen);
+				sel.Range(r).anchor.SetPosition(positionInsert - hanlen);
+			}
+		} else { // Original code follows  for other IMEs.
+			PreEditString pes(im_context);
+			if (strlen(pes.str) > 0) {
+				PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), pes.str);
+				pango_layout_set_attributes(layout, pes.attrs);
+
+				gint w, h;
+				pango_layout_get_pixel_size(layout, &w, &h);
+				g_object_unref(layout);
+
+				gint x, y;
+				gdk_window_get_origin(PWindow(wText), &x, &y);
+
+				Point pt = PointMainCaret();
+				if (pt.x < 0)
+					pt.x = 0;
+				if (pt.y < 0)
+					pt.y = 0;
+
+				gtk_window_move(GTK_WINDOW(PWidget(wPreedit)), x + pt.x, y + pt.y);
+				gtk_window_resize(GTK_WINDOW(PWidget(wPreedit)), w, h);
+				gtk_widget_show(PWidget(wPreedit));
+				gtk_widget_queue_draw_area(PWidget(wPreeditDraw), 0, 0, w, h);
+			} else {
+				gtk_widget_hide(PWidget(wPreedit));
+			}
 		}
-		g_free(str);
-		pango_attr_list_unref(attrs);
 	} catch (...) {
 		errorStatus = SC_STATUS_FAILURE;
 	}
@@ -2711,8 +2843,8 @@ void ScintillaGTK::DragDataGet(GtkWidget *widget, GdkDragContext *context,
 	}
 }
 
-int ScintillaGTK::TimeOut(ScintillaGTK *sciThis) {
-	sciThis->Tick();
+int ScintillaGTK::TimeOut(TimeThunk *tt) {
+	tt->scintilla->TickFor(tt->reason);
 	return 1;
 }
 


Modified: scintilla/include/SciLexer.h
18 lines changed, 18 insertions(+), 0 deletions(-)
===================================================================
@@ -127,6 +127,7 @@
 #define SCLEX_DMAP 112
 #define SCLEX_AS 113
 #define SCLEX_DMIS 114
+#define SCLEX_REGISTRY 115
 #define SCLEX_AUTOMATIC 1000
 #define SCE_P_DEFAULT 0
 #define SCE_P_COMMENTLINE 1
@@ -906,6 +907,7 @@
 #define SCE_KIX_KEYWORD 7
 #define SCE_KIX_FUNCTIONS 8
 #define SCE_KIX_OPERATOR 9
+#define SCE_KIX_COMMENTSTREAM 10
 #define SCE_KIX_IDENTIFIER 31
 #define SCE_GC_DEFAULT 0
 #define SCE_GC_COMMENTLINE 1
@@ -1692,6 +1694,9 @@
 #define SCE_RUST_LIFETIME 18
 #define SCE_RUST_MACRO 19
 #define SCE_RUST_LEXERROR 20
+#define SCE_RUST_BYTESTRING 21
+#define SCE_RUST_BYTESTRINGR 22
+#define SCE_RUST_BYTECHARACTER 23
 #define SCE_DMAP_DEFAULT 0
 #define SCE_DMAP_COMMENT 1
 #define SCE_DMAP_NUMBER 2
@@ -1713,6 +1718,19 @@
 #define SCE_DMIS_UNSUPPORTED_MAJOR 7
 #define SCE_DMIS_UNSUPPORTED_MINOR 8
 #define SCE_DMIS_LABEL 9
+#define SCE_REG_DEFAULT 0
+#define SCE_REG_COMMENT 1
+#define SCE_REG_VALUENAME 2
+#define SCE_REG_STRING 3
+#define SCE_REG_HEXDIGIT 4
+#define SCE_REG_VALUETYPE 5
+#define SCE_REG_ADDEDKEY 6
+#define SCE_REG_DELETEDKEY 7
+#define SCE_REG_ESCAPED 8
+#define SCE_REG_KEYPATH_GUID 9
+#define SCE_REG_STRING_GUID 10
+#define SCE_REG_PARAMETER 11
+#define SCE_REG_OPERATOR 12
 /* --Autogenerated -- end of section automatically generated from Scintilla.iface */
 
 #endif


Modified: scintilla/include/Scintilla.h
15 lines changed, 12 insertions(+), 3 deletions(-)
===================================================================
@@ -18,9 +18,9 @@ extern "C" {
 #if defined(_WIN32)
 /* Return false on failure: */
 int Scintilla_RegisterClasses(void *hInstance);
-int Scintilla_ReleaseResources();
+int Scintilla_ReleaseResources(void);
 #endif
-int Scintilla_LinkLexers();
+int Scintilla_LinkLexers(void);
 
 #ifdef __cplusplus
 }
@@ -92,6 +92,9 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam,
 #define SCI_SETBUFFEREDDRAW 2035
 #define SCI_SETTABWIDTH 2036
 #define SCI_GETTABWIDTH 2121
+#define SCI_CLEARTABSTOPS 2675
+#define SCI_ADDTABSTOP 2676
+#define SCI_GETNEXTTABSTOP 2677
 #define SC_CP_UTF8 65001
 #define SCI_SETCODEPAGE 2037
 #define MARKER_MAX 31
@@ -517,6 +520,11 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam,
 #define SCI_APPENDTEXT 2282
 #define SCI_GETTWOPHASEDRAW 2283
 #define SCI_SETTWOPHASEDRAW 2284
+#define SC_PHASES_ONE 0
+#define SC_PHASES_TWO 1
+#define SC_PHASES_MULTIPLE 2
+#define SCI_GETPHASESDRAW 2673
+#define SCI_SETPHASESDRAW 2674
 #define SC_EFF_QUALITY_MASK 0xF
 #define SC_EFF_QUALITY_DEFAULT 0
 #define SC_EFF_QUALITY_NON_ANTIALIASED 1
@@ -952,7 +960,8 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam,
 #define SC_MOD_CONTAINER 0x40000
 #define SC_MOD_LEXERSTATE 0x80000
 #define SC_MOD_INSERTCHECK 0x100000
-#define SC_MODEVENTMASKALL 0x1FFFFF
+#define SC_MOD_CHANGETABSTOPS 0x200000
+#define SC_MODEVENTMASKALL 0x3FFFFF
 #define SC_UPDATE_CONTENT 0x1
 #define SC_UPDATE_SELECTION 0x2
 #define SC_UPDATE_V_SCROLL 0x4


Modified: scintilla/include/Scintilla.iface
48 lines changed, 46 insertions(+), 2 deletions(-)
===================================================================
@@ -226,6 +226,15 @@ set void SetTabWidth=2036(int tabWidth,)
 # Retrieve the visible size of a tab.
 get int GetTabWidth=2121(,)
 
+# Clear explicit tabstops on a line.
+fun void ClearTabStops=2675(int line,)
+
+# Add an explicit tab stop for a line.
+fun void AddTabStop=2676(int line, int x)
+
+# Find the next explicit tab stop position on a line after a position.
+fun int GetNextTabStop=2677(int line, int x)
+
 # The SC_CP_UTF8 value can be used to enter Unicode mode.
 # This is the same value as CP_UTF8 in Windows
 val SC_CP_UTF8=65001
@@ -1291,13 +1300,27 @@ get bool GetVScrollBar=2281(,)
 # Append a string to the end of the document without changing the selection.
 fun void AppendText=2282(int length, string text)
 
-# Is drawing done in two phases with backgrounds drawn before faoregrounds?
+# Is drawing done in two phases with backgrounds drawn before foregrounds?
 get bool GetTwoPhaseDraw=2283(,)
 
 # In twoPhaseDraw mode, drawing is performed in two phases, first the background
 # and then the foreground. This avoids chopping off characters that overlap the next run.
 set void SetTwoPhaseDraw=2284(bool twoPhase,)
 
+enu FontQuality=SC_PHASES_
+val SC_PHASES_ONE=0
+val SC_PHASES_TWO=1
+val SC_PHASES_MULTIPLE=2
+
+# How many phases is drawing done in?
+get int GetPhasesDraw=2673(,)
+
+# In one phase draw, text is drawn in a series of rectangular blocks with no overlap.
+# In two phase draw, text is drawn in a series of lines allowing runs to overlap horizontally.
+# In multiple phase draw, each element is drawn over the whole drawing area, allowing text
+# to overlap from one line to the next.
+set void SetPhasesDraw=2674(int phases,)
+
 # Control font anti-aliasing.
 
 enu FontQuality=SC_EFF_
@@ -2509,7 +2532,8 @@ val SC_MOD_CHANGEANNOTATION=0x20000
 val SC_MOD_CONTAINER=0x40000
 val SC_MOD_LEXERSTATE=0x80000
 val SC_MOD_INSERTCHECK=0x100000
-val SC_MODEVENTMASKALL=0x1FFFFF
+val SC_MOD_CHANGETABSTOPS=0x200000
+val SC_MODEVENTMASKALL=0x3FFFFF
 
 enu Update=SC_UPDATE_
 val SC_UPDATE_CONTENT=0x1
@@ -2675,6 +2699,7 @@ val SCLEX_RUST=111
 val SCLEX_DMAP=112
 val SCLEX_AS=113
 val SCLEX_DMIS=114
+val SCLEX_REGISTRY=115
 
 # When a lexer specifies its language as SCLEX_AUTOMATIC it receives a
 # value assigned in sequence from SCLEX_AUTOMATIC+1.
@@ -3567,6 +3592,7 @@ val SCE_KIX_MACRO=6
 val SCE_KIX_KEYWORD=7
 val SCE_KIX_FUNCTIONS=8
 val SCE_KIX_OPERATOR=9
+val SCE_KIX_COMMENTSTREAM=10
 val SCE_KIX_IDENTIFIER=31
 # Lexical states for SCLEX_GUI4CLI
 lex Gui4Cli=SCLEX_GUI4CLI SCE_GC_
@@ -4443,6 +4469,9 @@ val SCE_RUST_IDENTIFIER=17
 val SCE_RUST_LIFETIME=18
 val SCE_RUST_MACRO=19
 val SCE_RUST_LEXERROR=20
+val SCE_RUST_BYTESTRING=21
+val SCE_RUST_BYTESTRINGR=22
+val SCE_RUST_BYTECHARACTER=23
 # Lexical states for SCLEX_DMAP
 lex DMAP=SCLEX_DMAP SCE_DMAP_
 val SCE_DMAP_DEFAULT=0
@@ -4468,6 +4497,21 @@ val SCE_DMIS_MINORWORD=6
 val SCE_DMIS_UNSUPPORTED_MAJOR=7
 val SCE_DMIS_UNSUPPORTED_MINOR=8
 val SCE_DMIS_LABEL=9
+# Lexical states for SCLEX_REGISTRY
+lex REG=SCLEX_REGISTRY SCE_REG_
+val SCE_REG_DEFAULT=0
+val SCE_REG_COMMENT=1
+val SCE_REG_VALUENAME=2
+val SCE_REG_STRING=3
+val SCE_REG_HEXDIGIT=4
+val SCE_REG_VALUETYPE=5
+val SCE_REG_ADDEDKEY=6
+val SCE_REG_DELETEDKEY=7
+val SCE_REG_ESCAPED=8
+val SCE_REG_KEYPATH_GUID=9
+val SCE_REG_STRING_GUID=10
+val SCE_REG_PARAMETER=11
+val SCE_REG_OPERATOR=12
 
 # Events
 


Modified: scintilla/lexers/LexHTML.cxx
12 lines changed, 10 insertions(+), 2 deletions(-)
===================================================================
@@ -822,19 +822,27 @@ static void ColouriseHyperTextDoc(unsigned int startPos, int length, int initSty
 		// handle start of Mako comment line
 		if (isMako && ch == '#' && chNext == '#') {
 			makoComment = 1;
+			state = SCE_HP_COMMENTLINE;
 		}
 
 		// handle end of Mako comment line
 		else if (isMako && makoComment && (ch == '\r' || ch == '\n')) {
 			makoComment = 0;
-			styler.ColourTo(i, SCE_HP_COMMENTLINE);
-			state = SCE_HP_DEFAULT;
+			styler.ColourTo(i, StateToPrint);
+			if (scriptLanguage == eScriptPython) {
+				state = SCE_HP_DEFAULT;
+			} else {
+				state = SCE_H_DEFAULT;
+			}
 		}
 
 		// Allow falling through to mako handling code if newline is going to end a block
 		if (((ch == '\r' && chNext != '\n') || (ch == '\n')) &&
 			(!isMako || (0 != strcmp(makoBlockType, "%")))) {
 		}
+		// Ignore everything in mako comment until the line ends
+		else if (isMako && makoComment) {
+		}
 
 		// generic end of script processing
 		else if ((inScriptType == eNonHtmlScript) && (ch == '<') && (chNext == '/')) {


Modified: scintilla/lexers/LexMatlab.cxx
5 lines changed, 4 insertions(+), 1 deletions(-)
===================================================================
@@ -12,6 +12,9 @@
  **   - added ... displayed as a comment
  **   - removed unused IsAWord functions
  **   - added some comments
+ **
+ ** Changes by John Donoghue 2014/08/01
+ **   - fix allowed transpose ' after {} operator
  **/
 // Copyright 1998-2001 by Neil Hodgson <neilh at scintilla.org>
 // The License.txt file describes the conditions under which this software may be distributed.
@@ -218,7 +221,7 @@ static void ColouriseMatlabOctaveDoc(
 			} else if (isalpha(sc.ch)) {
 				sc.SetState(SCE_MATLAB_KEYWORD);
 			} else if (isoperator(static_cast<char>(sc.ch)) || sc.ch == '@' || sc.ch == '\\') {
-				if (sc.ch == ')' || sc.ch == ']') {
+				if (sc.ch == ')' || sc.ch == ']' || sc.ch == '}') {
 					transpose = true;
 				} else {
 					transpose = false;


Modified: scintilla/lexers/LexRuby.cxx
36 lines changed, 35 insertions(+), 1 deletions(-)
===================================================================
@@ -882,6 +882,31 @@ static void ColouriseRbDoc(unsigned int startPos, int length, int initStyle,
 					preferRE = false;
                 } else if (isSafeWordcharOrHigh(chNext)) {
 					state = SCE_RB_SYMBOL;
+                } else if ((chNext == '@' || chNext == '$') &&
+                            isSafeWordcharOrHigh(chNext2)) {
+                    // instance and global variable followed by an identifier
+                    advance_char(i, ch, chNext, chNext2);
+                    state = SCE_RB_SYMBOL;
+                } else if (((chNext == '@' && chNext2 == '@')  ||
+                            (chNext == '$' && chNext2 == '-')) &&
+                           isSafeWordcharOrHigh(styler.SafeGetCharAt(i+3))) {
+                    // class variables and special global variable "$-IDENTCHAR"
+                    state = SCE_RB_SYMBOL;
+                    // $-IDENTCHAR doesn't continue past the IDENTCHAR
+                    if (chNext == '$') {
+                        styler.ColourTo(i+3, SCE_RB_SYMBOL);
+                        state = SCE_RB_DEFAULT;
+                    }
+                    i += 3;
+                    ch = styler.SafeGetCharAt(i);
+                    chNext = styler.SafeGetCharAt(i+1);
+                } else if (chNext == '$' && strchr("_~*$?!@/\\;,.=:<>\"&`'+", chNext2)) {
+                    // single-character special global variables
+                    i += 2;
+                    ch = chNext2;
+                    chNext = styler.SafeGetCharAt(i+1);
+                    styler.ColourTo(i, SCE_RB_SYMBOL);
+                    state = SCE_RB_DEFAULT;
                 } else if (strchr("[*!~+-*/%=<>&^|", chNext)) {
                     // Do the operator analysis in-line, looking ahead
                     // Based on the table in pickaxe 2nd ed., page 339
@@ -1260,7 +1285,16 @@ static void ColouriseRbDoc(unsigned int startPos, int length, int initStyle,
         } else if (state == SCE_RB_CLASS_VAR
                    || state == SCE_RB_INSTANCE_VAR
                    || state == SCE_RB_SYMBOL) {
-            if (!isSafeWordcharOrHigh(ch)) {
+            if (state == SCE_RB_SYMBOL &&
+                 // FIDs suffices '?' and '!'
+                (((ch == '!' || ch == '?') && chNext != '=') ||
+                 // identifier suffix '='
+                 (ch == '=' && (chNext != '~' && chNext != '>' &&
+                               (chNext != '=' || chNext2 == '>'))))) {
+                styler.ColourTo(i, state);
+                state = SCE_RB_DEFAULT;
+                preferRE = false;
+            } else if (!isSafeWordcharOrHigh(ch)) {
                 styler.ColourTo(i - 1, state);
                 redo_char(i, ch, chNext, chNext2, state); // pass by ref
                 preferRE = false;


Modified: scintilla/lexers/LexRust.cxx
105 lines changed, 69 insertions(+), 36 deletions(-)
===================================================================
@@ -230,7 +230,9 @@ static void ScanIdentifier(Accessor& styler, int& pos, WordList *keywords) {
 	}
 }
 
-static void ScanDigits(Accessor& styler, int& pos, int base) {
+/* Scans a sequence of digits, returning true if it found any. */
+static bool ScanDigits(Accessor& styler, int& pos, int base) {
+	int old_pos = pos;
 	for (;;) {
 		int c = styler.SafeGetCharAt(pos, '\0');
 		if (IsADigit(c, base) || c == '_')
@@ -238,13 +240,17 @@ static void ScanDigits(Accessor& styler, int& pos, int base) {
 		else
 			break;
 	}
+	return old_pos != pos;
 }
 
+/* Scans an integer and floating point literals. */
 static void ScanNumber(Accessor& styler, int& pos) {
 	int base = 10;
 	int c = styler.SafeGetCharAt(pos, '\0');
 	int n = styler.SafeGetCharAt(pos + 1, '\0');
 	bool error = false;
+	/* Scan the prefix, thus determining the base.
+	 * 10 is default if there's no prefix. */
 	if (c == '0' && n == 'x') {
 		pos += 2;
 		base = 16;
@@ -255,8 +261,11 @@ static void ScanNumber(Accessor& styler, int& pos) {
 		pos += 2;
 		base = 8;
 	}
-	int old_pos = pos;
-	ScanDigits(styler, pos, base);
+
+	/* Scan initial digits. The literal is malformed if there are none. */
+	error |= !ScanDigits(styler, pos, base);
+	/* See if there's an integer suffix. We mimic the Rust's lexer
+	 * and munch it even if there was an error above. */
 	c = styler.SafeGetCharAt(pos, '\0');
 	if (c == 'u' || c == 'i') {
 		pos++;
@@ -271,14 +280,22 @@ static void ScanNumber(Accessor& styler, int& pos) {
 		} else if (c == '6' && n == '4') {
 			pos += 2;
 		}
-	} else {
+	/* See if it's a floating point literal. These literals have to be base 10.
+	 */
+	} else if (!error) {
+		/* If there's a period, it's a floating point literal unless it's
+		 * followed by an identifier (meaning this is a method call, e.g.
+		 * `1.foo()`) or another period, in which case it's a range (e.g. 1..2) 
+		 */
 		n = styler.SafeGetCharAt(pos + 1, '\0');
 		if (c == '.' && !(IsIdentifierStart(n) || n == '.')) {
 			error |= base != 10;
 			pos++;
+			/* It's ok to have no digits after the period. */
 			ScanDigits(styler, pos, 10);
 		}
 
+		/* Look for the exponentiation. */
 		c = styler.SafeGetCharAt(pos, '\0');
 		if (c == 'e' || c == 'E') {
 			error |= base != 10;
@@ -286,13 +303,11 @@ static void ScanNumber(Accessor& styler, int& pos) {
 			c = styler.SafeGetCharAt(pos, '\0');
 			if (c == '-' || c == '+')
 				pos++;
-			int old_pos = pos;
-			ScanDigits(styler, pos, 10);
-			if (old_pos == pos) {
-				error = true;
-			}
+			/* It is invalid to have no digits in the exponent. */
+			error |= !ScanDigits(styler, pos, 10);
 		}
 		
+		/* Scan the floating point suffix. */
 		c = styler.SafeGetCharAt(pos, '\0');
 		if (c == 'f') {
 			error |= base != 10;
@@ -308,9 +323,7 @@ static void ScanNumber(Accessor& styler, int& pos) {
 			}
 		}
 	}
-	if (old_pos == pos) {
-		error = true;
-	}
+
 	if (error)
 		styler.ColourTo(pos - 1, SCE_RUST_LEXERROR);
 	else
@@ -351,7 +364,7 @@ static bool IsValidCharacterEscape(int c) {
 }
 
 static bool IsValidStringEscape(int c) {
-	return IsValidCharacterEscape(c) || c == '\n';
+	return IsValidCharacterEscape(c) || c == '\n' || c == '\r';
 }
 
 static bool ScanNumericEscape(Accessor &styler, int& pos, int num_digits, bool stop_asap) {
@@ -373,12 +386,12 @@ static bool ScanNumericEscape(Accessor &styler, int& pos, int num_digits, bool s
 
 /* This is overly permissive for character literals in order to accept UTF-8 encoded
  * character literals. */
-static void ScanCharacterLiteralOrLifetime(Accessor &styler, int& pos) {
+static void ScanCharacterLiteralOrLifetime(Accessor &styler, int& pos, bool ascii_only) {
 	pos++;
 	int c = styler.SafeGetCharAt(pos, '\0');
 	int n = styler.SafeGetCharAt(pos + 1, '\0');
 	bool done = false;
-	bool valid_lifetime = IsIdentifierStart(c);
+	bool valid_lifetime = !ascii_only && IsIdentifierStart(c);
 	bool valid_char = true;
 	bool first = true;
 	while (!done) {
@@ -390,10 +403,10 @@ static void ScanCharacterLiteralOrLifetime(Accessor &styler, int& pos) {
 				} else if (n == 'x') {
 					pos += 2;
 					valid_char = ScanNumericEscape(styler, pos, 2, false);
-				} else if (n == 'u') {
+				} else if (n == 'u' && !ascii_only) {
 					pos += 2;
 					valid_char = ScanNumericEscape(styler, pos, 4, false);
-				} else if (n == 'U') {
+				} else if (n == 'U' && !ascii_only) {
 					pos += 2;
 					valid_char = ScanNumericEscape(styler, pos, 8, false);
 				} else {
@@ -412,7 +425,10 @@ static void ScanCharacterLiteralOrLifetime(Accessor &styler, int& pos) {
 				done = true;
 				break;
 			default:
-				if (!IsIdentifierContinue(c) && !first) {
+				if (ascii_only && !IsASCII((char)c)) {
+					done = true;
+					valid_char = false;
+				} else if (!IsIdentifierContinue(c) && !first) {
 					done = true;
 				} else {
 					pos++;
@@ -433,7 +449,7 @@ static void ScanCharacterLiteralOrLifetime(Accessor &styler, int& pos) {
 		styler.ColourTo(pos - 1, SCE_RUST_LIFETIME);
 	} else if (valid_char) {
 		pos++;
-		styler.ColourTo(pos - 1, SCE_RUST_CHARACTER);
+		styler.ColourTo(pos - 1, ascii_only ? SCE_RUST_BYTECHARACTER : SCE_RUST_CHARACTER);
 	} else {
 		styler.ColourTo(pos - 1, SCE_RUST_LEXERROR);
 	}
@@ -542,7 +558,7 @@ static void ScanComments(Accessor &styler, int& pos, int max) {
 		ResumeBlockComment(styler, pos, max, UnknownComment, 1);
 }
 
-static void ResumeString(Accessor &styler, int& pos, int max) {
+static void ResumeString(Accessor &styler, int& pos, int max, bool ascii_only) {
 	int c = styler.SafeGetCharAt(pos, '\0');
 	bool error = false;
 	while (c != '"' && !error) {
@@ -559,10 +575,10 @@ static void ResumeString(Accessor &styler, int& pos, int max) {
 			} else if (n == 'x') {
 				pos += 2;
 				error = !ScanNumericEscape(styler, pos, 2, true);
-			} else if (n == 'u') {
+			} else if (n == 'u' && !ascii_only) {
 				pos += 2;
 				error = !ScanNumericEscape(styler, pos, 4, true);
-			} else if (n == 'U') {
+			} else if (n == 'U' && !ascii_only) {
 				pos += 2;
 				error = !ScanNumericEscape(styler, pos, 8, true);
 			} else {
@@ -570,16 +586,19 @@ static void ResumeString(Accessor &styler, int& pos, int max) {
 				error = true;
 			}
 		} else {
-			pos++;
+			if (ascii_only && !IsASCII((char)c))
+				error = true;
+			else
+				pos++;
 		}
 		c = styler.SafeGetCharAt(pos, '\0');
 	}
 	if (!error)
 		pos++;
-	styler.ColourTo(pos - 1, SCE_RUST_STRING);
+	styler.ColourTo(pos - 1, ascii_only ? SCE_RUST_BYTESTRING : SCE_RUST_STRING);
 }
 
-static void ResumeRawString(Accessor &styler, int& pos, int max, int num_hashes) {
+static void ResumeRawString(Accessor &styler, int& pos, int max, int num_hashes, bool ascii_only) {
 	for (;;) {
 		if (pos == styler.LineEnd(styler.GetLine(pos)))
 			styler.SetLineState(styler.GetLine(pos), num_hashes);
@@ -594,19 +613,20 @@ static void ResumeRawString(Accessor &styler, int& pos, int max, int num_hashes)
 			}
 			if (trailing_num_hashes == num_hashes) {
 				styler.SetLineState(styler.GetLine(pos), 0);
-				styler.ColourTo(pos - 1, SCE_RUST_STRINGR);
 				break;
 			}
 		} else if (pos >= max) {
-			styler.ColourTo(pos - 1, SCE_RUST_STRINGR);
 			break;
-		} else {		
+		} else {
+			if (ascii_only && !IsASCII((char)c)) 
+				break;
 			pos++;
 		}
 	}
+	styler.ColourTo(pos - 1, ascii_only ? SCE_RUST_BYTESTRINGR : SCE_RUST_STRINGR);
 }
 
-static void ScanRawString(Accessor &styler, int& pos, int max) {
+static void ScanRawString(Accessor &styler, int& pos, int max, bool ascii_only) {
 	pos++;
 	int num_hashes = 0;
 	while (styler.SafeGetCharAt(pos, '\0') == '#') {
@@ -617,7 +637,7 @@ static void ScanRawString(Accessor &styler, int& pos, int max) {
 		styler.ColourTo(pos - 1, SCE_RUST_LEXERROR);
 	} else {
 		pos++;
-		ResumeRawString(styler, pos, max, num_hashes);
+		ResumeRawString(styler, pos, max, num_hashes, ascii_only);
 	}
 }
 
@@ -635,9 +655,13 @@ void SCI_METHOD LexerRust::Lex(unsigned int startPos, int length, int initStyle,
 	} else if (initStyle == SCE_RUST_COMMENTLINE || initStyle == SCE_RUST_COMMENTLINEDOC) {
 		ResumeLineComment(styler, pos, max, initStyle == SCE_RUST_COMMENTLINEDOC ? DocComment : NotDocComment);
 	} else if (initStyle == SCE_RUST_STRING) {
-		ResumeString(styler, pos, max);
+		ResumeString(styler, pos, max, false);
+	} else if (initStyle == SCE_RUST_BYTESTRING) {
+		ResumeString(styler, pos, max, true);
 	} else if (initStyle == SCE_RUST_STRINGR) {
-		ResumeRawString(styler, pos, max, styler.GetLineState(styler.GetLine(pos) - 1));
+		ResumeRawString(styler, pos, max, styler.GetLineState(styler.GetLine(pos) - 1), false);
+	} else if (initStyle == SCE_RUST_BYTESTRINGR) {
+		ResumeRawString(styler, pos, max, styler.GetLineState(styler.GetLine(pos) - 1), true);
 	}
 
 	while (pos < max) {
@@ -645,7 +669,7 @@ void SCI_METHOD LexerRust::Lex(unsigned int startPos, int length, int initStyle,
 		int n = styler.SafeGetCharAt(pos + 1, '\0');
 		int n2 = styler.SafeGetCharAt(pos + 2, '\0');
 
-		if (pos == 0 && c == '#' && n == '!') {
+		if (pos == 0 && c == '#' && n == '!' && n2 != '[') {
 			pos += 2;
 			ResumeLineComment(styler, pos, max, NotDocComment);
 		} else if (IsWhitespace(c)) {
@@ -653,7 +677,16 @@ void SCI_METHOD LexerRust::Lex(unsigned int startPos, int length, int initStyle,
 		} else if (c == '/' && (n == '/' || n == '*')) {
 			ScanComments(styler, pos, max);
 		} else if (c == 'r' && (n == '#' || n == '"')) {
-			ScanRawString(styler, pos, max);
+			ScanRawString(styler, pos, max, false);
+		} else if (c == 'b' && n == 'r' && (n2 == '#' || n2 == '"')) {
+			pos++;
+			ScanRawString(styler, pos, max, true);
+		} else if (c == 'b' && n == '"') {
+			pos += 2;
+			ResumeString(styler, pos, max, true);
+		} else if (c == 'b' && n == '\'') {
+			pos++;
+			ScanCharacterLiteralOrLifetime(styler, pos, true);
 		} else if (IsIdentifierStart(c)) {
 			ScanIdentifier(styler, pos, keywords);
 		} else if (IsADigit(c)) {
@@ -668,10 +701,10 @@ void SCI_METHOD LexerRust::Lex(unsigned int startPos, int length, int initStyle,
 			pos++;
 			styler.ColourTo(pos - 1, SCE_RUST_OPERATOR);
 		} else if (c == '\'') {
-			ScanCharacterLiteralOrLifetime(styler, pos);
+			ScanCharacterLiteralOrLifetime(styler, pos, false);
 		} else if (c == '"') {
 			pos++;
-			ResumeString(styler, pos, max);
+			ResumeString(styler, pos, max, false);
 		} else {
 			pos++;
 			styler.ColourTo(pos - 1, SCE_RUST_LEXERROR);


Modified: scintilla/lexlib/LexerModule.h
7 lines changed, 6 insertions(+), 1 deletions(-)
===================================================================
@@ -67,7 +67,12 @@ inline int Maximum(int a, int b) {
 
 // Shut up annoying Visual C++ warnings:
 #ifdef _MSC_VER
-#pragma warning(disable: 4244 4309)
+#pragma warning(disable: 4244 4309 4456 4457)
+#endif
+
+// Turn off shadow warnings for lexers as may be maintained by others
+#if defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Wshadow"
 #endif
 
 #ifdef SCI_NAMESPACE


Modified: scintilla/makefile.win32
3 lines changed, 3 insertions(+), 0 deletions(-)
===================================================================
@@ -130,10 +130,13 @@ SRCOBJS=\
 	Decoration.o \
 	Document.o \
 	Editor.o \
+	EditModel.o \
+	EditView.o \
 	ExternalLexer.o \
 	Indicator.o \
 	KeyMap.o \
 	LineMarker.o \
+	MarginView.o \
 	PerLine.o \
 	PositionCache.o \
 	RESearch.o \


Modified: scintilla/scintilla_changes.patch
3 lines changed, 2 insertions(+), 1 deletions(-)
===================================================================
@@ -31,7 +31,7 @@ diff --git b/scintilla/src/Catalogue.cxx a/scintilla/src/Catalogue.cxx
 index 41d5d54..70ce3bc 100644
 --- scintilla/src/Catalogue.cxx
 +++ scintilla/src/Catalogue.cxx
-@@ -76,115 +76,48 @@ int Scintilla_LinkLexers() {
+@@ -76,116 +76,48 @@ int Scintilla_LinkLexers() {
  
  //++Autogenerated -- run scripts/LexGen.py to regenerate
  //**\(\tLINK_LEXER(\*);\n\)
@@ -123,6 +123,7 @@ index 41d5d54..70ce3bc 100644
  	LINK_LEXER(lmPython);
  	LINK_LEXER(lmR);
 -	LINK_LEXER(lmREBOL);
+-	LINK_LEXER(lmRegistry);
  	LINK_LEXER(lmRuby);
  	LINK_LEXER(lmRust);
 -	LINK_LEXER(lmScriptol);


Modified: scintilla/src/CellBuffer.cxx
40 lines changed, 39 insertions(+), 1 deletions(-)
===================================================================
@@ -144,6 +144,7 @@ UndoHistory::UndoHistory() {
 	currentAction = 0;
 	undoSequenceDepth = 0;
 	savePoint = 0;
+	tentativePoint = -1;
 
 	actions[currentAction].Create(startAction);
 }
@@ -194,7 +195,7 @@ const char *UndoHistory::AppendAction(actionType at, int position, const char *d
 			// Visual Studio 2013 Code Analysis wrongly believes actions can be NULL at its next reference
 			__analysis_assume(actions);
 #endif
-			if (currentAction == savePoint) {
+			if ((currentAction == savePoint) || (currentAction == tentativePoint)) {
 				currentAction++;
 			} else if (!actions[currentAction].mayCoalesce) {
 				// Not allowed to coalesce if this set
@@ -282,6 +283,7 @@ void UndoHistory::DeleteUndoHistory() {
 	currentAction = 0;
 	actions[currentAction].Create(startAction);
 	savePoint = 0;
+	tentativePoint = -1;
 }
 
 void UndoHistory::SetSavePoint() {
@@ -292,6 +294,26 @@ bool UndoHistory::IsSavePoint() const {
 	return savePoint == currentAction;
 }
 
+void UndoHistory::TentativeStart() {
+	tentativePoint = currentAction;
+}
+
+void UndoHistory::TentativeCommit() {
+	tentativePoint = -1;
+	// Truncate undo history
+	maxAction = currentAction;
+}
+
+int UndoHistory::TentativeSteps() {
+	// Drop any trailing startAction
+	if (actions[currentAction].at == startAction && currentAction > 0)
+		currentAction--;
+	if (tentativePoint >= 0)
+		return currentAction - tentativePoint;
+	else
+		return -1;
+}
+
 bool UndoHistory::CanUndo() const {
 	return (currentAction > 0) && (maxAction > 0);
 }
@@ -505,6 +527,22 @@ bool CellBuffer::IsSavePoint() const {
 	return uh.IsSavePoint();
 }
 
+void CellBuffer::TentativeStart() {
+	uh.TentativeStart();
+}
+
+void CellBuffer::TentativeCommit() {
+	uh.TentativeCommit();
+}
+
+int CellBuffer::TentativeSteps() {
+	return uh.TentativeSteps();
+}
+
+bool CellBuffer::TentativeActive() const {
+	return uh.TentativeActive();
+}
+
 // Without undo
 
 void CellBuffer::InsertLine(int line, int position, bool lineStart) {


Modified: scintilla/src/CellBuffer.h
12 lines changed, 12 insertions(+), 0 deletions(-)
===================================================================
@@ -95,6 +95,7 @@ class UndoHistory {
 	int currentAction;
 	int undoSequenceDepth;
 	int savePoint;
+	int tentativePoint;
 
 	void EnsureUndoRoom();
 
@@ -117,6 +118,12 @@ class UndoHistory {
 	void SetSavePoint();
 	bool IsSavePoint() const;
 
+	// Tentative actions are used for input composition so that it can be undone cleanly
+	void TentativeStart();
+	void TentativeCommit();
+	bool TentativeActive() const { return tentativePoint >= 0; }
+	int TentativeSteps();
+
 	/// To perform an undo, StartUndo is called to retrieve the number of steps, then UndoStep is
 	/// called that many times. Similarly for redo.
 	bool CanUndo() const;
@@ -193,6 +200,11 @@ class CellBuffer {
 	void SetSavePoint();
 	bool IsSavePoint() const;
 
+	void TentativeStart();
+	void TentativeCommit();
+	bool TentativeActive() const;
+	int TentativeSteps();
+
 	bool SetUndoCollection(bool collectUndo);
 	bool IsCollectingUndo() const;
 	void BeginUndoAction();


Modified: scintilla/src/ContractionState.cxx
18 lines changed, 9 insertions(+), 9 deletions(-)
===================================================================
@@ -150,8 +150,8 @@ bool ContractionState::GetVisible(int lineDoc) const {
 	}
 }
 
-bool ContractionState::SetVisible(int lineDocStart, int lineDocEnd, bool visible_) {
-	if (OneToOne() && visible_) {
+bool ContractionState::SetVisible(int lineDocStart, int lineDocEnd, bool isVisible) {
+	if (OneToOne() && isVisible) {
 		return false;
 	} else {
 		EnsureData();
@@ -159,9 +159,9 @@ bool ContractionState::SetVisible(int lineDocStart, int lineDocEnd, bool visible
 		Check();
 		if ((lineDocStart <= lineDocEnd) && (lineDocStart >= 0) && (lineDocEnd < LinesInDoc())) {
 			for (int line = lineDocStart; line <= lineDocEnd; line++) {
-				if (GetVisible(line) != visible_) {
-					int difference = visible_ ? heights->ValueAt(line) : -heights->ValueAt(line);
-					visible->SetValueAt(line, visible_ ? 1 : 0);
+				if (GetVisible(line) != isVisible) {
+					int difference = isVisible ? heights->ValueAt(line) : -heights->ValueAt(line);
+					visible->SetValueAt(line, isVisible ? 1 : 0);
 					displayLines->InsertText(line, difference);
 					delta += difference;
 				}
@@ -191,13 +191,13 @@ bool ContractionState::GetExpanded(int lineDoc) const {
 	}
 }
 
-bool ContractionState::SetExpanded(int lineDoc, bool expanded_) {
-	if (OneToOne() && expanded_) {
+bool ContractionState::SetExpanded(int lineDoc, bool isExpanded) {
+	if (OneToOne() && isExpanded) {
 		return false;
 	} else {
 		EnsureData();
-		if (expanded_ != (expanded->ValueAt(lineDoc) == 1)) {
-			expanded->SetValueAt(lineDoc, expanded_ ? 1 : 0);
+		if (isExpanded != (expanded->ValueAt(lineDoc) == 1)) {
+			expanded->SetValueAt(lineDoc, isExpanded ? 1 : 0);
 			Check();
 			return true;
 		} else {


Modified: scintilla/src/ContractionState.h
4 lines changed, 2 insertions(+), 2 deletions(-)
===================================================================
@@ -48,11 +48,11 @@ class ContractionState {
 	void DeleteLines(int lineDoc, int lineCount);
 
 	bool GetVisible(int lineDoc) const;
-	bool SetVisible(int lineDocStart, int lineDocEnd, bool visible);
+	bool SetVisible(int lineDocStart, int lineDocEnd, bool isVisible);
 	bool HiddenLines() const;
 
 	bool GetExpanded(int lineDoc) const;
-	bool SetExpanded(int lineDoc, bool expanded);
+	bool SetExpanded(int lineDoc, bool isExpanded);
 	int ContractedNext(int lineDocStart) const;
 
 	int GetHeight(int lineDoc) const;


Modified: scintilla/src/Document.cxx
59 lines changed, 59 insertions(+), 0 deletions(-)
===================================================================
@@ -209,6 +209,65 @@ void Document::SetSavePoint() {
 	NotifySavePoint(true);
 }
 
+void Document::TentativeUndo() {
+	CheckReadOnly();
+	if (enteredModification == 0) {
+		enteredModification++;
+		if (!cb.IsReadOnly()) {
+			bool startSavePoint = cb.IsSavePoint();
+			bool multiLine = false;
+			int steps = cb.TentativeSteps();
+			//Platform::DebugPrintf("Steps=%d\n", steps);
+			for (int step = 0; step < steps; step++) {
+				const int prevLinesTotal = LinesTotal();
+				const Action &action = cb.GetUndoStep();
+				if (action.at == removeAction) {
+					NotifyModified(DocModification(
+									SC_MOD_BEFOREINSERT | SC_PERFORMED_UNDO, action));
+				} else if (action.at == containerAction) {
+					DocModification dm(SC_MOD_CONTAINER | SC_PERFORMED_UNDO);
+					dm.token = action.position;
+					NotifyModified(dm);
+				} else {
+					NotifyModified(DocModification(
+									SC_MOD_BEFOREDELETE | SC_PERFORMED_UNDO, action));
+				}
+				cb.PerformUndoStep();
+				if (action.at != containerAction) {
+					ModifiedAt(action.position);
+				}
+
+				int modFlags = SC_PERFORMED_UNDO;
+				// With undo, an insertion action becomes a deletion notification
+				if (action.at == removeAction) {
+					modFlags |= SC_MOD_INSERTTEXT;
+				} else if (action.at == insertAction) {
+					modFlags |= SC_MOD_DELETETEXT;
+				}
+				if (steps > 1)
+					modFlags |= SC_MULTISTEPUNDOREDO;
+				const int linesAdded = LinesTotal() - prevLinesTotal;
+				if (linesAdded != 0)
+					multiLine = true;
+				if (step == steps - 1) {
+					modFlags |= SC_LASTSTEPINUNDOREDO;
+					if (multiLine)
+						modFlags |= SC_MULTILINEUNDOREDO;
+				}
+				NotifyModified(DocModification(modFlags, action.position, action.lenData,
+											   linesAdded, action.data));
+			}
+
+			bool endSavePoint = cb.IsSavePoint();
+			if (startSavePoint != endSavePoint)
+				NotifySavePoint(endSavePoint);
+				
+			cb.TentativeCommit();
+		}
+		enteredModification--;
+	}
+}
+
 int Document::GetMark(int line) {
 	return static_cast<LineMarkers *>(perLineData[ldMarkers])->MarkValue(line);
 }


Modified: scintilla/src/Document.h
8 lines changed, 7 insertions(+), 1 deletions(-)
===================================================================
@@ -303,6 +303,12 @@ class Document : PerLine, public IDocumentWithLineEnd, public ILoader {
 	void AddUndoAction(int token, bool mayCoalesce) { cb.AddUndoAction(token, mayCoalesce); }
 	void SetSavePoint();
 	bool IsSavePoint() const { return cb.IsSavePoint(); }
+
+	void TentativeStart() { cb.TentativeStart(); }
+	void TentativeCommit() { cb.TentativeCommit(); }
+	void TentativeUndo();
+	bool TentativeActive() const { return cb.TentativeActive(); }
+
 	const char * SCI_METHOD BufferPointer() { return cb.BufferPointer(); }
 	const char *RangePointer(int position, int rangeLength) { return cb.RangePointer(position, rangeLength); }
 	int GapPosition() const { return cb.GapPosition(); }
@@ -368,7 +374,7 @@ class Document : PerLine, public IDocumentWithLineEnd, public ILoader {
 
 	void SetDefaultCharClasses(bool includeWordClass);
 	void SetCharClasses(const unsigned char *chars, CharClassify::cc newCharClass);
-	int GetCharsOfClass(CharClassify::cc charClass, unsigned char *buffer);
+	int GetCharsOfClass(CharClassify::cc characterClass, unsigned char *buffer);
 	void SCI_METHOD StartStyling(int position, char mask);
 	bool SCI_METHOD SetStyleFor(int length, char style);
 	bool SCI_METHOD SetStyles(int length, const char *styles);


Modified: scintilla/src/EditModel.cxx
74 lines changed, 74 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,74 @@
+// Scintilla source code edit control
+/** @file EditModel.cxx
+ ** Defines the editor state that must be visible to EditorView.
+ **/
+// Copyright 1998-2014 by Neil Hodgson <neilh at scintilla.org>
+// The License.txt file describes the conditions under which this software may be distributed.
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <assert.h>
+#include <ctype.h>
+
+#include <string>
+#include <vector>
+#include <map>
+#include <algorithm>
+#include <memory>
+
+#include "Platform.h"
+
+#include "ILexer.h"
+#include "Scintilla.h"
+
+#include "StringCopy.h"
+#include "SplitVector.h"
+#include "Partitioning.h"
+#include "RunStyles.h"
+#include "ContractionState.h"
+#include "CellBuffer.h"
+#include "KeyMap.h"
+#include "Indicator.h"
+#include "XPM.h"
+#include "LineMarker.h"
+#include "Style.h"
+#include "ViewStyle.h"
+#include "CharClassify.h"
+#include "Decoration.h"
+#include "CaseFolder.h"
+#include "Document.h"
+#include "UniConversion.h"
+#include "Selection.h"
+#include "PositionCache.h"
+#include "EditModel.h"
+
+#ifdef SCI_NAMESPACE
+using namespace Scintilla;
+#endif
+
+Caret::Caret() :
+	active(false), on(false), period(500) {}
+
+EditModel::EditModel() {
+	inOverstrike = false;
+	xOffset = 0;
+	trackLineWidth = false;
+	posDrag = SelectionPosition(invalidPosition);
+	braces[0] = invalidPosition;
+	braces[1] = invalidPosition;
+	bracesMatchStyle = STYLE_BRACEBAD;
+	highlightGuideColumn = 0;
+	primarySelection = true;
+	foldFlags = 0;
+	hotspot = Range(invalidPosition);
+	wrapWidth = LineLayout::wrapWidthInfinite;
+	pdoc = new Document();
+	pdoc->AddRef();
+}
+
+EditModel::~EditModel() {
+	pdoc->Release();
+	pdoc = 0;
+}


Modified: scintilla/src/EditModel.h
67 lines changed, 67 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,67 @@
+// Scintilla source code edit control
+/** @file EditModel.h
+ ** Defines the editor state that must be visible to EditorView.
+ **/
+// Copyright 1998-2014 by Neil Hodgson <neilh at scintilla.org>
+// The License.txt file describes the conditions under which this software may be distributed.
+
+#ifndef EDITMODEL_H
+#define EDITMODEL_H
+
+#ifdef SCI_NAMESPACE
+namespace Scintilla {
+#endif
+
+/**
+*/
+class Caret {
+public:
+	bool active;
+	bool on;
+	int period;
+
+	Caret();
+};
+
+class EditModel {
+	// Private so EditModel objects can not be copied
+	EditModel(const EditModel &);
+	EditModel &operator=(const EditModel &);
+
+public:
+	bool inOverstrike;
+	int xOffset;		///< Horizontal scrolled amount in pixels
+	bool trackLineWidth;
+
+	SpecialRepresentations reprs;
+	Caret caret;
+	SelectionPosition posDrag;
+	Position braces[2];
+	int bracesMatchStyle;
+	int highlightGuideColumn;
+	Selection sel;
+	bool primarySelection;
+
+	int foldFlags;
+	ContractionState cs;
+	// Hotspot support
+	Range hotspot;
+
+	// Wrapping support
+	int wrapWidth;
+
+	Document *pdoc;
+
+	EditModel();
+	virtual ~EditModel();
+	virtual int TopLineOfMain() const = 0;
+	virtual Point GetVisibleOriginInMain() const = 0;
+	virtual int LinesOnScreen() const = 0;
+	virtual Range GetHotSpotRange() const = 0;
+};
+
+#ifdef SCI_NAMESPACE
+}
+#endif
+
+#endif


Modified: scintilla/src/EditView.cxx
2072 lines changed, 2072 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,2072 @@
+// Scintilla source code edit control
+/** @file Editor.cxx
+ ** Defines the appearance of the main text area of the editor window.
+ **/
+// Copyright 1998-2014 by Neil Hodgson <neilh at scintilla.org>
+// The License.txt file describes the conditions under which this software may be distributed.
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <assert.h>
+#include <ctype.h>
+
+#include <string>
+#include <vector>
+#include <map>
+#include <algorithm>
+#include <memory>
+
+#include "Platform.h"
+
+#include "ILexer.h"
+#include "Scintilla.h"
+
+#include "StringCopy.h"
+#include "SplitVector.h"
+#include "Partitioning.h"
+#include "RunStyles.h"
+#include "ContractionState.h"
+#include "CellBuffer.h"
+#include "PerLine.h"
+#include "KeyMap.h"
+#include "Indicator.h"
+#include "XPM.h"
+#include "LineMarker.h"
+#include "Style.h"
+#include "ViewStyle.h"
+#include "CharClassify.h"
+#include "Decoration.h"
+#include "CaseFolder.h"
+#include "Document.h"
+#include "UniConversion.h"
+#include "Selection.h"
+#include "PositionCache.h"
+#include "EditModel.h"
+#include "MarginView.h"
+#include "EditView.h"
+
+#ifdef SCI_NAMESPACE
+using namespace Scintilla;
+#endif
+
+static inline bool IsControlCharacter(int ch) {
+	// iscntrl returns true for lots of chars > 127 which are displayable
+	return ch >= 0 && ch < ' ';
+}
+
+PrintParameters::PrintParameters() {
+	magnification = 0;
+	colourMode = SC_PRINT_NORMAL;
+	wrapState = eWrapWord;
+}
+
+#ifdef SCI_NAMESPACE
+namespace Scintilla {
+#endif
+
+bool ValidStyledText(const ViewStyle &vs, size_t styleOffset, const StyledText &st) {
+	if (st.multipleStyles) {
+		for (size_t iStyle = 0; iStyle<st.length; iStyle++) {
+			if (!vs.ValidStyle(styleOffset + st.styles[iStyle]))
+				return false;
+		}
+	} else {
+		if (!vs.ValidStyle(styleOffset + st.style))
+			return false;
+	}
+	return true;
+}
+
+static int WidthStyledText(Surface *surface, const ViewStyle &vs, int styleOffset,
+	const char *text, const unsigned char *styles, size_t len) {
+	int width = 0;
+	size_t start = 0;
+	while (start < len) {
+		size_t style = styles[start];
+		size_t endSegment = start;
+		while ((endSegment + 1 < len) && (static_cast<size_t>(styles[endSegment + 1]) == style))
+			endSegment++;
+		FontAlias fontText = vs.styles[style + styleOffset].font;
+		width += static_cast<int>(surface->WidthText(fontText, text + start,
+			static_cast<int>(endSegment - start + 1)));
+		start = endSegment + 1;
+	}
+	return width;
+}
+
+int WidestLineWidth(Surface *surface, const ViewStyle &vs, int styleOffset, const StyledText &st) {
+	int widthMax = 0;
+	size_t start = 0;
+	while (start < st.length) {
+		size_t lenLine = st.LineLength(start);
+		int widthSubLine;
+		if (st.multipleStyles) {
+			widthSubLine = WidthStyledText(surface, vs, styleOffset, st.text + start, st.styles + start, lenLine);
+		} else {
+			FontAlias fontText = vs.styles[styleOffset + st.style].font;
+			widthSubLine = static_cast<int>(surface->WidthText(fontText,
+				st.text + start, static_cast<int>(lenLine)));
+		}
+		if (widthSubLine > widthMax)
+			widthMax = widthSubLine;
+		start += lenLine + 1;
+	}
+	return widthMax;
+}
+
+void DrawTextNoClipPhase(Surface *surface, PRectangle rc, const Style &style, XYPOSITION ybase,
+	const char *s, int len, DrawPhase phase) {
+	FontAlias fontText = style.font;
+	if (phase & drawBack) {
+		if (phase & drawText) {
+			// Drawing both
+			surface->DrawTextNoClip(rc, fontText, ybase, s, len,
+				style.fore, style.back);
+		} else {
+			surface->FillRectangle(rc, style.back);
+		}
+	} else if (phase & drawText) {
+		surface->DrawTextTransparent(rc, fontText, ybase, s, len, style.fore);
+	}
+}
+
+void DrawStyledText(Surface *surface, const ViewStyle &vs, int styleOffset, PRectangle rcText,
+	const StyledText &st, size_t start, size_t length, DrawPhase phase) {
+
+	if (st.multipleStyles) {
+		int x = static_cast<int>(rcText.left);
+		size_t i = 0;
+		while (i < length) {
+			size_t end = i;
+			size_t style = st.styles[i + start];
+			while (end < length - 1 && st.styles[start + end + 1] == style)
+				end++;
+			style += styleOffset;
+			FontAlias fontText = vs.styles[style].font;
+			const int width = static_cast<int>(surface->WidthText(fontText,
+				st.text + start + i, static_cast<int>(end - i + 1)));
+			PRectangle rcSegment = rcText;
+			rcSegment.left = static_cast<XYPOSITION>(x);
+			rcSegment.right = static_cast<XYPOSITION>(x + width + 1);
+			DrawTextNoClipPhase(surface, rcSegment, vs.styles[style],
+				rcText.top + vs.maxAscent, st.text + start + i,
+				static_cast<int>(end - i + 1), phase);
+			x += width;
+			i = end + 1;
+		}
+	} else {
+		const size_t style = st.style + styleOffset;
+		DrawTextNoClipPhase(surface, rcText, vs.styles[style],
+			rcText.top + vs.maxAscent, st.text + start,
+			static_cast<int>(length), phase);
+	}
+}
+
+#ifdef SCI_NAMESPACE
+}
+#endif
+
+const XYPOSITION epsilon = 0.0001f;	// A small nudge to avoid floating point precision issues
+
+EditView::EditView() {
+	ldTabstops = NULL;
+	hideSelection = false;
+	drawOverstrikeCaret = true;
+	bufferedDraw = true;
+	phasesDraw = phasesTwo;
+	lineWidthMaxSeen = 0;
+	additionalCaretsBlink = true;
+	additionalCaretsVisible = true;
+	imeCaretBlockOverride = false;
+	pixmapLine = 0;
+	pixmapIndentGuide = 0;
+	pixmapIndentGuideHighlight = 0;
+	llc.SetLevel(LineLayoutCache::llcCaret);
+	posCache.SetSize(0x400);
+}
+
+EditView::~EditView() {
+	delete ldTabstops;
+	ldTabstops = NULL;
+}
+
+bool EditView::SetTwoPhaseDraw(bool twoPhaseDraw) {
+	const PhasesDraw phasesDrawNew = twoPhaseDraw ? phasesTwo : phasesOne;
+	const bool redraw = phasesDraw != phasesDrawNew;
+	phasesDraw = phasesDrawNew;
+	return redraw;
+}
+
+bool EditView::SetPhasesDraw(int phases) {
+	const PhasesDraw phasesDrawNew = static_cast<PhasesDraw>(phases);
+	const bool redraw = phasesDraw != phasesDrawNew;
+	phasesDraw = phasesDrawNew;
+	return redraw;
+}
+
+bool EditView::LinesOverlap() const {
+	return phasesDraw == phasesMultiple;
+}
+
+void EditView::ClearAllTabstops() {
+	delete ldTabstops;
+	ldTabstops = 0;
+}
+
+int EditView::NextTabstopPos(int line, int x, int tabWidth) const {
+	int next = GetNextTabstop(line, x);
+	if (next > 0)
+		return next;
+	return ((((x + 2) / tabWidth) + 1) * tabWidth);
+}
+
+bool EditView::ClearTabstops(int line) {
+	LineTabstops *lt = static_cast<LineTabstops *>(ldTabstops);
+	return lt && lt->ClearTabstops(line);
+}
+
+bool EditView::AddTabstop(int line, int x) {
+	if (!ldTabstops) {
+		ldTabstops = new LineTabstops();
+	}
+	LineTabstops *lt = static_cast<LineTabstops *>(ldTabstops);
+	return lt && lt->AddTabstop(line, x);
+}
+
+int EditView::GetNextTabstop(int line, int x) const {
+	LineTabstops *lt = static_cast<LineTabstops *>(ldTabstops);
+	if (lt) {
+		return lt->GetNextTabstop(line, x);
+	} else {
+		return 0;
+	}
+}
+
+void EditView::LinesAddedOrRemoved(int lineOfPos, int linesAdded) {
+	if (ldTabstops) {
+		if (linesAdded > 0) {
+			for (int line = lineOfPos; line < lineOfPos + linesAdded; line++) {
+				ldTabstops->InsertLine(line);
+			}
+		} else {
+			for (int line = (lineOfPos + -linesAdded) - 1; line >= lineOfPos; line--) {
+				ldTabstops->RemoveLine(line);
+			}
+		}
+	}
+}
+
+void EditView::DropGraphics(bool freeObjects) {
+	if (freeObjects) {
+		delete pixmapLine;
+		pixmapLine = 0;
+		delete pixmapIndentGuide;
+		pixmapIndentGuide = 0;
+		delete pixmapIndentGuideHighlight;
+		pixmapIndentGuideHighlight = 0;
+	} else {
+		if (pixmapLine)
+			pixmapLine->Release();
+		if (pixmapIndentGuide)
+			pixmapIndentGuide->Release();
+		if (pixmapIndentGuideHighlight)
+			pixmapIndentGuideHighlight->Release();
+	}
+}
+
+void EditView::AllocateGraphics(const ViewStyle &vsDraw) {
+	if (!pixmapLine)
+		pixmapLine = Surface::Allocate(vsDraw.technology);
+	if (!pixmapIndentGuide)
+		pixmapIndentGuide = Surface::Allocate(vsDraw.technology);
+	if (!pixmapIndentGuideHighlight)
+		pixmapIndentGuideHighlight = Surface::Allocate(vsDraw.technology);
+}
+
+const char *ControlCharacterString(unsigned char ch) {
+	const char *reps[] = {
+		"NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
+		"BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
+		"DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
+		"CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
+	};
+	if (ch < ELEMENTS(reps)) {
+		return reps[ch];
+	} else {
+		return "BAD";
+	}
+}
+
+void DrawTabArrow(Surface *surface, PRectangle rcTab, int ymid) {
+	int ydiff = static_cast<int>(rcTab.bottom - rcTab.top) / 2;
+	int xhead = static_cast<int>(rcTab.right) - 1 - ydiff;
+	if (xhead <= rcTab.left) {
+		ydiff -= static_cast<int>(rcTab.left) - xhead - 1;
+		xhead = static_cast<int>(rcTab.left) - 1;
+	}
+	if ((rcTab.left + 2) < (rcTab.right - 1))
+		surface->MoveTo(static_cast<int>(rcTab.left) + 2, ymid);
+	else
+		surface->MoveTo(static_cast<int>(rcTab.right) - 1, ymid);
+	surface->LineTo(static_cast<int>(rcTab.right) - 1, ymid);
+	surface->LineTo(xhead, ymid - ydiff);
+	surface->MoveTo(static_cast<int>(rcTab.right) - 1, ymid);
+	surface->LineTo(xhead, ymid + ydiff);
+}
+
+void EditView::RefreshPixMaps(Surface *surfaceWindow, WindowID wid, const ViewStyle &vsDraw) {
+	if (!pixmapIndentGuide->Initialised()) {
+		// 1 extra pixel in height so can handle odd/even positions and so produce a continuous line
+		pixmapIndentGuide->InitPixMap(1, vsDraw.lineHeight + 1, surfaceWindow, wid);
+		pixmapIndentGuideHighlight->InitPixMap(1, vsDraw.lineHeight + 1, surfaceWindow, wid);
+		PRectangle rcIG = PRectangle::FromInts(0, 0, 1, vsDraw.lineHeight);
+		pixmapIndentGuide->FillRectangle(rcIG, vsDraw.styles[STYLE_INDENTGUIDE].back);
+		pixmapIndentGuide->PenColour(vsDraw.styles[STYLE_INDENTGUIDE].fore);
+		pixmapIndentGuideHighlight->FillRectangle(rcIG, vsDraw.styles[STYLE_BRACELIGHT].back);
+		pixmapIndentGuideHighlight->PenColour(vsDraw.styles[STYLE_BRACELIGHT].fore);
+		for (int stripe = 1; stripe < vsDraw.lineHeight + 1; stripe += 2) {
+			PRectangle rcPixel = PRectangle::FromInts(0, stripe, 1, stripe + 1);
+			pixmapIndentGuide->FillRectangle(rcPixel, vsDraw.styles[STYLE_INDENTGUIDE].fore);
+			pixmapIndentGuideHighlight->FillRectangle(rcPixel, vsDraw.styles[STYLE_BRACELIGHT].fore);
+		}
+	}
+}
+
+LineLayout *EditView::RetrieveLineLayout(int lineNumber, const EditModel &model) {
+	int posLineStart = model.pdoc->LineStart(lineNumber);
+	int posLineEnd = model.pdoc->LineStart(lineNumber + 1);
+	PLATFORM_ASSERT(posLineEnd >= posLineStart);
+	int lineCaret = model.pdoc->LineFromPosition(model.sel.MainCaret());
+	return llc.Retrieve(lineNumber, lineCaret,
+		posLineEnd - posLineStart, model.pdoc->GetStyleClock(),
+		model.LinesOnScreen() + 1, model.pdoc->LinesTotal());
+}
+
+/**
+* Fill in the LineLayout data for the given line.
+* Copy the given @a line and its styles from the document into local arrays.
+* Also determine the x position at which each character starts.
+*/
+void EditView::LayoutLine(const EditModel &model, int line, Surface *surface, const ViewStyle &vstyle, LineLayout *ll, int width) {
+	if (!ll)
+		return;
+
+	PLATFORM_ASSERT(line < model.pdoc->LinesTotal());
+	PLATFORM_ASSERT(ll->chars != NULL);
+	int posLineStart = model.pdoc->LineStart(line);
+	int posLineEnd = model.pdoc->LineStart(line + 1);
+	// If the line is very long, limit the treatment to a length that should fit in the viewport
+	if (posLineEnd >(posLineStart + ll->maxLineLength)) {
+		posLineEnd = posLineStart + ll->maxLineLength;
+	}
+	if (ll->validity == LineLayout::llCheckTextAndStyle) {
+		int lineLength = posLineEnd - posLineStart;
+		if (!vstyle.viewEOL) {
+			lineLength = model.pdoc->LineEnd(line) - posLineStart;
+		}
+		if (lineLength == ll->numCharsInLine) {
+			// See if chars, styles, indicators, are all the same
+			bool allSame = true;
+			// Check base line layout
+			char styleByte = 0;
+			int numCharsInLine = 0;
+			while (numCharsInLine < lineLength) {
+				int charInDoc = numCharsInLine + posLineStart;
+				char chDoc = model.pdoc->CharAt(charInDoc);
+				styleByte = model.pdoc->StyleAt(charInDoc);
+				allSame = allSame &&
+					(ll->styles[numCharsInLine] == static_cast<unsigned char>(styleByte));
+				if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseMixed)
+					allSame = allSame &&
+					(ll->chars[numCharsInLine] == chDoc);
+				else if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseLower)
+					allSame = allSame &&
+					(ll->chars[numCharsInLine] == static_cast<char>(tolower(chDoc)));
+				else	// Style::caseUpper
+					allSame = allSame &&
+					(ll->chars[numCharsInLine] == static_cast<char>(toupper(chDoc)));
+				numCharsInLine++;
+			}
+			allSame = allSame && (ll->styles[numCharsInLine] == styleByte);	// For eolFilled
+			if (allSame) {
+				ll->validity = LineLayout::llPositions;
+			} else {
+				ll->validity = LineLayout::llInvalid;
+			}
+		} else {
+			ll->validity = LineLayout::llInvalid;
+		}
+	}
+	if (ll->validity == LineLayout::llInvalid) {
+		ll->widthLine = LineLayout::wrapWidthInfinite;
+		ll->lines = 1;
+		if (vstyle.edgeState == EDGE_BACKGROUND) {
+			ll->edgeColumn = model.pdoc->FindColumn(line, vstyle.theEdge);
+			if (ll->edgeColumn >= posLineStart) {
+				ll->edgeColumn -= posLineStart;
+			}
+		} else {
+			ll->edgeColumn = -1;
+		}
+
+		// Fill base line layout
+		const int lineLength = posLineEnd - posLineStart;
+		model.pdoc->GetCharRange(ll->chars, posLineStart, lineLength);
+		model.pdoc->GetStyleRange(ll->styles, posLineStart, lineLength);
+		int numCharsBeforeEOL = model.pdoc->LineEnd(line) - posLineStart;
+		const int numCharsInLine = (vstyle.viewEOL) ? lineLength : numCharsBeforeEOL;
+		for (int styleInLine = 0; styleInLine < numCharsInLine; styleInLine++) {
+			const unsigned char styleByte = ll->styles[styleInLine];
+			ll->styles[styleInLine] = styleByte;
+		}
+		const unsigned char styleByteLast = (lineLength > 0) ? ll->styles[lineLength - 1] : 0;
+		if (vstyle.someStylesForceCase) {
+			for (int charInLine = 0; charInLine<lineLength; charInLine++) {
+				char chDoc = ll->chars[charInLine];
+				if (vstyle.styles[ll->styles[charInLine]].caseForce == Style::caseUpper)
+					ll->chars[charInLine] = static_cast<char>(toupper(chDoc));
+				else if (vstyle.styles[ll->styles[charInLine]].caseForce == Style::caseLower)
+					ll->chars[charInLine] = static_cast<char>(tolower(chDoc));
+			}
+		}
+		ll->xHighlightGuide = 0;
+		// Extra element at the end of the line to hold end x position and act as
+		ll->chars[numCharsInLine] = 0;   // Also triggers processing in the loops as this is a control character
+		ll->styles[numCharsInLine] = styleByteLast;	// For eolFilled
+
+		// Layout the line, determining the position of each character,
+		// with an extra element at the end for the end of the line.
+		ll->positions[0] = 0;
+		bool lastSegItalics = false;
+
+		BreakFinder bfLayout(ll, NULL, Range(0, numCharsInLine), posLineStart, 0, false, model.pdoc, &model.reprs);
+		while (bfLayout.More()) {
+
+			const TextSegment ts = bfLayout.Next();
+
+			std::fill(&ll->positions[ts.start + 1], &ll->positions[ts.end() + 1], 0.0f);
+			if (vstyle.styles[ll->styles[ts.start]].visible) {
+				if (ts.representation) {
+					XYPOSITION representationWidth = vstyle.controlCharWidth;
+					if (ll->chars[ts.start] == '\t') {
+						// Tab is a special case of representation, taking a variable amount of space
+						const int x = static_cast<int>(ll->positions[ts.start]);
+						const int tabWidth = static_cast<int>(vstyle.tabWidth);
+						representationWidth = static_cast<XYPOSITION>(NextTabstopPos(line, x, tabWidth) - ll->positions[ts.start]);
+					} else {
+						if (representationWidth <= 0.0) {
+							XYPOSITION positionsRepr[256];	// Should expand when needed
+							posCache.MeasureWidths(surface, vstyle, STYLE_CONTROLCHAR, ts.representation->stringRep.c_str(),
+								static_cast<unsigned int>(ts.representation->stringRep.length()), positionsRepr, model.pdoc);
+							representationWidth = positionsRepr[ts.representation->stringRep.length() - 1] + vstyle.ctrlCharPadding;
+						}
+					}
+					for (int ii = 0; ii < ts.length; ii++)
+						ll->positions[ts.start + 1 + ii] = representationWidth;
+				} else {
+					if ((ts.length == 1) && (' ' == ll->chars[ts.start])) {
+						// Over half the segments are single characters and of these about half are space characters.
+						ll->positions[ts.start + 1] = vstyle.styles[ll->styles[ts.start]].spaceWidth;
+					} else {
+						posCache.MeasureWidths(surface, vstyle, ll->styles[ts.start], ll->chars + ts.start,
+							ts.length, ll->positions + ts.start + 1, model.pdoc);
+					}
+				}
+				lastSegItalics = (!ts.representation) && ((ll->chars[ts.end() - 1] != ' ') && vstyle.styles[ll->styles[ts.start]].italic);
+			}
+
+			for (int posToIncrease = ts.start + 1; posToIncrease <= ts.end(); posToIncrease++) {
+				ll->positions[posToIncrease] += ll->positions[ts.start];
+			}
+		}
+
+		// Small hack to make lines that end with italics not cut off the edge of the last character
+		if (lastSegItalics) {
+			ll->positions[numCharsInLine] += vstyle.lastSegItalicsOffset;
+		}
+		ll->numCharsInLine = numCharsInLine;
+		ll->numCharsBeforeEOL = numCharsBeforeEOL;
+		ll->validity = LineLayout::llPositions;
+	}
+	// Hard to cope when too narrow, so just assume there is space
+	if (width < 20) {
+		width = 20;
+	}
+	if ((ll->validity == LineLayout::llPositions) || (ll->widthLine != width)) {
+		ll->widthLine = width;
+		if (width == LineLayout::wrapWidthInfinite) {
+			ll->lines = 1;
+		} else if (width > ll->positions[ll->numCharsInLine]) {
+			// Simple common case where line does not need wrapping.
+			ll->lines = 1;
+		} else {
+			if (vstyle.wrapVisualFlags & SC_WRAPVISUALFLAG_END) {
+				width -= static_cast<int>(vstyle.aveCharWidth); // take into account the space for end wrap mark
+			}
+			XYPOSITION wrapAddIndent = 0; // This will be added to initial indent of line
+			if (vstyle.wrapIndentMode == SC_WRAPINDENT_INDENT) {
+				wrapAddIndent = model.pdoc->IndentSize() * vstyle.spaceWidth;
+			} else if (vstyle.wrapIndentMode == SC_WRAPINDENT_FIXED) {
+				wrapAddIndent = vstyle.wrapVisualStartIndent * vstyle.aveCharWidth;
+			}
+			ll->wrapIndent = wrapAddIndent;
+			if (vstyle.wrapIndentMode != SC_WRAPINDENT_FIXED)
+			for (int i = 0; i < ll->numCharsInLine; i++) {
+				if (!IsSpaceOrTab(ll->chars[i])) {
+					ll->wrapIndent += ll->positions[i]; // Add line indent
+					break;
+				}
+			}
+			// Check for text width minimum
+			if (ll->wrapIndent > width - static_cast<int>(vstyle.aveCharWidth) * 15)
+				ll->wrapIndent = wrapAddIndent;
+			// Check for wrapIndent minimum
+			if ((vstyle.wrapVisualFlags & SC_WRAPVISUALFLAG_START) && (ll->wrapIndent < vstyle.aveCharWidth))
+				ll->wrapIndent = vstyle.aveCharWidth; // Indent to show start visual
+			ll->lines = 0;
+			// Calculate line start positions based upon width.
+			int lastGoodBreak = 0;
+			int lastLineStart = 0;
+			XYACCUMULATOR startOffset = 0;
+			int p = 0;
+			while (p < ll->numCharsInLine) {
+				if ((ll->positions[p + 1] - startOffset) >= width) {
+					if (lastGoodBreak == lastLineStart) {
+						// Try moving to start of last character
+						if (p > 0) {
+							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;
+						}
+					}
+					lastLineStart = lastGoodBreak;
+					ll->lines++;
+					ll->SetLineStart(ll->lines, lastGoodBreak);
+					startOffset = ll->positions[lastGoodBreak];
+					// take into account the space for start wrap mark and indent
+					startOffset -= ll->wrapIndent;
+					p = lastGoodBreak + 1;
+					continue;
+				}
+				if (p > 0) {
+					if (vstyle.wrapState == eWrapChar) {
+						lastGoodBreak = model.pdoc->MovePositionOutsideChar(p + posLineStart, -1)
+							- posLineStart;
+						p = model.pdoc->MovePositionOutsideChar(p + 1 + posLineStart, 1) - posLineStart;
+						continue;
+					} else if ((vstyle.wrapState == eWrapWord) && (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++;
+		}
+		ll->validity = LineLayout::llLines;
+	}
+}
+
+Point EditView::LocationFromPosition(Surface *surface, const EditModel &model, SelectionPosition pos, int topLine, const ViewStyle &vs) {
+	Point pt;
+	if (pos.Position() == INVALID_POSITION)
+		return pt;
+	const int line = model.pdoc->LineFromPosition(pos.Position());
+	const int lineVisible = model.cs.DisplayFromDoc(line);
+	//Platform::DebugPrintf("line=%d\n", line);
+	AutoLineLayout ll(llc, RetrieveLineLayout(line, model));
+	if (surface && ll) {
+		const int posLineStart = model.pdoc->LineStart(line);
+		LayoutLine(model, line, surface, vs, ll, model.wrapWidth);
+		const int posInLine = pos.Position() - posLineStart;
+		pt = ll->PointFromPosition(posInLine, vs.lineHeight);
+		pt.y += (lineVisible - topLine) * vs.lineHeight;
+		pt.x += vs.textStart - model.xOffset;
+	}
+	pt.x += pos.VirtualSpace() * vs.styles[ll->EndLineStyle()].spaceWidth;
+	return pt;
+}
+
+SelectionPosition EditView::SPositionFromLocation(Surface *surface, const EditModel &model, Point pt, bool canReturnInvalid, bool charPosition, bool virtualSpace, const ViewStyle &vs) {
+	pt.x = pt.x - vs.textStart;
+	int visibleLine = static_cast<int>(floor(pt.y / vs.lineHeight));
+	if (!canReturnInvalid && (visibleLine < 0))
+		visibleLine = 0;
+	const int lineDoc = model.cs.DocFromDisplay(visibleLine);
+	if (canReturnInvalid && (lineDoc < 0))
+		return SelectionPosition(INVALID_POSITION);
+	if (lineDoc >= model.pdoc->LinesTotal())
+		return SelectionPosition(canReturnInvalid ? INVALID_POSITION : model.pdoc->Length());
+	const int posLineStart = model.pdoc->LineStart(lineDoc);
+	AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc, model));
+	if (surface && ll) {
+		LayoutLine(model, lineDoc, surface, vs, ll, model.wrapWidth);
+		const int lineStartSet = model.cs.DisplayFromDoc(lineDoc);
+		const int subLine = visibleLine - lineStartSet;
+		if (subLine < ll->lines) {
+			const Range rangeSubLine = ll->SubLineRange(subLine);
+			const XYPOSITION subLineStart = ll->positions[rangeSubLine.start];
+			if (subLine > 0)	// Wrapped
+				pt.x -= ll->wrapIndent;
+			const int positionInLine = ll->FindPositionFromX(pt.x + subLineStart, rangeSubLine, charPosition);
+			if (positionInLine < rangeSubLine.end) {
+				return SelectionPosition(model.pdoc->MovePositionOutsideChar(positionInLine + posLineStart, 1));
+			}
+			if (virtualSpace) {
+				const XYPOSITION spaceWidth = vs.styles[ll->EndLineStyle()].spaceWidth;
+				const int spaceOffset = static_cast<int>(
+					(pt.x + subLineStart - ll->positions[rangeSubLine.end] + spaceWidth / 2) / spaceWidth);
+				return SelectionPosition(rangeSubLine.end + posLineStart, spaceOffset);
+			} else if (canReturnInvalid) {
+				if (pt.x < (ll->positions[rangeSubLine.end] - subLineStart)) {
+					return SelectionPosition(model.pdoc->MovePositionOutsideChar(rangeSubLine.end + posLineStart, 1));
+				}
+			} else {
+				return SelectionPosition(rangeSubLine.end + posLineStart);
+			}
+		}
+		if (!canReturnInvalid)
+			return SelectionPosition(ll->numCharsInLine + posLineStart);
+	}
+	return SelectionPosition(canReturnInvalid ? INVALID_POSITION : posLineStart);
+}
+
+/**
+* Find the document position corresponding to an x coordinate on a particular document line.
+* Ensure is between whole characters when document is in multi-byte or UTF-8 mode.
+* This method is used for rectangular selections and does not work on wrapped lines.
+*/
+SelectionPosition EditView::SPositionFromLineX(Surface *surface, const EditModel &model, int lineDoc, int x, const ViewStyle &vs) {
+	AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc, model));
+	if (surface && ll) {
+		const int posLineStart = model.pdoc->LineStart(lineDoc);
+		LayoutLine(model, lineDoc, surface, vs, ll, model.wrapWidth);
+		const Range rangeSubLine = ll->SubLineRange(0);
+		const XYPOSITION subLineStart = ll->positions[rangeSubLine.start];
+		const int positionInLine = ll->FindPositionFromX(x + subLineStart, rangeSubLine, false);
+		if (positionInLine < rangeSubLine.end) {
+			return SelectionPosition(model.pdoc->MovePositionOutsideChar(positionInLine + posLineStart, 1));
+		}
+		const XYPOSITION spaceWidth = vs.styles[ll->EndLineStyle()].spaceWidth;
+		const int spaceOffset = static_cast<int>(
+			(x + subLineStart - ll->positions[rangeSubLine.end] + spaceWidth / 2) / spaceWidth);
+		return SelectionPosition(rangeSubLine.end + posLineStart, spaceOffset);
+	}
+	return SelectionPosition(0);
+}
+
+int EditView::DisplayFromPosition(Surface *surface, const EditModel &model, int pos, const ViewStyle &vs) {
+	int lineDoc = model.pdoc->LineFromPosition(pos);
+	int lineDisplay = model.cs.DisplayFromDoc(lineDoc);
+	AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc, model));
+	if (surface && ll) {
+		LayoutLine(model, lineDoc, surface, vs, ll, model.wrapWidth);
+		unsigned int posLineStart = model.pdoc->LineStart(lineDoc);
+		int posInLine = pos - posLineStart;
+		lineDisplay--; // To make up for first increment ahead.
+		for (int subLine = 0; subLine < ll->lines; subLine++) {
+			if (posInLine >= ll->LineStart(subLine)) {
+				lineDisplay++;
+			}
+		}
+	}
+	return lineDisplay;
+}
+
+int EditView::StartEndDisplayLine(Surface *surface, const EditModel &model, int pos, bool start, const ViewStyle &vs) {
+	int line = model.pdoc->LineFromPosition(pos);
+	AutoLineLayout ll(llc, RetrieveLineLayout(line, model));
+	int posRet = INVALID_POSITION;
+	if (surface && ll) {
+		unsigned int posLineStart = model.pdoc->LineStart(line);
+		LayoutLine(model, line, surface, vs, ll, model.wrapWidth);
+		int posInLine = pos - posLineStart;
+		if (posInLine <= ll->maxLineLength) {
+			for (int subLine = 0; subLine < ll->lines; subLine++) {
+				if ((posInLine >= ll->LineStart(subLine)) && (posInLine <= ll->LineStart(subLine + 1))) {
+					if (start) {
+						posRet = ll->LineStart(subLine) + posLineStart;
+					} else {
+						if (subLine == ll->lines - 1)
+							posRet = ll->LineStart(subLine + 1) + posLineStart;
+						else
+							posRet = ll->LineStart(subLine + 1) + posLineStart - 1;
+					}
+				}
+			}
+		}
+	}
+	return posRet;
+}
+
+static ColourDesired SelectionBackground(const ViewStyle &vsDraw, bool main, bool primarySelection) {
+	return main ?
+		(primarySelection ? vsDraw.selColours.back : vsDraw.selBackground2) :
+		vsDraw.selAdditionalBackground;
+}
+
+static ColourDesired TextBackground(const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll,
+	ColourOptional background, int inSelection, bool inHotspot, int styleMain, int i) {
+	if (inSelection == 1) {
+		if (vsDraw.selColours.back.isSet && (vsDraw.selAlpha == SC_ALPHA_NOALPHA)) {
+			return SelectionBackground(vsDraw, true, model.primarySelection);
+		}
+	} else if (inSelection == 2) {
+		if (vsDraw.selColours.back.isSet && (vsDraw.selAdditionalAlpha == SC_ALPHA_NOALPHA)) {
+			return SelectionBackground(vsDraw, false, model.primarySelection);
+		}
+	} else {
+		if ((vsDraw.edgeState == EDGE_BACKGROUND) &&
+			(i >= ll->edgeColumn) &&
+			(i < ll->numCharsBeforeEOL))
+			return vsDraw.edgecolour;
+		if (inHotspot && vsDraw.hotspotColours.back.isSet)
+			return vsDraw.hotspotColours.back;
+	}
+	if (background.isSet && (styleMain != STYLE_BRACELIGHT) && (styleMain != STYLE_BRACEBAD)) {
+		return background;
+	} else {
+		return vsDraw.styles[styleMain].back;
+	}
+}
+
+void EditView::DrawIndentGuide(Surface *surface, int lineVisible, int lineHeight, int start, PRectangle rcSegment, bool highlight) {
+	Point from = Point::FromInts(0, ((lineVisible & 1) && (lineHeight & 1)) ? 1 : 0);
+	PRectangle rcCopyArea = PRectangle::FromInts(start + 1, static_cast<int>(rcSegment.top), start + 2, static_cast<int>(rcSegment.bottom));
+	surface->Copy(rcCopyArea, from,
+		highlight ? *pixmapIndentGuideHighlight : *pixmapIndentGuide);
+}
+
+static void SimpleAlphaRectangle(Surface *surface, PRectangle rc, ColourDesired fill, int alpha) {
+	if (alpha != SC_ALPHA_NOALPHA) {
+		surface->AlphaRectangle(rc, 0, fill, alpha, fill, alpha, 0);
+	}
+}
+
+static void DrawTextBlob(Surface *surface, const ViewStyle &vsDraw, PRectangle rcSegment,
+	const char *s, ColourDesired textBack, ColourDesired textFore, bool fillBackground) {
+	if (fillBackground) {
+		surface->FillRectangle(rcSegment, textBack);
+	}
+	FontAlias ctrlCharsFont = vsDraw.styles[STYLE_CONTROLCHAR].font;
+	int normalCharHeight = static_cast<int>(surface->Ascent(ctrlCharsFont) -
+		surface->InternalLeading(ctrlCharsFont));
+	PRectangle rcCChar = rcSegment;
+	rcCChar.left = rcCChar.left + 1;
+	rcCChar.top = rcSegment.top + vsDraw.maxAscent - normalCharHeight;
+	rcCChar.bottom = rcSegment.top + vsDraw.maxAscent + 1;
+	PRectangle rcCentral = rcCChar;
+	rcCentral.top++;
+	rcCentral.bottom--;
+	surface->FillRectangle(rcCentral, textFore);
+	PRectangle rcChar = rcCChar;
+	rcChar.left++;
+	rcChar.right--;
+	surface->DrawTextClipped(rcChar, ctrlCharsFont,
+		rcSegment.top + vsDraw.maxAscent, s, static_cast<int>(s ? strlen(s) : 0),
+		textBack, textFore);
+}
+
+void EditView::DrawEOL(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll,
+	PRectangle rcLine, int line, int lineEnd, int xStart, int subLine, XYACCUMULATOR subLineStart,
+	ColourOptional background) {
+
+	const int posLineStart = model.pdoc->LineStart(line);
+	PRectangle rcSegment = rcLine;
+
+	const bool lastSubLine = subLine == (ll->lines - 1);
+	XYPOSITION virtualSpace = 0;
+	if (lastSubLine) {
+		const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth;
+		virtualSpace = model.sel.VirtualSpaceFor(model.pdoc->LineEnd(line)) * spaceWidth;
+	}
+	XYPOSITION xEol = static_cast<XYPOSITION>(ll->positions[lineEnd] - subLineStart);
+
+	// Fill the virtual space and show selections within it
+	if (virtualSpace) {
+		rcSegment.left = xEol + xStart;
+		rcSegment.right = xEol + xStart + virtualSpace;
+		surface->FillRectangle(rcSegment, background.isSet ? background : vsDraw.styles[ll->styles[ll->numCharsInLine]].back);
+		if (!hideSelection && ((vsDraw.selAlpha == SC_ALPHA_NOALPHA) || (vsDraw.selAdditionalAlpha == SC_ALPHA_NOALPHA))) {
+			SelectionSegment virtualSpaceRange(SelectionPosition(model.pdoc->LineEnd(line)), SelectionPosition(model.pdoc->LineEnd(line), model.sel.VirtualSpaceFor(model.pdoc->LineEnd(line))));
+			for (size_t r = 0; r<model.sel.Count(); r++) {
+				int alpha = (r == model.sel.Main()) ? vsDraw.selAlpha : vsDraw.selAdditionalAlpha;
+				if (alpha == SC_ALPHA_NOALPHA) {
+					SelectionSegment portion = model.sel.Range(r).Intersect(virtualSpaceRange);
+					if (!portion.Empty()) {
+						const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth;
+						rcSegment.left = xStart + ll->positions[portion.start.Position() - posLineStart] -
+							static_cast<XYPOSITION>(subLineStart)+portion.start.VirtualSpace() * spaceWidth;
+						rcSegment.right = xStart + ll->positions[portion.end.Position() - posLineStart] -
+							static_cast<XYPOSITION>(subLineStart)+portion.end.VirtualSpace() * spaceWidth;
+						rcSegment.left = (rcSegment.left > rcLine.left) ? rcSegment.left : rcLine.left;
+						rcSegment.right = (rcSegment.right < rcLine.right) ? rcSegment.right : rcLine.right;
+						surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, r == model.sel.Main(), model.primarySelection));
+					}
+				}
+			}
+		}
+	}
+
+	int eolInSelection = 0;
+	int alpha = SC_ALPHA_NOALPHA;
+	if (!hideSelection) {
+		int posAfterLineEnd = model.pdoc->LineStart(line + 1);
+		eolInSelection = (subLine == (ll->lines - 1)) ? model.sel.InSelectionForEOL(posAfterLineEnd) : 0;
+		alpha = (eolInSelection == 1) ? vsDraw.selAlpha : vsDraw.selAdditionalAlpha;
+	}
+
+	// Draw the [CR], [LF], or [CR][LF] blobs if visible line ends are on
+	XYPOSITION blobsWidth = 0;
+	if (lastSubLine) {
+		for (int eolPos = ll->numCharsBeforeEOL; eolPos<ll->numCharsInLine; eolPos++) {
+			rcSegment.left = xStart + ll->positions[eolPos] - static_cast<XYPOSITION>(subLineStart)+virtualSpace;
+			rcSegment.right = xStart + ll->positions[eolPos + 1] - static_cast<XYPOSITION>(subLineStart)+virtualSpace;
+			blobsWidth += rcSegment.Width();
+			char hexits[4];
+			const char *ctrlChar;
+			unsigned char chEOL = ll->chars[eolPos];
+			int styleMain = ll->styles[eolPos];
+			ColourDesired textBack = TextBackground(model, vsDraw, ll, background, eolInSelection, false, styleMain, eolPos);
+			if (UTF8IsAscii(chEOL)) {
+				ctrlChar = ControlCharacterString(chEOL);
+			} else {
+				const Representation *repr = model.reprs.RepresentationFromCharacter(ll->chars + eolPos, ll->numCharsInLine - eolPos);
+				if (repr) {
+					ctrlChar = repr->stringRep.c_str();
+					eolPos = ll->numCharsInLine;
+				} else {
+					sprintf(hexits, "x%2X", chEOL);
+					ctrlChar = hexits;
+				}
+			}
+			ColourDesired textFore = vsDraw.styles[styleMain].fore;
+			if (eolInSelection && vsDraw.selColours.fore.isSet) {
+				textFore = (eolInSelection == 1) ? vsDraw.selColours.fore : vsDraw.selAdditionalForeground;
+			}
+			if (eolInSelection && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1)) {
+				if (alpha == SC_ALPHA_NOALPHA) {
+					surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection));
+				} else {
+					surface->FillRectangle(rcSegment, textBack);
+				}
+			} else {
+				surface->FillRectangle(rcSegment, textBack);
+			}
+			DrawTextBlob(surface, vsDraw, rcSegment, ctrlChar, textBack, textFore, phasesDraw == phasesOne);
+			if (eolInSelection && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) {
+				SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection), alpha);
+			}
+		}
+	}
+
+	// Draw the eol-is-selected rectangle
+	rcSegment.left = xEol + xStart + virtualSpace + blobsWidth;
+	rcSegment.right = rcSegment.left + vsDraw.aveCharWidth;
+
+	if (eolInSelection && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1) && (alpha == SC_ALPHA_NOALPHA)) {
+		surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection));
+	} else {
+		if (background.isSet) {
+			surface->FillRectangle(rcSegment, background);
+		} else if (line < model.pdoc->LinesTotal() - 1) {
+			surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine]].back);
+		} else if (vsDraw.styles[ll->styles[ll->numCharsInLine]].eolFilled) {
+			surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine]].back);
+		} else {
+			surface->FillRectangle(rcSegment, vsDraw.styles[STYLE_DEFAULT].back);
+		}
+		if (eolInSelection && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) {
+			SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection), alpha);
+		}
+	}
+
+	// Fill the remainder of the line
+	rcSegment.left = rcSegment.right;
+	if (rcSegment.left < rcLine.left)
+		rcSegment.left = rcLine.left;
+	rcSegment.right = rcLine.right;
+
+	if (eolInSelection && vsDraw.selEOLFilled && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1) && (alpha == SC_ALPHA_NOALPHA)) {
+		surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection));
+	} else {
+		if (background.isSet) {
+			surface->FillRectangle(rcSegment, background);
+		} else if (vsDraw.styles[ll->styles[ll->numCharsInLine]].eolFilled) {
+			surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine]].back);
+		} else {
+			surface->FillRectangle(rcSegment, vsDraw.styles[STYLE_DEFAULT].back);
+		}
+		if (eolInSelection && vsDraw.selEOLFilled && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) {
+			SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection), alpha);
+		}
+	}
+
+	bool drawWrapMarkEnd = false;
+
+	if (vsDraw.wrapVisualFlags & SC_WRAPVISUALFLAG_END) {
+		if (subLine + 1 < ll->lines) {
+			drawWrapMarkEnd = ll->LineStart(subLine + 1) != 0;
+		}
+	}
+
+	if (drawWrapMarkEnd) {
+		PRectangle rcPlace = rcSegment;
+
+		if (vsDraw.wrapVisualFlagsLocation & SC_WRAPVISUALFLAGLOC_END_BY_TEXT) {
+			rcPlace.left = xEol + xStart + virtualSpace;
+			rcPlace.right = rcPlace.left + vsDraw.aveCharWidth;
+		} else {
+			// rcLine is clipped to text area
+			rcPlace.right = rcLine.right;
+			rcPlace.left = rcPlace.right - vsDraw.aveCharWidth;
+		}
+		DrawWrapMarker(surface, rcPlace, true, vsDraw.WrapColour());
+	}
+}
+
+static void DrawIndicator(int indicNum, int startPos, int endPos, Surface *surface, const ViewStyle &vsDraw,
+	const LineLayout *ll, int xStart, PRectangle rcLine, int subLine) {
+	const XYPOSITION subLineStart = ll->positions[ll->LineStart(subLine)];
+	PRectangle rcIndic(
+		ll->positions[startPos] + xStart - subLineStart,
+		rcLine.top + vsDraw.maxAscent,
+		ll->positions[endPos] + xStart - subLineStart,
+		rcLine.top + vsDraw.maxAscent + 3);
+	vsDraw.indicators[indicNum].Draw(surface, rcIndic, rcLine);
+}
+
+static void DrawIndicators(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll,
+	int line, int xStart, PRectangle rcLine, int subLine, int lineEnd, bool under) {
+	// Draw decorators
+	const int posLineStart = model.pdoc->LineStart(line);
+	const int lineStart = ll->LineStart(subLine);
+	const int posLineEnd = posLineStart + lineEnd;
+
+	for (Decoration *deco = model.pdoc->decorations.root; deco; deco = deco->next) {
+		if (under == vsDraw.indicators[deco->indicator].under) {
+			int startPos = posLineStart + lineStart;
+			if (!deco->rs.ValueAt(startPos)) {
+				startPos = deco->rs.EndRun(startPos);
+			}
+			while ((startPos < posLineEnd) && (deco->rs.ValueAt(startPos))) {
+				int endPos = deco->rs.EndRun(startPos);
+				if (endPos > posLineEnd)
+					endPos = posLineEnd;
+				DrawIndicator(deco->indicator, startPos - posLineStart, endPos - posLineStart,
+					surface, vsDraw, ll, xStart, rcLine, subLine);
+				startPos = endPos;
+				if (!deco->rs.ValueAt(startPos)) {
+					startPos = deco->rs.EndRun(startPos);
+				}
+			}
+		}
+	}
+
+	// Use indicators to highlight matching braces
+	if ((vsDraw.braceHighlightIndicatorSet && (model.bracesMatchStyle == STYLE_BRACELIGHT)) ||
+		(vsDraw.braceBadLightIndicatorSet && (model.bracesMatchStyle == STYLE_BRACEBAD))) {
+		int braceIndicator = (model.bracesMatchStyle == STYLE_BRACELIGHT) ? vsDraw.braceHighlightIndicator : vsDraw.braceBadLightIndicator;
+		if (under == vsDraw.indicators[braceIndicator].under) {
+			Range rangeLine(posLineStart + lineStart, posLineEnd);
+			if (rangeLine.ContainsCharacter(model.braces[0])) {
+				int braceOffset = model.braces[0] - posLineStart;
+				if (braceOffset < ll->numCharsInLine) {
+					DrawIndicator(braceIndicator, braceOffset, braceOffset + 1, surface, vsDraw, ll, xStart, rcLine, subLine);
+				}
+			}
+			if (rangeLine.ContainsCharacter(model.braces[1])) {
+				int braceOffset = model.braces[1] - posLineStart;
+				if (braceOffset < ll->numCharsInLine) {
+					DrawIndicator(braceIndicator, braceOffset, braceOffset + 1, surface, vsDraw, ll, xStart, rcLine, subLine);
+				}
+			}
+		}
+	}
+}
+
+void EditView::DrawAnnotation(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll,
+	int line, int xStart, PRectangle rcLine, int subLine, DrawPhase phase) {
+	int indent = static_cast<int>(model.pdoc->GetLineIndentation(line) * vsDraw.spaceWidth);
+	PRectangle rcSegment = rcLine;
+	int annotationLine = subLine - ll->lines;
+	const StyledText stAnnotation = model.pdoc->AnnotationStyledText(line);
+	if (stAnnotation.text && ValidStyledText(vsDraw, vsDraw.annotationStyleOffset, stAnnotation)) {
+		if (phase & drawBack) {
+			surface->FillRectangle(rcSegment, vsDraw.styles[0].back);
+		}
+		rcSegment.left = static_cast<XYPOSITION>(xStart);
+		if (model.trackLineWidth || (vsDraw.annotationVisible == ANNOTATION_BOXED)) {
+			// Only care about calculating width if tracking or need to draw box
+			int widthAnnotation = WidestLineWidth(surface, vsDraw, vsDraw.annotationStyleOffset, stAnnotation);
+			if (vsDraw.annotationVisible == ANNOTATION_BOXED) {
+				widthAnnotation += static_cast<int>(vsDraw.spaceWidth * 2); // Margins
+			}
+			if (widthAnnotation > lineWidthMaxSeen)
+				lineWidthMaxSeen = widthAnnotation;
+			if (vsDraw.annotationVisible == ANNOTATION_BOXED) {
+				rcSegment.left = static_cast<XYPOSITION>(xStart + indent);
+				rcSegment.right = rcSegment.left + widthAnnotation;
+			}
+		}
+		const int annotationLines = model.pdoc->AnnotationLines(line);
+		size_t start = 0;
+		size_t lengthAnnotation = stAnnotation.LineLength(start);
+		int lineInAnnotation = 0;
+		while ((lineInAnnotation < annotationLine) && (start < stAnnotation.length)) {
+			start += lengthAnnotation + 1;
+			lengthAnnotation = stAnnotation.LineLength(start);
+			lineInAnnotation++;
+		}
+		PRectangle rcText = rcSegment;
+		if ((phase & drawBack) && (vsDraw.annotationVisible == ANNOTATION_BOXED)) {
+			surface->FillRectangle(rcText,
+				vsDraw.styles[stAnnotation.StyleAt(start) + vsDraw.annotationStyleOffset].back);
+			rcText.left += vsDraw.spaceWidth;
+		}
+		DrawStyledText(surface, vsDraw, vsDraw.annotationStyleOffset, rcText,
+			stAnnotation, start, lengthAnnotation, phase);
+		if ((phase & drawBack) && (vsDraw.annotationVisible == ANNOTATION_BOXED)) {
+			surface->PenColour(vsDraw.styles[vsDraw.annotationStyleOffset].fore);
+			surface->MoveTo(static_cast<int>(rcSegment.left), static_cast<int>(rcSegment.top));
+			surface->LineTo(static_cast<int>(rcSegment.left), static_cast<int>(rcSegment.bottom));
+			surface->MoveTo(static_cast<int>(rcSegment.right), static_cast<int>(rcSegment.top));
+			surface->LineTo(static_cast<int>(rcSegment.right), static_cast<int>(rcSegment.bottom));
+			if (subLine == ll->lines) {
+				surface->MoveTo(static_cast<int>(rcSegment.left), static_cast<int>(rcSegment.top));
+				surface->LineTo(static_cast<int>(rcSegment.right), static_cast<int>(rcSegment.top));
+			}
+			if (subLine == ll->lines + annotationLines - 1) {
+				surface->MoveTo(static_cast<int>(rcSegment.left), static_cast<int>(rcSegment.bottom - 1));
+				surface->LineTo(static_cast<int>(rcSegment.right), static_cast<int>(rcSegment.bottom - 1));
+			}
+		}
+	}
+}
+
+static void DrawBlockCaret(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll,
+	int subLine, int xStart, int offset, int posCaret, PRectangle rcCaret, ColourDesired caretColour) {
+
+	int lineStart = ll->LineStart(subLine);
+	int posBefore = posCaret;
+	int posAfter = model.pdoc->MovePositionOutsideChar(posCaret + 1, 1);
+	int numCharsToDraw = posAfter - posCaret;
+
+	// Work out where the starting and ending offsets are. We need to
+	// see if the previous character shares horizontal space, such as a
+	// glyph / combining character. If so we'll need to draw that too.
+	int offsetFirstChar = offset;
+	int offsetLastChar = offset + (posAfter - posCaret);
+	while ((posBefore > 0) && ((offsetLastChar - numCharsToDraw) >= lineStart)) {
+		if ((ll->positions[offsetLastChar] - ll->positions[offsetLastChar - numCharsToDraw]) > 0) {
+			// The char does not share horizontal space
+			break;
+		}
+		// Char shares horizontal space, update the numChars to draw
+		// Update posBefore to point to the prev char
+		posBefore = model.pdoc->MovePositionOutsideChar(posBefore - 1, -1);
+		numCharsToDraw = posAfter - posBefore;
+		offsetFirstChar = offset - (posCaret - posBefore);
+	}
+
+	// See if the next character shares horizontal space, if so we'll
+	// need to draw that too.
+	if (offsetFirstChar < 0)
+		offsetFirstChar = 0;
+	numCharsToDraw = offsetLastChar - offsetFirstChar;
+	while ((offsetLastChar < ll->LineStart(subLine + 1)) && (offsetLastChar <= ll->numCharsInLine)) {
+		// Update posAfter to point to the 2nd next char, this is where
+		// the next character ends, and 2nd next begins. We'll need
+		// to compare these two
+		posBefore = posAfter;
+		posAfter = model.pdoc->MovePositionOutsideChar(posAfter + 1, 1);
+		offsetLastChar = offset + (posAfter - posCaret);
+		if ((ll->positions[offsetLastChar] - ll->positions[offsetLastChar - (posAfter - posBefore)]) > 0) {
+			// The char does not share horizontal space
+			break;
+		}
+		// Char shares horizontal space, update the numChars to draw
+		numCharsToDraw = offsetLastChar - offsetFirstChar;
+	}
+
+	// We now know what to draw, update the caret drawing rectangle
+	rcCaret.left = ll->positions[offsetFirstChar] - ll->positions[lineStart] + xStart;
+	rcCaret.right = ll->positions[offsetFirstChar + numCharsToDraw] - ll->positions[lineStart] + xStart;
+
+	// Adjust caret position to take into account any word wrapping symbols.
+	if ((ll->wrapIndent != 0) && (lineStart != 0)) {
+		XYPOSITION wordWrapCharWidth = ll->wrapIndent;
+		rcCaret.left += wordWrapCharWidth;
+		rcCaret.right += wordWrapCharWidth;
+	}
+
+	// This character is where the caret block is, we override the colours
+	// (inversed) for drawing the caret here.
+	int styleMain = ll->styles[offsetFirstChar];
+	FontAlias fontText = vsDraw.styles[styleMain].font;
+	surface->DrawTextClipped(rcCaret, fontText,
+		rcCaret.top + vsDraw.maxAscent, ll->chars + offsetFirstChar,
+		numCharsToDraw, vsDraw.styles[styleMain].back,
+		caretColour);
+}
+
+void EditView::DrawCarets(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll,
+	int lineDoc, int xStart, PRectangle rcLine, int subLine) const {
+	// When drag is active it is the only caret drawn
+	bool drawDrag = model.posDrag.IsValid();
+	if (hideSelection && !drawDrag)
+		return;
+	const int posLineStart = model.pdoc->LineStart(lineDoc);
+	// For each selection draw
+	for (size_t r = 0; (r<model.sel.Count()) || drawDrag; r++) {
+		const bool mainCaret = r == model.@@ Diff output truncated at 100000 characters. @@

--------------
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