[geany/geany] 788a57: Merge branch 'scintilla-update'

Colomban Wendling git-noreply at xxxxx
Wed May 22 01:38:38 UTC 2013


Branch:      refs/heads/master
Author:      Colomban Wendling <ban at herbesfolles.org>
Committer:   Colomban Wendling <ban at herbesfolles.org>
Date:        Wed, 22 May 2013 01:38:38 UTC
Commit:      788a57f6fcf6bdb152847aedfaaf09aadc7cce43
             https://github.com/geany/geany/commit/788a57f6fcf6bdb152847aedfaaf09aadc7cce43

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


Modified Paths:
--------------
    data/filetypes.c
    data/filetypes.haskell
    scintilla/gtk/PlatGTK.cxx
    scintilla/gtk/ScintillaGTK.cxx
    scintilla/include/SciLexer.h
    scintilla/include/Scintilla.h
    scintilla/include/Scintilla.iface
    scintilla/lexers/LexCPP.cxx
    scintilla/lexers/LexHaskell.cxx
    scintilla/lexers/LexLaTeX.cxx
    scintilla/lexers/LexOthers.cxx
    scintilla/lexlib/LexerModule.cxx
    scintilla/lexlib/PropSetSimple.cxx
    scintilla/lexlib/PropSetSimple.h
    scintilla/lexlib/StyleContext.h
    scintilla/lexlib/WordList.cxx
    scintilla/lexlib/WordList.h
    scintilla/scintilla_changes.patch
    scintilla/src/CallTip.cxx
    scintilla/src/CallTip.h
    scintilla/src/CellBuffer.cxx
    scintilla/src/CellBuffer.h
    scintilla/src/ContractionState.cxx
    scintilla/src/Decoration.cxx
    scintilla/src/Document.cxx
    scintilla/src/Document.h
    scintilla/src/Editor.cxx
    scintilla/src/Editor.h
    scintilla/src/Indicator.cxx
    scintilla/src/KeyMap.cxx
    scintilla/src/KeyMap.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/RunStyles.cxx
    scintilla/src/RunStyles.h
    scintilla/src/Selection.cxx
    scintilla/src/SplitVector.h
    scintilla/src/Style.cxx
    scintilla/src/Style.h
    scintilla/src/ViewStyle.cxx
    scintilla/src/ViewStyle.h
    scintilla/src/XPM.cxx
    scintilla/src/XPM.h
    scintilla/version.txt
    src/highlighting.c
    src/highlightingmappings.h

Modified: data/filetypes.c
1 files changed, 1 insertions(+), 0 deletions(-)
===================================================================
@@ -6,6 +6,7 @@
 commentline=comment_line
 commentdoc=comment_doc
 preprocessorcomment=comment
+preprocessorcommentdoc=comment_doc
 number=number_1
 word=keyword_1
 word2=keyword_2


Modified: data/filetypes.haskell
4 files changed, 4 insertions(+), 0 deletions(-)
===================================================================
@@ -20,6 +20,10 @@ module=function
 data=number_2
 pragma=preprocessor
 preprocessor=preprocessor
+stringeol=string_eol
+reserved_operator=operator
+literate_comment=comment
+literate_codedelim=other
 
 [keywords]
 # all items must be in one line


Modified: scintilla/gtk/PlatGTK.cxx
122 files changed, 58 insertions(+), 64 deletions(-)
===================================================================
@@ -9,6 +9,7 @@
 #include <stddef.h>
 #include <math.h>
 
+#include <string>
 #include <vector>
 #include <map>
 
@@ -259,6 +260,7 @@ class FontCached : Font {
 public:
 	static FontID FindOrCreate(const FontParameters &fp);
 	static void ReleaseId(FontID fid_);
+	static void ReleaseAll();
 };
 
 FontCached *FontCached::first = 0;
@@ -299,11 +301,9 @@ FontID FontCached::FindOrCreate(const FontParameters &fp) {
 	}
 	if (ret == 0) {
 		FontCached *fc = new FontCached(fp);
-		if (fc) {
-			fc->next = first;
-			first = fc;
-			ret = fc->fid;
-		}
+		fc->next = first;
+		first = fc;
+		ret = fc->fid;
 	}
 	FontMutexUnlock();
 	return ret;
@@ -328,6 +328,12 @@ void FontCached::ReleaseId(FontID fid_) {
 	FontMutexUnlock();
 }
 
+void FontCached::ReleaseAll() {
+	while (first) {
+		ReleaseId(first->GetID());
+	}
+}
+
 FontID FontCached::CreateNewFont(const FontParameters &fp) {
 	PangoFontDescription *pfd = pango_font_description_new();
 	if (pfd) {
@@ -831,8 +837,8 @@ void SurfaceImpl::Copy(PRectangle rc, Point from, Surface &surfaceSource) {
 	}
 }
 
-char *UTF8FromLatin1(const char *s, int &len) {
-	char *utfForm = new char[len*2+1];
+std::string UTF8FromLatin1(const char *s, int len) {
+	std::string utfForm(len*2 + 1, '\0');
 	size_t lenU = 0;
 	for (int i=0;i<len;i++) {
 		unsigned int uch = static_cast<unsigned char>(s[i]);
@@ -843,27 +849,26 @@ char *UTF8FromLatin1(const char *s, int &len) {
 			utfForm[lenU++] = static_cast<char>(0x80 | (uch & 0x3f));
 		}
 	}
-	utfForm[lenU] = '\0';
-	len = lenU;
+	utfForm.resize(lenU);
 	return utfForm;
 }
 
-static char *UTF8FromIconv(const Converter &conv, const char *s, int &len) {
+static std::string UTF8FromIconv(const Converter &conv, const char *s, int len) {
 	if (conv) {
-		char *utfForm = new char[len*3+1];
+		std::string utfForm(len*3+1, '\0');
 		char *pin = const_cast<char *>(s);
 		size_t inLeft = len;
-		char *pout = utfForm;
+		char *putf = &utfForm[0];
+		char *pout = putf;
 		size_t outLeft = len*3+1;
 		size_t conversions = conv.Convert(&pin, &inLeft, &pout, &outLeft);
 		if (conversions != ((size_t)(-1))) {
 			*pout = '\0';
-			len = pout - utfForm;
+			utfForm.resize(pout - putf);
 			return utfForm;
 		}
-		delete []utfForm;
 	}
-	return 0;
+	return std::string();
 }
 
 // Work out how many bytes are in a character by trying to convert using iconv,
@@ -901,18 +906,16 @@ void SurfaceImpl::DrawTextBase(PRectangle rc, Font &font_, XYPOSITION ybase, con
 	if (context) {
 		XYPOSITION xText = rc.left;
 		if (PFont(font_)->pfd) {
-			char *utfForm = 0;
+			std::string utfForm;
 			if (et == UTF8) {
 				pango_layout_set_text(layout, s, len);
 			} else {
-				if (!utfForm) {
-					SetConverter(PFont(font_)->characterSet);
-					utfForm = UTF8FromIconv(conv, s, len);
-				}
-				if (!utfForm) {	// iconv failed so treat as Latin1
+				SetConverter(PFont(font_)->characterSet);
+				utfForm = UTF8FromIconv(conv, s, len);
+				if (utfForm.empty()) {	// iconv failed so treat as Latin1
 					utfForm = UTF8FromLatin1(s, len);
 				}
-				pango_layout_set_text(layout, utfForm, len);
+				pango_layout_set_text(layout, utfForm.c_str(), utfForm.length());
 			}
 			pango_layout_set_font_description(layout, PFont(font_)->pfd);
 			pango_cairo_update_layout(context, layout);
@@ -923,7 +926,6 @@ void SurfaceImpl::DrawTextBase(PRectangle rc, Font &font_, XYPOSITION ybase, con
 #endif
 			cairo_move_to(context, xText, ybase);
 			pango_cairo_show_layout_line(context, pll);
-			delete []utfForm;
 		}
 	}
 }
@@ -1020,20 +1022,20 @@ void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, XYPOSITION
 				int positionsCalculated = 0;
 				if (et == dbcs) {
 					SetConverter(PFont(font_)->characterSet);
-					char *utfForm = UTF8FromIconv(conv, s, len);
-					if (utfForm) {
+					std::string utfForm = UTF8FromIconv(conv, s, len);
+					if (!utfForm.empty()) {
 						// Convert to UTF-8 so can ask Pango for widths, then
 						// Loop through UTF-8 and DBCS forms, taking account of different
 						// character byte lengths.
 						Converter convMeasure("UCS-2", CharacterSetID(characterSet), false);
-						pango_layout_set_text(layout, utfForm, strlen(utfForm));
+						pango_layout_set_text(layout, utfForm.c_str(), strlen(utfForm.c_str()));
 						int i = 0;
 						int clusterStart = 0;
-						ClusterIterator iti(layout, strlen(utfForm));
+						ClusterIterator iti(layout, strlen(utfForm.c_str()));
 						while (!iti.finished) {
 							iti.Next();
 							int clusterEnd = iti.curIndex;
-							int places = g_utf8_strlen(utfForm + clusterStart, clusterEnd - clusterStart);
+							int places = g_utf8_strlen(utfForm.c_str() + clusterStart, clusterEnd - clusterStart);
 							int place = 1;
 							while (clusterStart < clusterEnd) {
 								size_t lenChar = MultiByteLenFromIconv(convMeasure, s+i, len-i);
@@ -1041,38 +1043,36 @@ void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, XYPOSITION
 									positions[i++] = iti.position - (places - place) * iti.distance / places;
 									positionsCalculated++;
 								}
-								clusterStart += UTF8CharLength(utfForm+clusterStart);
+								clusterStart += UTF8CharLength(utfForm.c_str()+clusterStart);
 								place++;
 							}
 						}
-						delete []utfForm;
 						PLATFORM_ASSERT(i == lenPositions);
 					}
 				}
 				if (positionsCalculated < 1 ) {
 					// Either Latin1 or DBCS conversion failed so treat as Latin1.
 					SetConverter(PFont(font_)->characterSet);
-					char *utfForm = UTF8FromIconv(conv, s, len);
-					if (!utfForm) {
+					std::string utfForm = UTF8FromIconv(conv, s, len);
+					if (utfForm.empty()) {
 						utfForm = UTF8FromLatin1(s, len);
 					}
-					pango_layout_set_text(layout, utfForm, len);
+					pango_layout_set_text(layout, utfForm.c_str(), utfForm.length());
 					int i = 0;
 					int clusterStart = 0;
 					// Each Latin1 input character may take 1 or 2 bytes in UTF-8
 					// and groups of up to 3 may be represented as ligatures.
-					ClusterIterator iti(layout, strlen(utfForm));
+					ClusterIterator iti(layout, utfForm.length());
 					while (!iti.finished) {
 						iti.Next();
 						int clusterEnd = iti.curIndex;
-						int ligatureLength = g_utf8_strlen(utfForm + clusterStart, clusterEnd - clusterStart);
+						int ligatureLength = g_utf8_strlen(utfForm.c_str() + clusterStart, clusterEnd - clusterStart);
 						PLATFORM_ASSERT(ligatureLength > 0 && ligatureLength <= 3);
 						for (int charInLig=0; charInLig<ligatureLength; charInLig++) {
 							positions[i++] = iti.position - (ligatureLength - 1 - charInLig) * iti.distance / ligatureLength;
 						}
 						clusterStart = clusterEnd;
 					}
-					delete []utfForm;
 					PLATFORM_ASSERT(i == lenPositions);
 				}
 			}
@@ -1092,20 +1092,18 @@ void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, XYPOSITION
 XYPOSITION SurfaceImpl::WidthText(Font &font_, const char *s, int len) {
 	if (font_.GetID()) {
 		if (PFont(font_)->pfd) {
-			char *utfForm = 0;
+			std::string utfForm;
 			pango_layout_set_font_description(layout, PFont(font_)->pfd);
 			PangoRectangle pos;
 			if (et == UTF8) {
 				pango_layout_set_text(layout, s, len);
 			} else {
-				if (!utfForm) {	// use iconv
-					SetConverter(PFont(font_)->characterSet);
-					utfForm = UTF8FromIconv(conv, s, len);
-				}
-				if (!utfForm) {	// iconv failed so treat as Latin1
+				SetConverter(PFont(font_)->characterSet);
+				utfForm = UTF8FromIconv(conv, s, len);
+				if (utfForm.empty()) {	// iconv failed so treat as Latin1
 					utfForm = UTF8FromLatin1(s, len);
 				}
-				pango_layout_set_text(layout, utfForm, len);
+				pango_layout_set_text(layout, utfForm.c_str(), utfForm.length());
 			}
 #ifdef PANGO_VERSION
 			PangoLayoutLine *pangoLine = pango_layout_get_line_readonly(layout,0);
@@ -1113,7 +1111,6 @@ XYPOSITION SurfaceImpl::WidthText(Font &font_, const char *s, int len) {
 			PangoLayoutLine *pangoLine = pango_layout_get_line(layout,0);
 #endif
 			pango_layout_line_get_extents(pangoLine, NULL, &pos);
-			delete []utfForm;
 			return doubleFromPangoUnits(pos.width);
 		}
 		return 1;
@@ -1883,30 +1880,26 @@ void ListBoxX::ClearRegisteredImages() {
 void ListBoxX::SetList(const char *listText, char separator, char typesep) {
 	Clear();
 	int count = strlen(listText) + 1;
-	char *words = new char[count];
-	if (words) {
-		memcpy(words, listText, count);
-		char *startword = words;
-		char *numword = NULL;
-		int i = 0;
-		for (; words[i]; i++) {
-			if (words[i] == separator) {
-				words[i] = '\0';
-				if (numword)
-					*numword = '\0';
-				Append(startword, numword?atoi(numword + 1):-1);
-				startword = words + i + 1;
-				numword = NULL;
-			} else if (words[i] == typesep) {
-				numword = words + i;
-			}
-		}
-		if (startword) {
+	std::vector<char> words(listText, listText+count);
+	char *startword = words.data();
+	char *numword = NULL;
+	int i = 0;
+	for (; words[i]; i++) {
+		if (words[i] == separator) {
+			words[i] = '\0';
 			if (numword)
 				*numword = '\0';
 			Append(startword, numword?atoi(numword + 1):-1);
+			startword = words.data() + i + 1;
+			numword = NULL;
+		} else if (words[i] == typesep) {
+			numword = words.data() + i;
 		}
-		delete []words;
+	}
+	if (startword) {
+		if (numword)
+			*numword = '\0';
+		Append(startword, numword?atoi(numword + 1):-1);
 	}
 }
 
@@ -2165,5 +2158,6 @@ void Platform_Initialise() {
 }
 
 void Platform_Finalise() {
+	FontCached::ReleaseAll();
 	FontMutexFree();
 }


Modified: scintilla/gtk/ScintillaGTK.cxx
236 files changed, 84 insertions(+), 152 deletions(-)
===================================================================
@@ -30,7 +30,6 @@
 #ifdef SCI_LEXER
 #include "SciLexer.h"
 #endif
-#include "SVector.h"
 #include "SplitVector.h"
 #include "Partitioning.h"
 #include "RunStyles.h"
@@ -109,7 +108,7 @@ static GdkWindow *PWindow(const Window &w) {
 using namespace Scintilla;
 #endif
 
-extern char *UTF8FromLatin1(const char *s, int &len);
+extern std::string UTF8FromLatin1(const char *s, int len);
 
 class ScintillaGTK : public ScintillaBase {
 	_ScintillaObject *sci;
@@ -186,7 +185,6 @@ class ScintillaGTK : public ScintillaBase {
 	virtual bool PaintContains(PRectangle rc);
 	void FullPaint();
 	virtual PRectangle GetClientRectangle();
-	void SyncPaint(PRectangle rc);
 	virtual void ScrollText(int linesToMove);
 	virtual void SetVerticalScrollPos();
 	virtual void SetHorizontalScrollPos();
@@ -280,7 +278,6 @@ class ScintillaGTK : public ScintillaBase {
 	static void SelectionGet(GtkWidget *widget, GtkSelectionData *selection_data,
 	                         guint info, guint time);
 	static gint SelectionClear(GtkWidget *widget, GdkEventSelection *selection_event);
-	static void DragBegin(GtkWidget *widget, GdkDragContext *context);
 	gboolean DragMotionThis(GdkDragContext *context, gint x, gint y, guint dragtime);
 	static gboolean DragMotion(GtkWidget *widget, GdkDragContext *context,
 	                           gint x, gint y, guint dragtime);
@@ -373,12 +370,12 @@ static ScintillaGTK *ScintillaFromWidget(GtkWidget *widget) {
 #endif
 
 #if PLAT_GTK_WIN32
- 	// There does not seem to be a real standard for indicating that the clipboard
+	// There does not seem to be a real standard for indicating that the clipboard
 	// contains a rectangular selection, so copy Developer Studio.
 	cfColumnSelect = static_cast<CLIPFORMAT>(
 		::RegisterClipboardFormat("MSDEVColumnSelect"));
 
-  	// Get intellimouse parameters when running on win32; otherwise use
+	// Get intellimouse parameters when running on win32; otherwise use
 	// reasonable default
 #ifndef SPI_GETWHEELSCROLLLINES
 #define SPI_GETWHEELSCROLLLINES   104
@@ -837,37 +834,34 @@ void ScintillaGTK::StartDrag() {
 	               reinterpret_cast<GdkEvent *>(&evbtn));
 }
 
-static char *ConvertText(int *lenResult, char *s, size_t len, const char *charSetDest,
+static std::string ConvertText(char *s, size_t len, const char *charSetDest,
 	const char *charSetSource, bool transliterations, bool silent=false) {
 	// s is not const because of different versions of iconv disagreeing about const
-	*lenResult = 0;
-	char *destForm = 0;
+	std::string destForm;
 	Converter conv(charSetDest, charSetSource, transliterations);
 	if (conv) {
-		destForm = new char[len*3+1];
+		size_t outLeft = len*3+1;
+		destForm = std::string(outLeft, '\0');
 		char *pin = s;
 		size_t inLeft = len;
-		char *pout = destForm;
-		size_t outLeft = len*3+1;
+		char *putf = &destForm[0];
+		char *pout = putf;
 		size_t conversions = conv.Convert(&pin, &inLeft, &pout, &outLeft);
 		if (conversions == ((size_t)(-1))) {
-			if (!silent)
-				fprintf(stderr, "iconv %s->%s failed for %s\n",
-					charSetSource, charSetDest, static_cast<char *>(s));
-			delete []destForm;
-			destForm = 0;
+			if (!silent) {
+				if (len == 1)
+					fprintf(stderr, "iconv %s->%s failed for %0x '%s'\n",
+						charSetSource, charSetDest, (unsigned char)(*s), static_cast<char *>(s));
+				else
+					fprintf(stderr, "iconv %s->%s failed for %s\n",
+						charSetSource, charSetDest, static_cast<char *>(s));
+			}
+			destForm = std::string();
 		} else {
-//fprintf(stderr, "iconv OK %s %d\n", destForm, pout - destForm);
-			*pout = '\0';
-			*lenResult = pout - destForm;
+			destForm.resize(pout - putf);
 		}
 	} else {
-fprintf(stderr, "Can not iconv %s %s\n", charSetDest, charSetSource);
-	}
-	if (!destForm) {
-		destForm = new char[1];
-		destForm[0] = '\0';
-		*lenResult = 0;
+		fprintf(stderr, "Can not iconv %s %s\n", charSetDest, charSetSource);
 	}
 	return destForm;
 }
@@ -884,26 +878,18 @@ int ScintillaGTK::TargetAsUTF8(char *text) {
 		// Need to convert
 		const char *charSetBuffer = CharacterSetID();
 		if (*charSetBuffer) {
-//~ fprintf(stderr, "AsUTF8 %s %d  %0d-%0d\n", charSetBuffer, targetLength, targetStart, targetEnd);
-			char *s = new char[targetLength];
-			if (s) {
-				pdoc->GetCharRange(s, targetStart, targetLength);
-//~ fprintf(stderr, "    \"%s\"\n", s);
-				if (text) {
-					char *tmputf = ConvertText(&targetLength, s, targetLength, "UTF-8", charSetBuffer, false);
-					memcpy(text, tmputf, targetLength);
-					delete []tmputf;
-//~ fprintf(stderr, "    \"%s\"\n", text);
-				}
-				delete []s;
+			std::string s = RangeText(targetStart, targetEnd);
+			std::string tmputf = ConvertText(&s[0], targetLength, "UTF-8", charSetBuffer, false);
+			if (text) {
+				memcpy(text, tmputf.c_str(), tmputf.length());
 			}
+			return tmputf.length();
 		} else {
 			if (text) {
 				pdoc->GetCharRange(text, targetStart, targetLength);
 			}
 		}
 	}
-//~ fprintf(stderr, "Length = %d bytes\n", targetLength);
 	return targetLength;
 }
 
@@ -920,15 +906,11 @@ int ScintillaGTK::EncodedFromUTF8(char *utf8, char *encoded) {
 		// Need to convert
 		const char *charSetBuffer = CharacterSetID();
 		if (*charSetBuffer) {
-			int outLength = 0;
-			char *tmpEncoded = ConvertText(&outLength, utf8, inputLength, charSetBuffer, "UTF-8", true);
-			if (tmpEncoded) {
-				if (encoded) {
-					memcpy(encoded, tmpEncoded, outLength);
-				}
-				delete []tmpEncoded;
+			std::string tmpEncoded = ConvertText(utf8, inputLength, charSetBuffer, "UTF-8", true);
+			if (encoded) {
+				memcpy(encoded, tmpEncoded.c_str(), tmpEncoded.length());
 			}
-			return outLength;
+			return tmpEncoded.length();
 		} else {
 			if (encoded) {
 				memcpy(encoded, utf8, inputLength);
@@ -966,7 +948,7 @@ sptr_t ScintillaGTK::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam
 
 #ifdef SCI_LEXER
 		case SCI_LOADLEXERLIBRARY:
-                        LexerManager::GetInstance()->Load(reinterpret_cast<const char*>(lParam));
+			LexerManager::GetInstance()->Load(reinterpret_cast<const char*>(lParam));
 			break;
 #endif
 		case SCI_TARGETASUTF8:
@@ -1109,30 +1091,6 @@ PRectangle ScintillaGTK::GetClientRectangle() {
 	return rc;
 }
 
-// Synchronously paint a rectangle of the window.
-void ScintillaGTK::SyncPaint(PRectangle rc) {
-	paintState = painting;
-	rcPaint = rc;
-	PRectangle rcClient = GetClientRectangle();
-	paintingAllText = rcPaint.Contains(rcClient);
-	if (PWindow(wText)) {
-		Surface *sw = Surface::Allocate(SC_TECHNOLOGY_DEFAULT);
-		if (sw) {
-			cairo_t *cr = gdk_cairo_create(PWindow(wText));
-			sw->Init(cr, PWidget(wText));
-			Paint(sw, rc);
-			sw->Release();
-			delete sw;
-			cairo_destroy(cr);
-		}
-	}
-	if (paintState == paintAbandoned) {
-		// Painting area was insufficient to cover new styling or brace highlight positions
-		FullPaint();
-	}
-	paintState = notPainting;
-}
-
 void ScintillaGTK::ScrollText(int linesToMove) {
 	int diff = vs.lineHeight * -linesToMove;
 	//Platform::DebugPrintf("ScintillaGTK::ScrollText %d %d %0d,%0d %0d,%0d\n", linesToMove, diff,
@@ -1301,11 +1259,10 @@ class CaseFolderDBCS : public CaseFolderTable {
 			folded[0] = mapping[static_cast<unsigned char>(mixed[0])];
 			return 1;
 		} else if (*charSet) {
-			int convertedLength = lenMixed;
-			char *sUTF8 = ConvertText(&convertedLength, const_cast<char *>(mixed), lenMixed,
+			std::string sUTF8 = ConvertText(const_cast<char *>(mixed), lenMixed,
 				"UTF-8", charSet, false);
-			if (sUTF8) {
-				gchar *mapped = g_utf8_casefold(sUTF8, strlen(sUTF8));
+			if (!sUTF8.empty()) {
+				gchar *mapped = g_utf8_casefold(sUTF8.c_str(), sUTF8.length());
 				size_t lenMapped = strlen(mapped);
 				if (lenMapped < sizeFolded) {
 					memcpy(folded, mapped,  lenMapped);
@@ -1314,7 +1271,6 @@ class CaseFolderDBCS : public CaseFolderTable {
 					lenMapped = 1;
 				}
 				g_free(mapped);
-				delete []sUTF8;
 				return lenMapped;
 			}
 		}
@@ -1337,23 +1293,20 @@ CaseFolder *ScintillaGTK::CaseFolderForEncoding() {
 				for (int i=0x80; i<0x100; i++) {
 					char sCharacter[2] = "A";
 					sCharacter[0] = i;
-					int convertedLength = 1;
-					const char *sUTF8 = ConvertText(&convertedLength, sCharacter, 1,
-						"UTF-8", charSetBuffer, false);
-					if (sUTF8) {
-						gchar *mapped = g_utf8_casefold(sUTF8, strlen(sUTF8));
+					// Silent as some bytes have no assigned character
+					std::string sUTF8 = ConvertText(sCharacter, 1,
+						"UTF-8", charSetBuffer, false, true);
+					if (!sUTF8.empty()) {
+						gchar *mapped = g_utf8_casefold(sUTF8.c_str(), sUTF8.length());
 						if (mapped) {
-							int mappedLength = strlen(mapped);
-							const char *mappedBack = ConvertText(&mappedLength, mapped,
-								mappedLength, charSetBuffer, "UTF-8", false, true);
-							if (mappedBack && (strlen(mappedBack) == 1) && (mappedBack[0] != sCharacter[0])) {
+							std::string mappedBack = ConvertText(mapped, strlen(mapped),
+								charSetBuffer, "UTF-8", false, true);
+							if ((mappedBack.length() == 1) && (mappedBack[0] != sCharacter[0])) {
 								pcf->SetTranslation(sCharacter[0], mappedBack[0]);
 							}
-							delete []mappedBack;
 							g_free(mapped);
 						}
 					}
-					delete []sUTF8;
 				}
 				return pcf;
 			} else {
@@ -1364,6 +1317,24 @@ CaseFolder *ScintillaGTK::CaseFolderForEncoding() {
 	}
 }
 
+namespace {
+
+struct CaseMapper {
+	gchar *mapped;	// Must be freed with g_free
+	CaseMapper(const std::string &sUTF8, bool toUpperCase) {
+		if (toUpperCase) {
+			mapped = g_utf8_strup(sUTF8.c_str(), sUTF8.length());
+		} else {
+			mapped = g_utf8_strdown(sUTF8.c_str(), sUTF8.length());
+		}
+	}
+	~CaseMapper() {
+		g_free(mapped);
+	}
+};
+
+}
+
 std::string ScintillaGTK::CaseMapString(const std::string &s, int caseMapping) {
 	if (s.size() == 0)
 		return std::string();
@@ -1371,43 +1342,18 @@ CaseFolder *ScintillaGTK::CaseFolderForEncoding() {
 	if (caseMapping == cmSame)
 		return s;
 
-	const char *needsFree1 = 0;	// Must be freed with delete []
 	const char *charSetBuffer = CharacterSetID();
-	const char *sUTF8 = s.c_str();
-	int rangeBytes = s.size();
 
-	int convertedLength = rangeBytes;
-	// Change text to UTF-8
-	if (!IsUnicodeMode()) {
-		// Need to convert
-		if (*charSetBuffer) {
-			sUTF8 = ConvertText(&convertedLength, const_cast<char *>(s.c_str()), rangeBytes,
-				"UTF-8", charSetBuffer, false);
-			needsFree1 = sUTF8;
-		}
-	}
-	gchar *mapped;	// Must be freed with g_free
-	if (caseMapping == cmUpper) {
-		mapped = g_utf8_strup(sUTF8, convertedLength);
+	if (IsUnicodeMode() || !*charSetBuffer) {
+		CaseMapper mapper(s, caseMapping == cmUpper);
+		return std::string(mapper.mapped, strlen(mapper.mapped));
 	} else {
-		mapped = g_utf8_strdown(sUTF8, convertedLength);
-	}
-	int mappedLength = strlen(mapped);
-	char *mappedBack = mapped;
-
-	char *needsFree2 = 0;	// Must be freed with delete []
-	if (!IsUnicodeMode()) {
-		if (*charSetBuffer) {
-			mappedBack = ConvertText(&mappedLength, mapped, mappedLength, charSetBuffer, "UTF-8", false);
-			needsFree2 = mappedBack;
-		}
+		// Change text to UTF-8
+		std::string sUTF8 = ConvertText(const_cast<char *>(s.c_str()), s.length(),
+			"UTF-8", charSetBuffer, false);
+		CaseMapper mapper(sUTF8, caseMapping == cmUpper);
+		return ConvertText(mapper.mapped, strlen(mapper.mapped), charSetBuffer, "UTF-8", false);
 	}
-
-	std::string ret(mappedBack, mappedLength);
-	g_free(mapped);
-	delete []needsFree1;
-	delete []needsFree2;
-	return ret;
 }
 
 int ScintillaGTK::KeyDefault(int key, int modifiers) {
@@ -1528,9 +1474,7 @@ void ScintillaGTK::GetGtkSelectionText(GtkSelectionData *selectionData, Selectio
 
 	// Return empty string if selection is not a string
 	if ((selectionTypeData != GDK_TARGET_STRING) && (selectionTypeData != atomUTF8)) {
-		char *empty = new char[1];
-		empty[0] = '\0';
-		selText.Set(empty, 0, SC_CP_UTF8, 0, false, false);
+		selText.Copy("", 0, SC_CP_UTF8, 0, false, false);
 		return;
 	}
 
@@ -1544,28 +1488,24 @@ void ScintillaGTK::GetGtkSelectionText(GtkSelectionData *selectionData, Selectio
 		len--;	// Forget the extra '\0'
 #endif
 
-	char *dest;
+	std::string dest = Document::TransformLineEnds(data, len, pdoc->eolMode);
 	if (selectionTypeData == GDK_TARGET_STRING) {
-		dest = Document::TransformLineEnds(&len, data, len, pdoc->eolMode);
 		if (IsUnicodeMode()) {
 			// Unknown encoding so assume in Latin1
-			char *destPrevious = dest;
-			dest = UTF8FromLatin1(dest, len);
-			selText.Set(dest, len, SC_CP_UTF8, 0, selText.rectangular, false);
-			delete []destPrevious;
+			dest = UTF8FromLatin1(dest.c_str(), len);
+			selText.Copy(dest.c_str(), dest.length(), SC_CP_UTF8, 0, selText.rectangular, false);
 		} else {
 			// Assume buffer is in same encoding as selection
-			selText.Set(dest, len, pdoc->dbcsCodePage,
+			selText.Copy(dest.c_str(), dest.length(), pdoc->dbcsCodePage,
 				vs.styles[STYLE_DEFAULT].characterSet, isRectangular, false);
 		}
 	} else {	// UTF-8
-		dest = Document::TransformLineEnds(&len, data, len, pdoc->eolMode);
-		selText.Set(dest, len, SC_CP_UTF8, 0, isRectangular, false);
+		selText.Copy(dest.c_str(), dest.length(), SC_CP_UTF8, 0, isRectangular, false);
 		const char *charSetBuffer = CharacterSetID();
 		if (!IsUnicodeMode() && *charSetBuffer) {
 			// Convert to locale
-			dest = ConvertText(&len, selText.s, selText.len, charSetBuffer, "UTF-8", true);
-			selText.Set(dest, len, pdoc->dbcsCodePage,
+			dest = ConvertText(selText.s, selText.len, charSetBuffer, "UTF-8", true);
+			selText.Copy(dest.c_str(), dest.length(), pdoc->dbcsCodePage,
 				vs.styles[STYLE_DEFAULT].characterSet, selText.rectangular, false);
 		}
 	}
@@ -1611,11 +1551,10 @@ void ScintillaGTK::ReceivedSelection(GtkSelectionData *selection_data) {
 void ScintillaGTK::ReceivedDrop(GtkSelectionData *selection_data) {
 	dragWasDropped = true;
 	if (TypeOfGSD(selection_data) == atomUriList || TypeOfGSD(selection_data) == atomDROPFILES_DND) {
-		char *ptr = new char[LengthOfGSD(selection_data) + 1];
-		ptr[LengthOfGSD(selection_data)] = '\0';
-		memcpy(ptr, DataOfGSD(selection_data), LengthOfGSD(selection_data));
- 		NotifyURIDropped(ptr);
-		delete []ptr;
+		const char *data = reinterpret_cast<const char *>(DataOfGSD(selection_data));
+		std::vector<char> drop(data, data + LengthOfGSD(selection_data));
+		drop.push_back('\0');
+		NotifyURIDropped(drop.data());
 	} else if ((TypeOfGSD(selection_data) == GDK_TARGET_STRING) || (TypeOfGSD(selection_data) == atomUTF8)) {
 		if (TypeOfGSD(selection_data) > 0) {
 			SelectionText selText;
@@ -1637,10 +1576,9 @@ void ScintillaGTK::GetSelection(GtkSelectionData *selection_data, guint info, Se
 	// from code below
 	SelectionText *newline_normalized = NULL;
 	{
-		int tmpstr_len;
-		char *tmpstr = Document::TransformLineEnds(&tmpstr_len, text->s, text->len, SC_EOL_LF);
+		std::string tmpstr = Document::TransformLineEnds(text->s, text->len, SC_EOL_LF);
 		newline_normalized = new SelectionText();
-		newline_normalized->Set(tmpstr, tmpstr_len, SC_CP_UTF8, 0, text->rectangular, false);
+		newline_normalized->Copy(tmpstr.c_str(), tmpstr.length(), SC_CP_UTF8, 0, text->rectangular, false);
 		text = newline_normalized;
 	}
 #endif
@@ -1650,10 +1588,9 @@ void ScintillaGTK::GetSelection(GtkSelectionData *selection_data, guint info, Se
 	if ((text->codePage != SC_CP_UTF8) && (info == TARGET_UTF8_STRING)) {
 		const char *charSet = ::CharacterSetID(text->characterSet);
 		if (*charSet) {
-			int new_len;
-			char* tmputf = ConvertText(&new_len, text->s, text->len, "UTF-8", charSet, false);
+			std::string tmputf = ConvertText(text->s, text->len, "UTF-8", charSet, false);
 			converted = new SelectionText();
-			converted->Set(tmputf, new_len, SC_CP_UTF8, 0, text->rectangular, false);
+			converted->Copy(tmputf.c_str(), tmputf.length(), SC_CP_UTF8, 0, text->rectangular, false);
 			text = converted;
 		}
 	}
@@ -1923,8 +1860,7 @@ gint ScintillaGTK::MouseRelease(GtkWidget *widget, GdkEventButton *event) {
 
 // win32gtk and GTK >= 2 use SCROLL_* events instead of passing the
 // button4/5/6/7 events to the GTK app
-gint ScintillaGTK::ScrollEvent(GtkWidget *widget,
-                               GdkEventScroll *event) {
+gint ScintillaGTK::ScrollEvent(GtkWidget *widget, GdkEventScroll *event) {
 	ScintillaGTK *sciThis = ScintillaFromWidget(widget);
 	try {
 
@@ -2617,10 +2553,6 @@ gint ScintillaGTK::SelectionClear(GtkWidget *widget, GdkEventSelection *selectio
 	return TRUE;
 }
 
-void ScintillaGTK::DragBegin(GtkWidget *, GdkDragContext *) {
-	//Platform::DebugPrintf("DragBegin\n");
-}
-
 gboolean ScintillaGTK::DragMotionThis(GdkDragContext *context,
                                  gint x, gint y, guint dragtime) {
 	try {


Modified: scintilla/include/SciLexer.h
9 files changed, 9 insertions(+), 0 deletions(-)
===================================================================
@@ -120,6 +120,7 @@
 #define SCLEX_ECL 105
 #define SCLEX_OSCRIPT 106
 #define SCLEX_VISUALPROLOG 107
+#define SCLEX_LITERATEHASKELL 108
 #define SCLEX_AUTOMATIC 1000
 #define SCE_P_DEFAULT 0
 #define SCE_P_COMMENTLINE 1
@@ -161,6 +162,7 @@
 #define SCE_C_TRIPLEVERBATIM 21
 #define SCE_C_HASHQUOTEDSTRING 22
 #define SCE_C_PREPROCESSORCOMMENT 23
+#define SCE_C_PREPROCESSORCOMMENTDOC 24
 #define SCE_D_DEFAULT 0
 #define SCE_D_COMMENT 1
 #define SCE_D_COMMENTLINE 2
@@ -1022,6 +1024,10 @@
 #define SCE_HA_COMMENTBLOCK3 16
 #define SCE_HA_PRAGMA 17
 #define SCE_HA_PREPROCESSOR 18
+#define SCE_HA_STRINGEOL 19
+#define SCE_HA_RESERVED_OPERATOR 20
+#define SCE_HA_LITERATE_COMMENT 21
+#define SCE_HA_LITERATE_CODEDELIM 22
 #define SCE_T3_DEFAULT 0
 #define SCE_T3_X_DEFAULT 1
 #define SCE_T3_PREPROCESSOR 2
@@ -1326,6 +1332,9 @@
 #define SCE_POWERSHELL_FUNCTION 11
 #define SCE_POWERSHELL_USER1 12
 #define SCE_POWERSHELL_COMMENTSTREAM 13
+#define SCE_POWERSHELL_HERE_STRING 14
+#define SCE_POWERSHELL_HERE_CHARACTER 15
+#define SCE_POWERSHELL_COMMENTDOCKEYWORD 16
 #define SCE_MYSQL_DEFAULT 0
 #define SCE_MYSQL_COMMENT 1
 #define SCE_MYSQL_COMMENTLINE 2


Modified: scintilla/include/Scintilla.h
13 files changed, 13 insertions(+), 0 deletions(-)
===================================================================
@@ -264,6 +264,7 @@
 #define INDIC_SQUIGGLELOW 11
 #define INDIC_DOTBOX 12
 #define INDIC_SQUIGGLEPIXMAP 13
+#define INDIC_COMPOSITIONTHICK 14
 #define INDIC_MAX 31
 #define INDIC_CONTAINER 8
 #define INDIC0_MASK 0x20
@@ -440,7 +441,19 @@
 #define SCI_SETFOLDEXPANDED 2229
 #define SCI_GETFOLDEXPANDED 2230
 #define SCI_TOGGLEFOLD 2231
+#define SC_FOLDACTION_CONTRACT 0
+#define SC_FOLDACTION_EXPAND 1
+#define SC_FOLDACTION_TOGGLE 2
+#define SCI_FOLDLINE 2237
+#define SCI_FOLDCHILDREN 2238
+#define SCI_EXPANDCHILDREN 2239
+#define SCI_FOLDALL 2662
 #define SCI_ENSUREVISIBLE 2232
+#define SC_AUTOMATICFOLD_SHOW 0x0001
+#define SC_AUTOMATICFOLD_CLICK 0x0002
+#define SC_AUTOMATICFOLD_CHANGE 0x0004
+#define SCI_SETAUTOMATICFOLD 2663
+#define SCI_GETAUTOMATICFOLD 2664
 #define SC_FOLDFLAG_LINEBEFORE_EXPANDED 0x0002
 #define SC_FOLDFLAG_LINEBEFORE_CONTRACTED 0x0004
 #define SC_FOLDFLAG_LINEAFTER_EXPANDED 0x0008


Modified: scintilla/include/Scintilla.iface
38 files changed, 38 insertions(+), 0 deletions(-)
===================================================================
@@ -581,6 +581,7 @@ val INDIC_DOTS=10
 val INDIC_SQUIGGLELOW=11
 val INDIC_DOTBOX=12
 val INDIC_SQUIGGLEPIXMAP=13
+val INDIC_COMPOSITIONTHICK=14
 val INDIC_MAX=31
 val INDIC_CONTAINER=8
 val INDIC0_MASK=0x20
@@ -1109,9 +1110,37 @@ get bool GetFoldExpanded=2230(int line,)
 # Switch a header line between expanded and contracted.
 fun void ToggleFold=2231(int line,)
 
+enu FoldAction=SC_FOLDACTION
+val SC_FOLDACTION_CONTRACT=0
+val SC_FOLDACTION_EXPAND=1
+val SC_FOLDACTION_TOGGLE=2
+
+# Expand or contract a fold header.
+fun void FoldLine=2237(int line, int action)
+
+# Expand or contract a fold header and its children.
+fun void FoldChildren=2238(int line, int action)
+
+# Expand a fold header and all children. Use the level argument instead of the line's current level.
+fun void ExpandChildren=2239(int line, int level)
+
+# Expand or contract all fold headers.
+fun void FoldAll=2662(int action,)
+
 # Ensure a particular line is visible by expanding any header line hiding it.
 fun void EnsureVisible=2232(int line,)
 
+enu AutomaticFold=SC_AUTOMATICFOLD_
+val SC_AUTOMATICFOLD_SHOW=0x0001
+val SC_AUTOMATICFOLD_CLICK=0x0002
+val SC_AUTOMATICFOLD_CHANGE=0x0004
+
+# Set automatic folding behaviours.
+set void SetAutomaticFold=2663(int automaticFold,)
+
+# Get automatic folding behaviours.
+get int GetAutomaticFold=2664(,)
+
 enu FoldFlag=SC_FOLDFLAG_
 val SC_FOLDFLAG_LINEBEFORE_EXPANDED=0x0002
 val SC_FOLDFLAG_LINEBEFORE_CONTRACTED=0x0004
@@ -2549,6 +2578,7 @@ val SCLEX_AVS=104
 val SCLEX_ECL=105
 val SCLEX_OSCRIPT=106
 val SCLEX_VISUALPROLOG=107
+val SCLEX_LITERATEHASKELL=108
 
 # When a lexer specifies its language as SCLEX_AUTOMATIC it receives a
 # value assigned in sequence from SCLEX_AUTOMATIC+1.
@@ -2599,6 +2629,7 @@ val SCE_C_STRINGRAW=20
 val SCE_C_TRIPLEVERBATIM=21
 val SCE_C_HASHQUOTEDSTRING=22
 val SCE_C_PREPROCESSORCOMMENT=23
+val SCE_C_PREPROCESSORCOMMENTDOC=24
 # Lexical states for SCLEX_D
 lex D=SCLEX_D SCE_D_
 val SCE_D_DEFAULT=0
@@ -3583,6 +3614,10 @@ val SCE_HA_COMMENTBLOCK2=15
 val SCE_HA_COMMENTBLOCK3=16
 val SCE_HA_PRAGMA=17
 val SCE_HA_PREPROCESSOR=18
+val SCE_HA_STRINGEOL=19
+val SCE_HA_RESERVED_OPERATOR=20
+val SCE_HA_LITERATE_COMMENT=21
+val SCE_HA_LITERATE_CODEDELIM=22
 # Lexical states of SCLEX_TADS3
 lex TADS3=SCLEX_TADS3 SCE_T3_
 val SCE_T3_DEFAULT=0
@@ -3923,6 +3958,9 @@ val SCE_POWERSHELL_ALIAS=10
 val SCE_POWERSHELL_FUNCTION=11
 val SCE_POWERSHELL_USER1=12
 val SCE_POWERSHELL_COMMENTSTREAM=13
+val SCE_POWERSHELL_HERE_STRING=14
+val SCE_POWERSHELL_HERE_CHARACTER=15
+val SCE_POWERSHELL_COMMENTDOCKEYWORD=16
 # Lexical state for SCLEX_MYSQL
 lex MySQL=SCLEX_MYSQL SCE_MYSQL_
 val SCE_MYSQL_DEFAULT=0


Modified: scintilla/lexers/LexCPP.cxx
15 files changed, 10 insertions(+), 5 deletions(-)
===================================================================
@@ -455,9 +455,9 @@ int SCI_METHOD LexerCPP::WordListSet(int n, const char *wl) {
 			if (n == 4) {
 				// Rebuild preprocessorDefinitions
 				preprocessorDefinitionsStart.clear();
-				for (int nDefinition = 0; nDefinition < ppDefinitions.len; nDefinition++) {
-					char *cpDefinition = ppDefinitions.words[nDefinition];
-					char *cpEquals = strchr(cpDefinition, '=');
+				for (int nDefinition = 0; nDefinition < ppDefinitions.Length(); nDefinition++) {
+					const char *cpDefinition = ppDefinitions.WordAt(nDefinition);
+					const char *cpEquals = strchr(cpDefinition, '=');
 					if (cpEquals) {
 						std::string name(cpDefinition, cpEquals - cpDefinition);
 						std::string val(cpEquals+1);
@@ -672,7 +672,7 @@ void SCI_METHOD LexerCPP::Lex(unsigned int startPos, int length, int initStyle,
 					sc.SetState(SCE_C_DEFAULT|activitySet);
 				}
 				break;
-			case SCE_C_PREPROCESSOR: 	
+			case SCE_C_PREPROCESSOR:
 				if (options.stylingWithinPreprocessor) {
 					if (IsASpace(sc.ch)) {
 						sc.SetState(SCE_C_DEFAULT|activitySet);
@@ -683,7 +683,11 @@ void SCI_METHOD LexerCPP::Lex(unsigned int startPos, int length, int initStyle,
 					if ((isIncludePreprocessor && sc.Match('<')) || sc.Match('\"')) {
 						isStringInPreprocessor = true;
 					} else if (sc.Match('/', '*')) {
-						sc.SetState(SCE_C_PREPROCESSORCOMMENT|activitySet);
+						if (sc.Match("/**") || sc.Match("/*!")) {
+							sc.SetState(SCE_C_PREPROCESSORCOMMENTDOC|activitySet);
+						} else {
+							sc.SetState(SCE_C_PREPROCESSORCOMMENT|activitySet);
+						}
 						sc.Forward();	// Eat the *
 					} else if (sc.Match('/', '/')) {
 						sc.SetState(SCE_C_DEFAULT|activitySet);
@@ -691,6 +695,7 @@ void SCI_METHOD LexerCPP::Lex(unsigned int startPos, int length, int initStyle,
 				}
 				break;
 			case SCE_C_PREPROCESSORCOMMENT:
+			case SCE_C_PREPROCESSORCOMMENTDOC:
 				if (sc.Match('*', '/')) {
 					sc.Forward();
 					sc.ForwardSetState(SCE_C_PREPROCESSOR|activitySet);


Modified: scintilla/lexers/LexHaskell.cxx
1063 files changed, 871 insertions(+), 192 deletions(-)
===================================================================
@@ -4,21 +4,20 @@
  *    A haskell lexer for the scintilla code control.
  *    Some stuff "lended" from LexPython.cxx and LexCPP.cxx.
  *    External lexer stuff inspired from the caml external lexer.
+ *    Folder copied from Python's.
  *
  *    Written by Tobias Engvall - tumm at dtek dot chalmers dot se
  *
  *    Several bug fixes by Krasimir Angelov - kr.angelov at gmail.com
  *
- *    Improvements by kudah - kudahkukarek at gmail.com
+ *    Improved by kudah <kudahkukarek at gmail.com>
  *
  *    TODO:
- *    * Implement a folder :)
- *    * Nice Character-lexing (stuff inside '\''), LexPython has
- *      this.
- *
+ *    * A proper lexical folder to fold group declarations, comments, pragmas,
+ *      #ifdefs, explicit layout, lists, tuples, quasi-quotes, splces, etc, etc,
+ *      etc.
  *
  *****************************************************************/
-
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
@@ -26,6 +25,9 @@
 #include <assert.h>
 #include <ctype.h>
 
+#include <string>
+#include <map>
+
 #include "ILexer.h"
 #include "Scintilla.h"
 #include "SciLexer.h"
@@ -37,195 +39,746 @@
 #include "StyleContext.h"
 #include "CharacterSet.h"
 #include "LexerModule.h"
+#include "OptionSet.h"
 
 #ifdef SCI_NAMESPACE
 using namespace Scintilla;
 #endif
 
-#ifdef BUILD_AS_EXTERNAL_LEXER
+static int u_iswalpha(int);
+static int u_iswalnum(int);
+static int u_iswupper(int);
+static int u_IsHaskellSymbol(int);
 
-#include "ExternalLexer.h"
-#include "WindowAccessor.h"
+// #define HASKELL_UNICODE
 
-#define BUILD_EXTERNAL_LEXER 0
+#ifndef HASKELL_UNICODE
+
+// Stubs
+
+static int u_iswalpha(int) {
+   return 0;
+}
+
+static int u_iswalnum(int) {
+   return 0;
+}
+
+static int u_iswupper(int) {
+   return 0;
+}
+
+static int u_IsHaskellSymbol(int) {
+   return 0;
+}
 
 #endif
 
-#define HA_MODE_DEFAULT     0
-#define HA_MODE_IMPORT1     1
-#define HA_MODE_IMPORT2     2
-#define HA_MODE_IMPORT3     3
-#define HA_MODE_MODULE      4
-#define HA_MODE_FFI         5
-#define HA_MODE_TYPE        6
+static inline bool IsHaskellLetter(const int ch) {
+   if (IsASCII(ch)) {
+      return (ch >= 'a' && ch <= 'z')
+          || (ch >= 'A' && ch <= 'Z');
+   } else {
+      return u_iswalpha(ch) != 0;
+   }
+}
+
+static inline bool IsHaskellAlphaNumeric(const int ch) {
+   if (IsASCII(ch)) {
+      return IsAlphaNumeric(ch);
+   } else {
+      return u_iswalnum(ch) != 0;
+   }
+}
+
+static inline bool IsHaskellUpperCase(const int ch) {
+   if (IsASCII(ch)) {
+      return ch >= 'A' && ch <= 'Z';
+   } else {
+      return u_iswupper(ch) != 0;
+   }
+}
 
-static inline bool IsAWordStart(const int ch) {
-   return (IsLowerCase(ch) || IsUpperCase(ch) || ch == '_');
+static inline bool IsAnHaskellOperatorChar(const int ch) {
+   if (IsASCII(ch)) {
+      return
+         (  ch == '!' || ch == '#' || ch == '$' || ch == '%'
+         || ch == '&' || ch == '*' || ch == '+' || ch == '-'
+         || ch == '.' || ch == '/' || ch == ':' || ch == '<'
+         || ch == '=' || ch == '>' || ch == '?' || ch == '@'
+         || ch == '^' || ch == '|' || ch == '~' || ch == '\\');
+   } else {
+      return u_IsHaskellSymbol(ch) != 0;
+   }
 }
 
-static inline bool IsAWordChar(const int ch, const bool magicHash) {
-   return (  IsAlphaNumeric(ch)
+static inline bool IsAHaskellWordStart(const int ch) {
+   return IsHaskellLetter(ch) || ch == '_';
+}
+
+static inline bool IsAHaskellWordChar(const int ch) {
+   return (  IsHaskellAlphaNumeric(ch)
           || ch == '_'
-          || ch == '\''
-          || (magicHash && ch == '#'));
+          || ch == '\'');
 }
 
-static inline bool IsAnOperatorChar(const int ch) {
-   return
-      (  ch == '!' || ch == '#' || ch == '$' || ch == '%'
-      || ch == '&' || ch == '*' || ch == '+' || ch == '-'
-      || ch == '.' || ch == '/' || ch == ':' || ch == '<'
-      || ch == '=' || ch == '>' || ch == '?' || ch == '@'
-      || ch == '\\' || ch == '^' || ch == '|' || ch == '~');
+static inline bool IsCommentBlockStyle(int style) {
+   return (style >= SCE_HA_COMMENTBLOCK && style <= SCE_HA_COMMENTBLOCK3);
 }
 
-static void ColorizeHaskellDoc(unsigned int startPos, int length, int initStyle,
-                               WordList *keywordlists[], Accessor &styler) {
+static inline bool IsCommentStyle(int style) {
+   return (style >= SCE_HA_COMMENTLINE && style <= SCE_HA_COMMENTBLOCK3)
+       || ( style == SCE_HA_LITERATE_COMMENT
+         || style == SCE_HA_LITERATE_CODEDELIM);
+}
 
-   WordList &keywords = *keywordlists[0];
-   WordList &ffi      = *keywordlists[1];
+// styles which do not belong to Haskell, but to external tools
+static inline bool IsExternalStyle(int style) {
+   return ( style == SCE_HA_PREPROCESSOR
+         || style == SCE_HA_LITERATE_COMMENT
+         || style == SCE_HA_LITERATE_CODEDELIM);
+}
 
-   // property lexer.haskell.allow.hash
-   //  Set to 1 to allow the # character in identifiers with the haskell lexer.
-   //  (GHC -XMagicHash extension)
-   const bool magicHash = styler.GetPropertyInt("lexer.haskell.allow.hash") != 0;
-   const bool stylingWithinPreprocessor = styler.GetPropertyInt("styling.within.preprocessor") != 0;
+static inline int CommentBlockStyleFromNestLevel(const unsigned int nestLevel) {
+   return SCE_HA_COMMENTBLOCK + (nestLevel % 3);
+}
 
-   StyleContext sc(startPos, length, initStyle, styler);
+// Mangled version of lexlib/Accessor.cxx IndentAmount.
+// Modified to treat comment blocks as whitespace
+// plus special case for commentline/preprocessor.
+static int HaskellIndentAmount(Accessor &styler, const int line) {
+
+   // Determines the indentation level of the current line
+   // Comment blocks are treated as whitespace
+
+   int pos = styler.LineStart(line);
+   int eol_pos = styler.LineStart(line + 1) - 1;
+
+   char ch = styler[pos];
+   int style = styler.StyleAt(pos);
+
+   int indent = 0;
+   bool inPrevPrefix = line > 0;
+
+   int posPrev = inPrevPrefix ? styler.LineStart(line-1) : 0;
+
+   while ((  ch == ' ' || ch == '\t'
+          || IsCommentBlockStyle(style)
+          || style == SCE_HA_LITERATE_CODEDELIM)
+         && (pos < eol_pos)) {
+      if (inPrevPrefix) {
+         char chPrev = styler[posPrev++];
+         if (chPrev != ' ' && chPrev != '\t') {
+            inPrevPrefix = false;
+         }
+      }
+      if (ch == '\t') {
+         indent = (indent / 8 + 1) * 8;
+      } else { // Space or comment block
+         indent++;
+      }
+      pos++;
+      ch = styler[pos];
+      style = styler.StyleAt(pos);
+   }
+
+   indent += SC_FOLDLEVELBASE;
+   // if completely empty line or the start of a comment or preprocessor...
+   if (  styler.LineStart(line) == styler.Length()
+      || ch == ' '
+      || ch == '\t'
+      || ch == '\n'
+      || ch == '\r'
+      || IsCommentStyle(style)
+      || style == SCE_HA_PREPROCESSOR)
+      return indent | SC_FOLDLEVELWHITEFLAG;
+   else
+      return indent;
+}
+
+struct OptionsHaskell {
+   bool magicHash;
+   bool allowQuotes;
+   bool implicitParams;
+   bool highlightSafe;
+   bool cpp;
+   bool stylingWithinPreprocessor;
+   bool fold;
+   bool foldComment;
+   bool foldCompact;
+   bool foldImports;
+   OptionsHaskell() {
+      magicHash = true;       // Widespread use, enabled by default.
+      allowQuotes = true;     // Widespread use, enabled by default.
+      implicitParams = false; // Fell out of favor, seldom used, disabled.
+      highlightSafe = true;   // Moderately used, doesn't hurt to enable.
+      cpp = true;             // Widespread use, enabled by default;
+      stylingWithinPreprocessor = false;
+      fold = false;
+      foldComment = false;
+      foldCompact = false;
+      foldImports = false;
+   }
+};
+
+static const char * const haskellWordListDesc[] = {
+   "Keywords",
+   "FFI",
+   "Reserved operators",
+   0
+};
+
+struct OptionSetHaskell : public OptionSet<OptionsHaskell> {
+   OptionSetHaskell() {
+      DefineProperty("lexer.haskell.allow.hash", &OptionsHaskell::magicHash,
+         "Set to 0 to disallow the '#' character at the end of identifiers and "
+         "literals with the haskell lexer "
+         "(GHC -XMagicHash extension)");
+
+      DefineProperty("lexer.haskell.allow.quotes", &OptionsHaskell::allowQuotes,
+         "Set to 0 to disable highlighting of Template Haskell name quotations "
+         "and promoted constructors "
+         "(GHC -XTemplateHaskell and -XDataKinds extensions)");
+
+      DefineProperty("lexer.haskell.allow.questionmark", &OptionsHaskell::implicitParams,
+         "Set to 1 to allow the '?' character at the start of identifiers "
+         "with the haskell lexer "
+         "(GHC & Hugs -XImplicitParams extension)");
+
+      DefineProperty("lexer.haskell.import.safe", &OptionsHaskell::highlightSafe,
+         "Set to 0 to disallow \"safe\" keyword in imports "
+         "(GHC -XSafe, -XTrustworthy, -XUnsafe extensions)");
+
+      DefineProperty("lexer.haskell.cpp", &OptionsHaskell::cpp,
+         "Set to 0 to disable C-preprocessor highlighting "
+         "(-XCPP extension)");
+
+      DefineProperty("styling.within.preprocessor", &OptionsHaskell::stylingWithinPreprocessor,
+         "For Haskell code, determines whether all preprocessor code is styled in the "
+         "preprocessor style (0, the default) or only from the initial # to the end "
+         "of the command word(1)."
+         );
+
+      DefineProperty("fold", &OptionsHaskell::fold);
+
+      DefineProperty("fold.comment", &OptionsHaskell::foldComment);
+
+      DefineProperty("fold.compact", &OptionsHaskell::foldCompact);
+
+      DefineProperty("fold.haskell.imports", &OptionsHaskell::foldImports,
+         "Set to 1 to enable folding of import declarations");
+
+      DefineWordListSets(haskellWordListDesc);
+   }
+};
+
+class LexerHaskell : public ILexer {
+   bool literate;
+   int firstImportLine;
+   int firstImportIndent;
+   WordList keywords;
+   WordList ffi;
+   WordList reserved_operators;
+   OptionsHaskell options;
+   OptionSetHaskell osHaskell;
+
+   enum HashCount {
+       oneHash
+      ,twoHashes
+      ,unlimitedHashes
+   };
+
+   enum KeywordMode {
+       HA_MODE_DEFAULT = 0
+      ,HA_MODE_IMPORT1 = 1 // after "import", before "qualified" or "safe" or package name or module name.
+      ,HA_MODE_IMPORT2 = 2 // after module name, before "as" or "hiding".
+      ,HA_MODE_IMPORT3 = 3 // after "as", before "hiding"
+      ,HA_MODE_MODULE  = 4 // after "module", before module name.
+      ,HA_MODE_FFI     = 5 // after "foreign", before FFI keywords
+      ,HA_MODE_TYPE    = 6 // after "type" or "data", before "family"
+   };
+
+   enum LiterateMode {
+       LITERATE_BIRD  = 0 // if '>' is the first character on the line,
+                          //   color '>' as a codedelim and the rest of
+                          //   the line as code.
+                          // else if "\begin{code}" is the only word on the
+                          //    line except whitespace, switch to LITERATE_BLOCK
+                          // otherwise color the line as a literate comment.
+      ,LITERATE_BLOCK = 1 // if the string "\end{code}" is encountered at column
+                          //   0 ignoring all later characters, color the line
+                          //   as a codedelim and switch to LITERATE_BIRD
+                          // otherwise color the line as code.
+   };
+
+   struct HaskellLineInfo {
+      unsigned int nestLevel; // 22 bits ought to be enough for anybody
+      unsigned int nonexternalStyle; // 5 bits, widen if number of styles goes
+                                     // beyond 31.
+      bool pragma;
+      LiterateMode lmode;
+      KeywordMode mode;
+
+      HaskellLineInfo(int state) :
+         nestLevel (state >> 10)
+       , nonexternalStyle ((state >> 5) & 0x1F)
+       , pragma ((state >> 4) & 0x1)
+       , lmode (static_cast<LiterateMode>((state >> 3) & 0x1))
+       , mode (static_cast<KeywordMode>(state & 0x7))
+         {}
+
+      int ToLineState() {
+         return
+              (nestLevel << 10)
+            | (nonexternalStyle << 5)
+            | (pragma << 4)
+            | (lmode << 3)
+            | mode;
+      }
+   };
+
+   inline void skipMagicHash(StyleContext &sc, const HashCount hashes) const {
+      if (options.magicHash && sc.ch == '#') {
+         sc.Forward();
+         if (hashes == twoHashes && sc.ch == '#') {
+            sc.Forward();
+         } else if (hashes == unlimitedHashes) {
+            while (sc.ch == '#') {
+               sc.Forward();
+            }
+         }
+      }
+   }
+
+   bool LineContainsImport(const int line, Accessor &styler) const {
+      if (options.foldImports) {
+         int currentPos = styler.LineStart(line);
+         int style = styler.StyleAt(currentPos);
+
+         int eol_pos = styler.LineStart(line + 1) - 1;
+
+         while (currentPos < eol_pos) {
+            int ch = styler[currentPos];
+            style = styler.StyleAt(currentPos);
+
+            if (ch == ' ' || ch == '\t'
+             || IsCommentBlockStyle(style)
+             || style == SCE_HA_LITERATE_CODEDELIM) {
+               currentPos++;
+            } else {
+               break;
+            }
+         }
+
+         return (style == SCE_HA_KEYWORD
+              && styler.Match(currentPos, "import"));
+      } else {
+         return false;
+      }
+   }
+
+   inline int IndentAmountWithOffset(Accessor &styler, const int line) const {
+      const int indent = HaskellIndentAmount(styler, line);
+      const int indentLevel = indent & SC_FOLDLEVELNUMBERMASK;
+      return indentLevel <= ((firstImportIndent - 1) + SC_FOLDLEVELBASE)
+               ? indent
+               : (indentLevel + firstImportIndent) | (indent & ~SC_FOLDLEVELNUMBERMASK);
+   }
+
+   inline int IndentLevelRemoveIndentOffset(const int indentLevel) const {
+      return indentLevel <= ((firstImportIndent - 1) + SC_FOLDLEVELBASE)
+            ? indentLevel
+            : indentLevel - firstImportIndent;
+   }
+
+public:
+   LexerHaskell(bool literate_)
+      : literate(literate_)
+      , firstImportLine(-1)
+      , firstImportIndent(0)
+      {}
+   virtual ~LexerHaskell() {}
+
+   void SCI_METHOD Release() {
+      delete this;
+   }
+
+   int SCI_METHOD Version() const {
+      return lvOriginal;
+   }
+
+   const char * SCI_METHOD PropertyNames() {
+      return osHaskell.PropertyNames();
+   }
+
+   int SCI_METHOD PropertyType(const char *name) {
+      return osHaskell.PropertyType(name);
+   }
+
+   const char * SCI_METHOD DescribeProperty(const char *name) {
+      return osHaskell.DescribeProperty(name);
+   }
+
+   int SCI_METHOD PropertySet(const char *key, const char *val);
+
+   const char * SCI_METHOD DescribeWordListSets() {
+      return osHaskell.DescribeWordListSets();
+   }
+
+   int SCI_METHOD WordListSet(int n, const char *wl);
+
+   void SCI_METHOD Lex(unsigned int startPos, int length, int initStyle, IDocument *pAccess);
+
+   void SCI_METHOD Fold(unsigned int startPos, int length, int initStyle, IDocument *pAccess);
+
+   void * SCI_METHOD PrivateCall(int, void *) {
+      return 0;
+   }
+
+   static ILexer *LexerFactoryHaskell() {
+      return new LexerHaskell(false);
+   }
+
+   static ILexer *LexerFactoryLiterateHaskell() {
+      return new LexerHaskell(true);
+   }
+};
+
+int SCI_METHOD LexerHaskell::PropertySet(const char *key, const char *val) {
+   if (osHaskell.PropertySet(&options, key, val)) {
+      return 0;
+   }
+   return -1;
+}
+
+int SCI_METHOD LexerHaskell::WordListSet(int n, const char *wl) {
+   WordList *wordListN = 0;
+   switch (n) {
+   case 0:
+      wordListN = &keywords;
+      break;
+   case 1:
+      wordListN = &ffi;
+      break;
+   case 2:
+      wordListN = &reserved_operators;
+      break;
+   }
+   int firstModification = -1;
+   if (wordListN) {
+      WordList wlNew;
+      wlNew.Set(wl);
+      if (*wordListN != wlNew) {
+         wordListN->Set(wl);
+         firstModification = 0;
+      }
+   }
+   return firstModification;
+}
+
+void SCI_METHOD LexerHaskell::Lex(unsigned int startPos, int length, int initStyle
+                                 ,IDocument *pAccess) {
+   LexAccessor styler(pAccess);
 
    int lineCurrent = styler.GetLine(startPos);
-   int state = lineCurrent ? styler.GetLineState(lineCurrent-1)
-                           : HA_MODE_DEFAULT;
-   int mode  = state & 0xF;
-   int xmode = state >> 4; // obscure parameter. Means different things in different modes.
+
+   HaskellLineInfo hs = HaskellLineInfo(lineCurrent ? styler.GetLineState(lineCurrent-1) : 0);
+
+   // Do not leak onto next line
+   if (initStyle == SCE_HA_STRINGEOL)
+      initStyle = SCE_HA_DEFAULT;
+   else if (initStyle == SCE_HA_LITERATE_CODEDELIM)
+      initStyle = hs.nonexternalStyle;
+
+   StyleContext sc(startPos, length, initStyle, styler);
+
+   int base = 10;
+   bool dot = false;
+
+   bool inDashes = false;
+   bool alreadyInTheMiddleOfOperator = false;
+
+   assert(!(IsCommentBlockStyle(initStyle) && hs.nestLevel == 0));
 
    while (sc.More()) {
       // Check for state end
 
+      if (!IsExternalStyle(sc.state)) {
+         hs.nonexternalStyle = sc.state;
+      }
+
+      // For lexer to work, states should unconditionally forward at least one
+      // character.
+      // If they don't, they should still check if they are at line end and
+      // forward if so.
+      // If a state forwards more than one character, it should check every time
+      // that it is not a line end and cease forwarding otherwise.
+      if (sc.atLineEnd) {
+         // Remember the line state for future incremental lexing
+         styler.SetLineState(lineCurrent, hs.ToLineState());
+         lineCurrent++;
+      }
+
+      // Handle line continuation generically.
+      if (sc.ch == '\\' && (sc.chNext == '\n' || sc.chNext == '\r')
+         && (  sc.state == SCE_HA_STRING
+            || sc.state == SCE_HA_PREPROCESSOR)) {
+         // Remember the line state for future incremental lexing
+         styler.SetLineState(lineCurrent, hs.ToLineState());
+         lineCurrent++;
+
+         sc.Forward();
+         if (sc.ch == '\r' && sc.chNext == '\n') {
+            sc.Forward();
+         }
+         sc.Forward();
+
+         continue;
+      }
+
+      if (sc.atLineStart) {
+
+         if (sc.state == SCE_HA_STRING || sc.state == SCE_HA_CHARACTER) {
+            // Prevent SCE_HA_STRINGEOL from leaking back to previous line
+            sc.SetState(sc.state);
+         }
+
+         if (literate && hs.lmode == LITERATE_BIRD) {
+            if (!IsExternalStyle(sc.state)) {
+               sc.SetState(SCE_HA_LITERATE_COMMENT);
+            }
+         }
+      }
+
+      // External
+         // Literate
+      if (  literate && hs.lmode == LITERATE_BIRD && sc.atLineStart
+         && sc.ch == '>') {
+            sc.SetState(SCE_HA_LITERATE_CODEDELIM);
+            sc.ForwardSetState(hs.nonexternalStyle);
+      }
+      else if (literate && hs.lmode == LITERATE_BIRD && sc.atLineStart
+            && (  sc.ch == ' ' || sc.ch == '\t'
+               || sc.Match("\\begin{code}"))) {
+         sc.SetState(sc.state);
+
+         while ((sc.ch == ' ' || sc.ch == '\t') && sc.More())
+            sc.Forward();
+
+         if (sc.Match("\\begin{code}")) {
+            sc.Forward(static_cast<int>(strlen("\\begin{code}")));
+
+            bool correct = true;
+
+            while (!sc.atLineEnd && sc.More()) {
+               if (sc.ch != ' ' && sc.ch != '\t') {
+                  correct = false;
+               }
+               sc.Forward();
+            }
+
+            if (correct) {
+               sc.ChangeState(SCE_HA_LITERATE_CODEDELIM); // color the line end
+               hs.lmode = LITERATE_BLOCK;
+            }
+         }
+      }
+      else if (literate && hs.lmode == LITERATE_BLOCK && sc.atLineStart
+            && sc.Match("\\end{code}")) {
+         sc.SetState(SCE_HA_LITERATE_CODEDELIM);
+
+         sc.Forward(static_cast<int>(strlen("\\end{code}")));
+
+         while (!sc.atLineEnd && sc.More()) {
+            sc.Forward();
+         }
+
+         sc.SetState(SCE_HA_LITERATE_COMMENT);
+         hs.lmode = LITERATE_BIRD;
+      }
+         // Preprocessor
+      else if (sc.atLineStart && sc.ch == '#' && options.cpp) {
+         sc.SetState(SCE_HA_PREPROCESSOR);
+         sc.Forward();
+      }
+            // Literate
+      else if (sc.state == SCE_HA_LITERATE_COMMENT) {
+         sc.Forward();
+      }
+      else if (sc.state == SCE_HA_LITERATE_CODEDELIM) {
+         sc.ForwardSetState(hs.nonexternalStyle);
+      }
+            // Preprocessor
+      else if (sc.state == SCE_HA_PREPROCESSOR) {
+         if (sc.atLineEnd) {
+            sc.SetState(options.stylingWithinPreprocessor
+                        ? SCE_HA_DEFAULT
+                        : hs.nonexternalStyle);
+            sc.Forward(); // prevent double counting a line
+         } else if (options.stylingWithinPreprocessor && !IsHaskellLetter(sc.ch)) {
+            sc.SetState(SCE_HA_DEFAULT);
+         } else {
+            sc.Forward();
+         }
+      }
+      // Haskell
          // Operator
-      if (sc.state == SCE_HA_OPERATOR) {
+      else if (sc.state == SCE_HA_OPERATOR) {
          int style = SCE_HA_OPERATOR;
 
-         if (sc.ch == ':' &&
+         if ( sc.ch == ':'
+            && !alreadyInTheMiddleOfOperator
             // except "::"
-            !(sc.chNext == ':' && !IsAnOperatorChar(sc.GetRelative(2)))) {
+            && !( sc.chNext == ':'
+               && !IsAnHaskellOperatorChar(sc.GetRelative(2)))) {
             style = SCE_HA_CAPITAL;
          }
 
-         while(IsAnOperatorChar(sc.ch))
+         alreadyInTheMiddleOfOperator = false;
+
+         while (IsAnHaskellOperatorChar(sc.ch))
                sc.Forward();
 
-         styler.ColourTo(sc.currentPos - 1, style);
-         sc.ChangeState(SCE_HA_DEFAULT);
+         char s[100];
+         sc.GetCurrent(s, sizeof(s));
+
+         if (reserved_operators.InList(s))
+            style = SCE_HA_RESERVED_OPERATOR;
+
+         sc.ChangeState(style);
+         sc.SetState(SCE_HA_DEFAULT);
       }
          // String
       else if (sc.state == SCE_HA_STRING) {
-         if (sc.ch == '\"') {
+         if (sc.atLineEnd) {
+            sc.ChangeState(SCE_HA_STRINGEOL);
+            sc.ForwardSetState(SCE_HA_DEFAULT);
+         } else if (sc.ch == '\"') {
             sc.Forward();
+            skipMagicHash(sc, oneHash);
             sc.SetState(SCE_HA_DEFAULT);
          } else if (sc.ch == '\\') {
             sc.Forward(2);
-         } else if (sc.atLineEnd) {
-            sc.SetState(SCE_HA_DEFAULT);
          } else {
             sc.Forward();
          }
       }
          // Char
       else if (sc.state == SCE_HA_CHARACTER) {
-         if (sc.ch == '\'') {
+         if (sc.atLineEnd) {
+            sc.ChangeState(SCE_HA_STRINGEOL);
+            sc.ForwardSetState(SCE_HA_DEFAULT);
+         } else if (sc.ch == '\'') {
             sc.Forward();
+            skipMagicHash(sc, oneHash);
             sc.SetState(SCE_HA_DEFAULT);
          } else if (sc.ch == '\\') {
             sc.Forward(2);
-         } else if (sc.atLineEnd) {
-            sc.SetState(SCE_HA_DEFAULT);
          } else {
             sc.Forward();
          }
       }
          // Number
       else if (sc.state == SCE_HA_NUMBER) {
-         if (IsADigit(sc.ch, xmode) ||
-            (sc.ch=='.' && IsADigit(sc.chNext, xmode))) {
+         if (sc.atLineEnd) {
+            sc.SetState(SCE_HA_DEFAULT);
+            sc.Forward(); // prevent double counting a line
+         } else if (IsADigit(sc.ch, base)) {
             sc.Forward();
-         } else if ((xmode == 10) &&
+         } else if (sc.ch=='.' && dot && IsADigit(sc.chNext, base)) {
+            sc.Forward(2);
+            dot = false;
+         } else if ((base == 10) &&
                     (sc.ch == 'e' || sc.ch == 'E') &&
                     (IsADigit(sc.chNext) || sc.chNext == '+' || sc.chNext == '-')) {
             sc.Forward();
             if (sc.ch == '+' || sc.ch == '-')
                 sc.Forward();
          } else {
+            skipMagicHash(sc, twoHashes);
             sc.SetState(SCE_HA_DEFAULT);
          }
       }
          // Keyword or Identifier
       else if (sc.state == SCE_HA_IDENTIFIER) {
+         int style = IsHaskellUpperCase(sc.ch) ? SCE_HA_CAPITAL : SCE_HA_IDENTIFIER;
+
+         assert(IsAHaskellWordStart(sc.ch));
+
+         sc.Forward();
+
          while (sc.More()) {
-            if (IsAWordChar(sc.ch, magicHash)) {
+            if (IsAHaskellWordChar(sc.ch)) {
                sc.Forward();
-            } else if (xmode == SCE_HA_CAPITAL && sc.ch=='.') {
-               if (isupper(sc.chNext)) {
-                  xmode = SCE_HA_CAPITAL;
+            } else if (sc.ch == '.' && style == SCE_HA_CAPITAL) {
+               if (IsHaskellUpperCase(sc.chNext)) {
                   sc.Forward();
-               } else if (IsAWordStart(sc.chNext)) {
-                  xmode = SCE_HA_IDENTIFIER;
+                  style = SCE_HA_CAPITAL;
+               } else if (IsAHaskellWordStart(sc.chNext)) {
                   sc.Forward();
-               } else if (IsAnOperatorChar(sc.chNext)) {
-                  xmode = SCE_HA_OPERATOR;
+                  style = SCE_HA_IDENTIFIER;
+               } else if (IsAnHaskellOperatorChar(sc.chNext)) {
                   sc.Forward();
+                  style = sc.ch == ':' ? SCE_HA_CAPITAL : SCE_HA_OPERATOR;
+                  while (IsAnHaskellOperatorChar(sc.ch))
+                     sc.Forward();
+                  break;
                } else {
                   break;
                }
-            } else if (xmode == SCE_HA_OPERATOR && IsAnOperatorChar(sc.ch)) {
-               sc.Forward();
             } else {
                break;
             }
          }
 
+         skipMagicHash(sc, unlimitedHashes);
+
          char s[100];
          sc.GetCurrent(s, sizeof(s));
 
-         int style = xmode;
-
-         int new_mode = HA_MODE_DEFAULT;
+         KeywordMode new_mode = HA_MODE_DEFAULT;
 
          if (keywords.InList(s)) {
             style = SCE_HA_KEYWORD;
-         } else if (isupper(s[0])) {
-            if (mode >= HA_MODE_IMPORT1 && mode <= HA_MODE_IMPORT3) {
+         } else if (style == SCE_HA_CAPITAL) {
+            if (hs.mode == HA_MODE_IMPORT1 || hs.mode == HA_MODE_IMPORT3) {
                style    = SCE_HA_MODULE;
                new_mode = HA_MODE_IMPORT2;
-            } else if (mode == HA_MODE_MODULE) {
+            } else if (hs.mode == HA_MODE_MODULE) {
                style = SCE_HA_MODULE;
             }
-         } else if (mode == HA_MODE_IMPORT1 &&
+         } else if (hs.mode == HA_MODE_IMPORT1 &&
                     strcmp(s,"qualified") == 0) {
              style    = SCE_HA_KEYWORD;
              new_mode = HA_MODE_IMPORT1;
-         } else if (mode == HA_MODE_IMPORT2) {
+         } else if (options.highlightSafe &&
+                    hs.mode == HA_MODE_IMPORT1 &&
+                    strcmp(s,"safe") == 0) {
+             style    = SCE_HA_KEYWORD;
+             new_mode = HA_MODE_IMPORT1;
+         } else if (hs.mode == HA_MODE_IMPORT2) {
              if (strcmp(s,"as") == 0) {
                 style    = SCE_HA_KEYWORD;
                 new_mode = HA_MODE_IMPORT3;
             } else if (strcmp(s,"hiding") == 0) {
                 style     = SCE_HA_KEYWORD;
             }
-         } else if (mode == HA_MODE_TYPE) {
+         } else if (hs.mode == HA_MODE_TYPE) {
             if (strcmp(s,"family") == 0)
                style    = SCE_HA_KEYWORD;
          }
 
-         if (mode == HA_MODE_FFI) {
+         if (hs.mode == HA_MODE_FFI) {
             if (ffi.InList(s)) {
                style = SCE_HA_KEYWORD;
                new_mode = HA_MODE_FFI;
             }
          }
 
-         styler.ColourTo(sc.currentPos - 1, style);
+         sc.ChangeState(style);
+         sc.SetState(SCE_HA_DEFAULT);
 
-         if (strcmp(s,"import") == 0 && mode != HA_MODE_FFI)
+         if (strcmp(s,"import") == 0 && hs.mode != HA_MODE_FFI)
             new_mode = HA_MODE_IMPORT1;
          else if (strcmp(s,"module") == 0)
             new_mode = HA_MODE_MODULE;
@@ -235,87 +788,88 @@ static void ColorizeHaskellDoc(unsigned int startPos, int length, int initStyle,
                || strcmp(s,"data") == 0)
             new_mode = HA_MODE_TYPE;
 
-         xmode = 0;
-         sc.ChangeState(SCE_HA_DEFAULT);
-         mode = new_mode;
+         hs.mode = new_mode;
       }
 
          // Comments
             // Oneliner
       else if (sc.state == SCE_HA_COMMENTLINE) {
-         if (xmode == 1 && sc.ch != '-') {
-            xmode = 0;
-            if (IsAnOperatorChar(sc.ch))
+         if (sc.atLineEnd) {
+            sc.SetState(hs.pragma ? SCE_HA_PRAGMA : SCE_HA_DEFAULT);
+            sc.Forward(); // prevent double counting a line
+         } else if (inDashes && sc.ch != '-' && !hs.pragma) {
+            inDashes = false;
+            if (IsAnHaskellOperatorChar(sc.ch)) {
+               alreadyInTheMiddleOfOperator = true;
                sc.ChangeState(SCE_HA_OPERATOR);
-         } else if (sc.atLineEnd) {
-            sc.SetState(SCE_HA_DEFAULT);
+            }
          } else {
             sc.Forward();
          }
       }
             // Nested
-      else if (sc.state == SCE_HA_COMMENTBLOCK) {
+      else if (IsCommentBlockStyle(sc.state)) {
          if (sc.Match('{','-')) {
+            sc.SetState(CommentBlockStyleFromNestLevel(hs.nestLevel));
             sc.Forward(2);
-            xmode++;
-         }
-         else if (sc.Match('-','}')) {
+            hs.nestLevel++;
+         } else if (sc.Match('-','}')) {
             sc.Forward(2);
-            xmode--;
-            if (xmode == 0) {
-               sc.SetState(SCE_HA_DEFAULT);
-            }
+            assert(hs.nestLevel > 0);
+            if (hs.nestLevel > 0)
+               hs.nestLevel--;
+            sc.SetState(
+               hs.nestLevel == 0
+                  ? (hs.pragma ? SCE_HA_PRAGMA : SCE_HA_DEFAULT)
+                  : CommentBlockStyleFromNestLevel(hs.nestLevel - 1));
          } else {
-            if (sc.atLineEnd) {
-                // Remember the line state for future incremental lexing
-                styler.SetLineState(lineCurrent, (xmode << 4) | mode);
-                lineCurrent++;
-            }
             sc.Forward();
          }
       }
             // Pragma
       else if (sc.state == SCE_HA_PRAGMA) {
          if (sc.Match("#-}")) {
+            hs.pragma = false;
             sc.Forward(3);
             sc.SetState(SCE_HA_DEFAULT);
-         } else {
-            sc.Forward();
-         }
-      }
-            // Preprocessor
-      else if (sc.state == SCE_HA_PREPROCESSOR) {
-         if (stylingWithinPreprocessor && !IsAWordStart(sc.ch)) {
-            sc.SetState(SCE_HA_DEFAULT);
-         } else if (sc.ch == '\\' && !stylingWithinPreprocessor) {
+         } else if (sc.Match('-','-')) {
+            sc.SetState(SCE_HA_COMMENTLINE);
             sc.Forward(2);
-         } else if (sc.atLineEnd) {
-            sc.SetState(SCE_HA_DEFAULT);
+            inDashes = false;
+         } else if (sc.Match('{','-')) {
+            sc.SetState(CommentBlockStyleFromNestLevel(hs.nestLevel));
+            sc.Forward(2);
+            hs.nestLevel = 1;
          } else {
             sc.Forward();
          }
       }
-      // New state?
-      if (sc.state == SCE_HA_DEFAULT) {
+            // New state?
+      else if (sc.state == SCE_HA_DEFAULT) {
          // Digit
          if (IsADigit(sc.ch)) {
+            hs.mode = HA_MODE_DEFAULT;
+
             sc.SetState(SCE_HA_NUMBER);
             if (sc.ch == '0' && (sc.chNext == 'X' || sc.chNext == 'x')) {
-                // Match anything starting with "0x" or "0X", too
-                sc.Forward(2);
-                xmode = 16;
+               // Match anything starting with "0x" or "0X", too
+               sc.Forward(2);
+               base = 16;
+               dot = false;
             } else if (sc.ch == '0' && (sc.chNext == 'O' || sc.chNext == 'o')) {
-                // Match anything starting with "0x" or "0X", too
-                sc.Forward(2);
-                xmode = 8;
+               // Match anything starting with "0o" or "0O", too
+               sc.Forward(2);
+               base = 8;
+               dot = false;
             } else {
-                sc.Forward();
-                xmode = 10;
+               sc.Forward();
+               base = 10;
+               dot = true;
             }
-            mode = HA_MODE_DEFAULT;
          }
          // Pragma
          else if (sc.Match("{-#")) {
+            hs.pragma = true;
             sc.SetState(SCE_HA_PRAGMA);
             sc.Forward(3);
          }
@@ -323,33 +877,65 @@ static void ColorizeHaskellDoc(unsigned int startPos, int length, int initStyle,
          else if (sc.Match('-','-')) {
             sc.SetState(SCE_HA_COMMENTLINE);
             sc.Forward(2);
-            xmode = 1;
+            inDashes = true;
          }
          // Comment block
          else if (sc.Match('{','-')) {
-            sc.SetState(SCE_HA_COMMENTBLOCK);
+            sc.SetState(CommentBlockStyleFromNestLevel(hs.nestLevel));
             sc.Forward(2);
-            xmode = 1;
+            hs.nestLevel = 1;
          }
          // String
-         else if (sc.Match('\"')) {
+         else if (sc.ch == '\"') {
             sc.SetState(SCE_HA_STRING);
             sc.Forward();
          }
-         // Character
-         else if (sc.Match('\'')) {
+         // Character or quoted name or promoted term
+         else if (sc.ch == '\'') {
+            hs.mode = HA_MODE_DEFAULT;
+
             sc.SetState(SCE_HA_CHARACTER);
             sc.Forward();
+
+            if (options.allowQuotes) {
+               // Quoted type ''T
+               if (sc.ch=='\'' && IsAHaskellWordStart(sc.chNext)) {
+                  sc.Forward();
+                  sc.ChangeState(SCE_HA_IDENTIFIER);
+               } else if (sc.chNext != '\'') {
+                  // Quoted name 'n or promoted constructor 'N
+                  if (IsAHaskellWordStart(sc.ch)) {
+                     sc.ChangeState(SCE_HA_IDENTIFIER);
+                  // Promoted constructor operator ':~>
+                  } else if (sc.ch == ':') {
+                     alreadyInTheMiddleOfOperator = false;
+                     sc.ChangeState(SCE_HA_OPERATOR);
+                  // Promoted list or tuple '[T]
+                  } else if (sc.ch == '[' || sc.ch== '(') {
+                     sc.ChangeState(SCE_HA_OPERATOR);
+                     sc.ForwardSetState(SCE_HA_DEFAULT);
+                  }
+               }
+            }
          }
-         // Preprocessor
-         else if (sc.atLineStart && sc.ch == '#') {
-            mode = HA_MODE_DEFAULT;
-            sc.SetState(SCE_HA_PREPROCESSOR);
-            sc.Forward();
+         // Operator starting with '?' or an implicit parameter
+         else if (sc.ch == '?') {
+            hs.mode = HA_MODE_DEFAULT;
+
+            alreadyInTheMiddleOfOperator = false;
+            sc.SetState(SCE_HA_OPERATOR);
+
+            if (  options.implicitParams
+               && IsAHaskellWordStart(sc.chNext)
+               && !IsHaskellUpperCase(sc.chNext)) {
+               sc.Forward();
+               sc.ChangeState(SCE_HA_IDENTIFIER);
+            }
          }
          // Operator
-         else if (IsAnOperatorChar(sc.ch)) {
-            mode = HA_MODE_DEFAULT;
+         else if (IsAnHaskellOperatorChar(sc.ch)) {
+            hs.mode = HA_MODE_DEFAULT;
+
             sc.SetState(SCE_HA_OPERATOR);
          }
          // Braces and punctuation
@@ -358,78 +944,171 @@ static void ColorizeHaskellDoc(unsigned int startPos, int length, int initStyle,
                || sc.ch == '[' || sc.ch == ']'
                || sc.ch == '{' || sc.ch == '}') {
             sc.SetState(SCE_HA_OPERATOR);
-            sc.Forward();
-            sc.SetState(SCE_HA_DEFAULT);
+            sc.ForwardSetState(SCE_HA_DEFAULT);
          }
          // Keyword or Identifier
-         else if (IsAWordStart(sc.ch)) {
-            xmode = isupper(sc.ch) ? SCE_HA_CAPITAL : SCE_HA_IDENTIFIER;
+         else if (IsAHaskellWordStart(sc.ch)) {
             sc.SetState(SCE_HA_IDENTIFIER);
-            sc.Forward();
+         // Something we don't care about
          } else {
-            if (sc.atLineEnd) {
-                // Remember the line state for future incremental lexing
-                styler.SetLineState(lineCurrent, (xmode << 4) | mode);
-                lineCurrent++;
-            }
             sc.Forward();
          }
       }
+            // This branch should never be reached.
+      else {
+         assert(false);
+         sc.Forward();
+      }
    }
+   styler.SetLineState(lineCurrent, hs.ToLineState());
    sc.Complete();
 }
 
-// External stuff - used for dynamic-loading, not implemented in wxStyledTextCtrl yet.
-// Inspired by the caml external lexer - Credits to Robert Roessler - http://www.rftp.com
-#ifdef BUILD_EXTERNAL_LEXER
-static const char* LexerName = "haskell";
-
-void EXT_LEXER_DECL Lex(unsigned int lexer, unsigned int startPos, int length, int initStyle,
-                        char *words[], WindowID window, char *props)
-{
-   PropSetSimple ps;
-   ps.SetMultiple(props);
-   WindowAccessor wa(window, ps);
-
-   int nWL = 0;
-   for (; words[nWL]; nWL++) ;
-   WordList** wl = new WordList* [nWL + 1];
-   int i = 0;
-   for (; i<nWL; i++)
-   {
-      wl[i] = new WordList();
-      wl[i]->Set(words[i]);
+void SCI_METHOD LexerHaskell::Fold(unsigned int startPos, int length, int // initStyle
+                                  ,IDocument *pAccess) {
+   if (!options.fold)
+      return;
+
+   Accessor styler(pAccess, NULL);
+
+   int lineCurrent = styler.GetLine(startPos);
+
+   if (lineCurrent <= firstImportLine) {
+      firstImportLine = -1; // readjust first import position
+      firstImportIndent = 0;
    }
-   wl[i] = 0;
 
-   ColorizeHaskellDoc(startPos, length, initStyle, wl, wa);
-   wa.Flush();
-   for (i=nWL-1;i>=0;i--)
-      delete wl[i];
-   delete [] wl;
-}
+   const int maxPos = startPos + length;
+   const int maxLines =
+      maxPos == styler.Length()
+         ? styler.GetLine(maxPos)
+         : styler.GetLine(maxPos - 1);  // Requested last line
+   const int docLines = styler.GetLine(styler.Length()); // Available last line
 
-void EXT_LEXER_DECL Fold (unsigned int lexer, unsigned int startPos, int length, int initStyle,
-                        char *words[], WindowID window, char *props)
-{
+   // Backtrack to previous non-blank line so we can determine indent level
+   // for any white space lines
+   // and so we can fix any preceding fold level (which is why we go back
+   // at least one line in all cases)
+   bool importHere = LineContainsImport(lineCurrent, styler);
+   int indentCurrent = IndentAmountWithOffset(styler, lineCurrent);
 
-}
+   while (lineCurrent > 0) {
+      lineCurrent--;
+      importHere = LineContainsImport(lineCurrent, styler);
+      indentCurrent = IndentAmountWithOffset(styler, lineCurrent);
+      if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG))
+         break;
+   }
 
-int EXT_LEXER_DECL GetLexerCount()
-{
-   return 1;
-}
+   int indentCurrentLevel = indentCurrent & SC_FOLDLEVELNUMBERMASK;
 
-void EXT_LEXER_DECL GetLexerName(unsigned int Index, char *name, int buflength)
-{
-   if (buflength > 0) {
-      buflength--;
-      int n = strlen(LexerName);
-      if (n > buflength)
-         n = buflength;
-      memcpy(name, LexerName, n), name[n] = '\0';
+   if (importHere) {
+      indentCurrentLevel = IndentLevelRemoveIndentOffset(indentCurrentLevel);
+      if (firstImportLine == -1) {
+         firstImportLine = lineCurrent;
+         firstImportIndent = (1 + indentCurrentLevel) - SC_FOLDLEVELBASE;
+      }
+      if (firstImportLine != lineCurrent) {
+         indentCurrentLevel++;
+      }
    }
+
+   indentCurrent = indentCurrentLevel | (indentCurrent & ~SC_FOLDLEVELNUMBERMASK);
+
+   // Process all characters to end of requested range
+   //that hangs over the end of the range.  Cap processing in all cases
+   // to end of document.
+   while (lineCurrent <= docLines && lineCurrent <= maxLines) {
+
+      // Gather info
+      int lineNext = lineCurrent + 1;
+      importHere = false;
+      int indentNext = indentCurrent;
+
+      if (lineNext <= docLines) {
+         // Information about next line is only available if not at end of document
+         importHere = LineContainsImport(lineNext, styler);
+         indentNext = IndentAmountWithOffset(styler, lineNext);
+      }
+      if (indentNext & SC_FOLDLEVELWHITEFLAG)
+         indentNext = SC_FOLDLEVELWHITEFLAG | indentCurrentLevel;
+
+      // Skip past any blank lines for next indent level info; we skip also
+      // comments (all comments, not just those starting in column 0)
+      // which effectively folds them into surrounding code rather
+      // than screwing up folding.
+
+      while (lineNext < docLines && (indentNext & SC_FOLDLEVELWHITEFLAG)) {
+         lineNext++;
+         importHere = LineContainsImport(lineNext, styler);
+         indentNext = IndentAmountWithOffset(styler, lineNext);
+      }
+
+      int indentNextLevel = indentNext & SC_FOLDLEVELNUMBERMASK;
+
+      if (importHere) {
+         indentNextLevel = IndentLevelRemoveIndentOffset(indentNextLevel);
+         if (firstImportLine == -1) {
+            firstImportLine = lineNext;
+            firstImportIndent = (1 + indentNextLevel) - SC_FOLDLEVELBASE;
+         }
+         if (firstImportLine != lineNext) {
+            indentNextLevel++;
+         }
+      }
+
+      indentNext = indentNextLevel | (indentNext & ~SC_FOLDLEVELNUMBERMASK);
+
+      const int levelBeforeComments = Maximum(indentCurrentLevel,indentNextLevel);
+
+      // Now set all the indent levels on the lines we skipped
+      // Do this from end to start.  Once we encounter one line
+      // which is indented more than the line after the end of
+      // the comment-block, use the level of the block before
+
+      int skipLine = lineNext;
+      int skipLevel = indentNextLevel;
+
+      while (--skipLine > lineCurrent) {
+         int skipLineIndent = IndentAmountWithOffset(styler, skipLine);
+
+         if (options.foldCompact) {
+            if ((skipLineIndent & SC_FOLDLEVELNUMBERMASK) > indentNextLevel) {
+               skipLevel = levelBeforeComments;
+            }
+
+            int whiteFlag = skipLineIndent & SC_FOLDLEVELWHITEFLAG;
+
+            styler.SetLevel(skipLine, skipLevel | whiteFlag);
+         } else {
+            if (  (skipLineIndent & SC_FOLDLEVELNUMBERMASK) > indentNextLevel
+               && !(skipLineIndent & SC_FOLDLEVELWHITEFLAG)) {
+               skipLevel = levelBeforeComments;
+            }
+
+            styler.SetLevel(skipLine, skipLevel);
+         }
+      }
+
+      int lev = indentCurrent;
+
+      if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) {
+         if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext & SC_FOLDLEVELNUMBERMASK))
+            lev |= SC_FOLDLEVELHEADERFLAG;
+      }
+
+      // Set fold level for this line and move to next line
+      styler.SetLevel(lineCurrent, options.foldCompact ? lev : lev & ~SC_FOLDLEVELWHITEFLAG);
+
+      indentCurrent = indentNext;
+      indentCurrentLevel = indentNextLevel;
+      lineCurrent = lineNext;
+   }
+
+   // NOTE: Cannot set level of last line here because indentCurrent doesn't have
+   // header flag set; the loop above is crafted to take care of this case!
+   //styler.SetLevel(lineCurrent, indentCurrent);
 }
-#endif
 
-LexerModule lmHaskell(SCLEX_HASKELL, ColorizeHaskellDoc, "haskell");
+LexerModule lmHaskell(SCLEX_HASKELL, LexerHaskell::LexerFactoryHaskell, "haskell", haskellWordListDesc);
+LexerModule lmLiterateHaskell(SCLEX_LITERATEHASKELL, LexerHaskell::LexerFactoryLiterateHaskell, "literatehaskell", haskellWordListDesc);


Modified: scintilla/lexers/LexLaTeX.cxx
6 files changed, 3 insertions(+), 3 deletions(-)
===================================================================
@@ -224,7 +224,7 @@ void SCI_METHOD LexerLaTeX::Lex(unsigned int startPos, int length, int initStyle
 					chNext = styler.SafeGetCharAt(i + 1);
 				} else if (chNext == '\r' || chNext == '\n') {
 					styler.ColourTo(i, SCE_L_ERROR);
-				} else {
+				} else if (isascii(chNext)) {
 					styler.ColourTo(i + 1, SCE_L_SHORTCMD);
 					if (chNext == '(') {
 						mode = 1;
@@ -340,7 +340,7 @@ void SCI_METHOD LexerLaTeX::Lex(unsigned int startPos, int length, int initStyle
 					chNext = styler.SafeGetCharAt(i + 1);
 				} else if (chNext == '\r' || chNext == '\n') {
 					styler.ColourTo(i, SCE_L_ERROR);
-				} else {
+				} else if (isascii(chNext)) {
 					if (chNext == ')') {
 						mode = 0;
 						state = SCE_L_DEFAULT;
@@ -382,7 +382,7 @@ void SCI_METHOD LexerLaTeX::Lex(unsigned int startPos, int length, int initStyle
 					chNext = styler.SafeGetCharAt(i + 1);
 				} else if (chNext == '\r' || chNext == '\n') {
 					styler.ColourTo(i, SCE_L_ERROR);
-				} else {
+				} else if (isascii(chNext)) {
 					if (chNext == ']') {
 						mode = 0;
 						state = SCE_L_DEFAULT;


Modified: scintilla/lexers/LexOthers.cxx
4 files changed, 2 insertions(+), 2 deletions(-)
===================================================================
@@ -1047,10 +1047,10 @@ static int RecogniseErrorListLine(const char *lineBuffer, unsigned int lengthLin
 				}
 			} else if (state == stCtagsStart) {
 				if ((lineBuffer[i - 1] == '\t') &&
-				        ((ch == '/' && lineBuffer[i + 1] == '^') || Is0To9(ch))) {
+				        ((ch == '/' && chNext == '^') || Is0To9(ch))) {
 					state = stCtags;
 					break;
-				} else if ((ch == '/') && (lineBuffer[i + 1] == '^')) {
+				} else if ((ch == '/') && (chNext == '^')) {
 					state = stCtagsStartString;
 				}
 			} else if ((state == stCtagsStartString) && ((lineBuffer[i] == '$') && (lineBuffer[i + 1] == '/'))) {


Modified: scintilla/lexlib/LexerModule.cxx
2 files changed, 1 insertions(+), 1 deletions(-)
===================================================================
@@ -75,7 +75,7 @@ int LexerModule::GetNumWordLists() const {
 
 const char *LexerModule::GetWordListDescription(int index) const {
 	assert(index < GetNumWordLists());
-	if (index >= GetNumWordLists()) {
+	if (!wordListDescriptions || (index >= GetNumWordLists())) {
 		return "";
 	} else {
 		return wordListDescriptions[index];


Modified: scintilla/lexlib/PropSetSimple.cxx
23 files changed, 7 insertions(+), 16 deletions(-)
===================================================================
@@ -141,30 +141,21 @@ static int ExpandAllInPlace(const PropSetSimple &props, std::string &withVars, i
 	return maxExpands;
 }
 
-char *PropSetSimple::Expanded(const char *key) const {
+int PropSetSimple::GetExpanded(const char *key, char *result) const {
 	std::string val = Get(key);
 	ExpandAllInPlace(*this, val, 100, VarChain(key));
-	char *ret = new char [val.size() + 1];
-	strcpy(ret, val.c_str());
-	return ret;
-}
-
-int PropSetSimple::GetExpanded(const char *key, char *result) const {
-	char *val = Expanded(key);
-	const int n = static_cast<int>(strlen(val));
+	const int n = static_cast<int>(val.size());
 	if (result) {
-		strcpy(result, val);
+		strcpy(result, val.c_str());
 	}
-	delete []val;
 	return n;	// Not including NUL
 }
 
 int PropSetSimple::GetInt(const char *key, int defaultValue) const {
-	char *val = Expanded(key);
-	if (val) {
-		int retVal = val[0] ? atoi(val) : defaultValue;
-		delete []val;
-		return retVal;
+	std::string val = Get(key);
+	ExpandAllInPlace(*this, val, 100, VarChain(key));
+	if (!val.empty()) {
+		return atoi(val.c_str());
 	}
 	return defaultValue;
 }


Modified: scintilla/lexlib/PropSetSimple.h
1 files changed, 0 insertions(+), 1 deletions(-)
===================================================================
@@ -21,7 +21,6 @@ class PropSetSimple {
 	void Set(const char *key, const char *val, int lenKey=-1, int lenVal=-1);
 	void SetMultiple(const char *);
 	const char *Get(const char *key) const;
-	char *Expanded(const char *key) const;
 	int GetExpanded(const char *key, char *result) const;
 	int GetInt(const char *key, int defaultValue=0) const;
 };


Modified: scintilla/lexlib/StyleContext.h
4 files changed, 3 insertions(+), 1 deletions(-)
===================================================================
@@ -76,7 +76,7 @@ class StyleContext {
 		// End of line?
 		// Trigger on CR only (Mac style) or either on LF from CR+LF (Dos/Win)
 		// or on LF alone (Unix). Avoid triggering two times on Dos/Win.
-		if (lineStartNext < styler.Length())
+		if (currentLine < lineDocEnd)
 			atLineEnd = static_cast<int>(pos) >= (lineStartNext-1);
 		else // Last line
 			atLineEnd = static_cast<int>(pos) >= lineStartNext;
@@ -85,6 +85,7 @@ class StyleContext {
 public:
 	unsigned int currentPos;
 	int currentLine;
+	int lineDocEnd;
 	int lineStartNext;
 	bool atLineStart;
 	bool atLineEnd;
@@ -112,6 +113,7 @@ class StyleContext {
 		lengthDocument = static_cast<unsigned int>(styler.Length());
 		if (endPos == lengthDocument)
 			endPos++;
+		lineDocEnd = styler.GetLine(lengthDocument);
 		atLineStart = static_cast<unsigned int>(styler.LineStart(currentLine)) == startPos;
 		unsigned int pos = currentPos;
 		ch = static_cast<unsigned char>(styler.SafeGetCharAt(pos, 0));


Modified: scintilla/lexlib/WordList.cxx
51 files changed, 34 insertions(+), 17 deletions(-)
===================================================================
@@ -45,29 +45,37 @@ static char **ArrayFromWordList(char *wordlist, int *len, bool onlyLineEnds = fa
 		prev = curr;
 	}
 	char **keywords = new char *[words + 1];
-	if (keywords) {
-		words = 0;
-		prev = '\0';
-		size_t slen = strlen(wordlist);
-		for (size_t k = 0; k < slen; k++) {
-			if (!wordSeparator[static_cast<unsigned char>(wordlist[k])]) {
-				if (!prev) {
-					keywords[words] = &wordlist[k];
-					words++;
-				}
-			} else {
-				wordlist[k] = '\0';
+	words = 0;
+	prev = '\0';
+	size_t slen = strlen(wordlist);
+	for (size_t k = 0; k < slen; k++) {
+		if (!wordSeparator[static_cast<unsigned char>(wordlist[k])]) {
+			if (!prev) {
+				keywords[words] = &wordlist[k];
+				words++;
 			}
-			prev = wordlist[k];
+		} else {
+			wordlist[k] = '\0';
 		}
-		keywords[words] = &wordlist[slen];
-		*len = words;
-	} else {
-		*len = 0;
+		prev = wordlist[k];
 	}
+	keywords[words] = &wordlist[slen];
+	*len = words;
 	return keywords;
 }
 
+WordList::WordList(bool onlyLineEnds_) :
+	words(0), list(0), len(0), onlyLineEnds(onlyLineEnds_) {
+}
+
+WordList::~WordList() { 
+	Clear();
+}
+
+WordList::operator bool() const {
+	return len ? true : false;
+}
+
 bool WordList::operator!=(const WordList &other) const {
 	if (len != other.len)
 		return true;
@@ -78,6 +86,10 @@ bool WordList::operator!=(const WordList &other) const {
 	return false;
 }
 
+int WordList::Length() const {
+	return len;
+}
+
 void WordList::Clear() {
 	if (words) {
 		delete []list;
@@ -217,3 +229,8 @@ bool WordList::InListAbbreviated(const char *s, const char marker) const {
 	}
 	return false;
 }
+
+const char *WordList::WordAt(int n) const {
+	return words[n];
+}
+


Modified: scintilla/lexlib/WordList.h
12 files changed, 6 insertions(+), 6 deletions(-)
===================================================================
@@ -15,23 +15,23 @@
 /**
  */
 class WordList {
-public:
 	// Each word contains at least one character - a empty word acts as sentinel at the end.
 	char **words;
 	char *list;
 	int len;
 	bool onlyLineEnds;	///< Delimited by any white space or only line ends
 	int starts[256];
-	WordList(bool onlyLineEnds_ = false) :
-		words(0), list(0), len(0), onlyLineEnds(onlyLineEnds_)
-		{}
-	~WordList() { Clear(); }
-	operator bool() const { return len ? true : false; }
+public:
+	WordList(bool onlyLineEnds_ = false);
+	~WordList();
+	operator bool() const;
 	bool operator!=(const WordList &other) const;
+	int Length() const;
 	void Clear();
 	void Set(const char *s);
 	bool InList(const char *s) const;
 	bool InListAbbreviated(const char *s, const char marker) const;
+	const char *WordAt(int n) const;
 };
 
 #ifdef SCI_NAMESPACE


Modified: scintilla/scintilla_changes.patch
3 files changed, 2 insertions(+), 1 deletions(-)
===================================================================
@@ -31,7 +31,7 @@ diff --git b/scintilla/src/Catalogue.cxx a/scintilla/src/Catalogue.cxx
 index 2f75247..a34f834 100644
 +++ scintilla/src/Catalogue.cxx
 --- scintilla/src/Catalogue.cxx
-@@ -81,108 +81,45 @@ int Scintilla_LinkLexers() {
+@@ -81,109 +81,45 @@ int Scintilla_LinkLexers() {
  
  //++Autogenerated -- run src/LexGen.py to regenerate
  //**\(\tLINK_LEXER(\*);\n\)
@@ -82,6 +82,7 @@ index 2f75247..a34f834 100644
 -	LINK_LEXER(lmKix);
  	LINK_LEXER(lmLatex);
  	LINK_LEXER(lmLISP);
+-	LINK_LEXER(lmLiterateHaskell);
 -	LINK_LEXER(lmLot);
 -	LINK_LEXER(lmLout);
  	LINK_LEXER(lmLua);


Modified: scintilla/src/CallTip.cxx
22 files changed, 9 insertions(+), 13 deletions(-)
===================================================================
@@ -7,12 +7,14 @@
 
 #include <stdlib.h>
 #include <string.h>
+#include <stdio.h>
+
+#include <string>
 
 #include "Platform.h"
 
 #include "Scintilla.h"
 #include "CallTip.h"
-#include <stdio.h>
 
 #ifdef SCI_NAMESPACE
 using namespace Scintilla;
@@ -22,7 +24,6 @@
 	wCallTip = 0;
 	inCallTipMode = false;
 	posStartCallTip = 0;
-	val = 0;
 	rectUp = PRectangle(0,0,0,0);
 	rectDown = PRectangle(0,0,0,0);
 	lineHeight = 1;
@@ -56,8 +57,6 @@
 CallTip::~CallTip() {
 	font.Release();
 	wCallTip.Destroy();
-	delete []val;
-	val = 0;
 }
 
 // Although this test includes 0, we should never see a \0 character.
@@ -176,17 +175,17 @@ int CallTip::PaintContents(Surface *surfaceWindow, bool draw) {
 	// Draw the definition in three parts: before highlight, highlighted, after highlight
 	int ytext = rcClient.top + ascent + 1;
 	rcClient.bottom = ytext + surfaceWindow->Descent(font) + 1;
-	char *chunkVal = val;
+	const char *chunkVal = val.c_str();
 	bool moreChunks = true;
 	int maxWidth = 0;
 
 	while (moreChunks) {
-		char *chunkEnd = strchr(chunkVal, '\n');
+		const char *chunkEnd = strchr(chunkVal, '\n');
 		if (chunkEnd == NULL) {
 			chunkEnd = chunkVal + strlen(chunkVal);
 			moreChunks = false;
 		}
-		int chunkOffset = chunkVal - val;
+		int chunkOffset = chunkVal - val.c_str();
 		int chunkLength = chunkEnd - chunkVal;
 		int chunkEndOffset = chunkOffset + chunkLength;
 		int thisStartHighlight = Platform::Maximum(startHighlight, chunkOffset);
@@ -215,7 +214,7 @@ int CallTip::PaintContents(Surface *surfaceWindow, bool draw) {
 }
 
 void CallTip::PaintCT(Surface *surfaceWindow) {
-	if (!val)
+	if (val.empty())
 		return;
 	PRectangle rcClientPos = wCallTip.GetClientPosition();
 	PRectangle rcClientSize(0, 0, rcClientPos.right - rcClientPos.left,
@@ -253,10 +252,7 @@ PRectangle CallTip::CallTipStart(int pos, Point pt, int textHeight, const char *
                                  int codePage_, int characterSet,
 								 int technology, Window &wParent) {
 	clickPlace = 0;
-	delete []val;
-	val = 0;
-	val = new char[strlen(defn) + 1];
-	strcpy(val, defn);
+	val = defn;
 	codePage = codePage_;
 	Surface *surfaceMeasure = Surface::Allocate(technology);
 	if (!surfaceMeasure)
@@ -275,7 +271,7 @@ PRectangle CallTip::CallTipStart(int pos, Point pt, int textHeight, const char *
 	// Only support \n here - simply means container must avoid \r!
 	int numLines = 1;
 	const char *newline;
-	const char *look = val;
+	const char *look = val.c_str();
 	rectUp = PRectangle(0,0,0,0);
 	rectDown = PRectangle(0,0,0,0);
 	offsetMain = insetX;            // changed to right edge of any arrows


Modified: scintilla/src/CallTip.h
2 files changed, 1 insertions(+), 1 deletions(-)
===================================================================
@@ -17,7 +17,7 @@
 class CallTip {
 	int startHighlight;    // character offset to start and...
 	int endHighlight;      // ...end of highlighted text
-	char *val;
+	std::string val;
 	Font font;
 	PRectangle rectUp;      // rectangle of last up angle in the tip
 	PRectangle rectDown;    // rectangle of last down arrow in the tip


Modified: scintilla/src/CellBuffer.cxx
24 files changed, 12 insertions(+), 12 deletions(-)
===================================================================
@@ -10,6 +10,8 @@
 #include <stdlib.h>
 #include <stdarg.h>
 
+#include <algorithm>
+
 #include "Platform.h"
 
 #include "Scintilla.h"
@@ -81,11 +83,15 @@ int LineVector::LineFromPosition(int pos) const {
 	Destroy();
 }
 
-void Action::Create(actionType at_, int position_, char *data_, int lenData_, bool mayCoalesce_) {
+void Action::Create(actionType at_, int position_, const char *data_, int lenData_, bool mayCoalesce_) {
 	delete []data;
+	data = NULL;
 	position = position_;
 	at = at_;
-	data = data_;
+	if (lenData_) {
+		data = new char[lenData_];
+		memcpy(data, data_, lenData_);
+	}
 	lenData = lenData_;
 	mayCoalesce = mayCoalesce_;
 }
@@ -162,7 +168,7 @@ void UndoHistory::EnsureUndoRoom() {
 	}
 }
 
-void UndoHistory::AppendAction(actionType at, int position, char *data, int lengthData,
+void UndoHistory::AppendAction(actionType at, int position, const char *data, int lengthData,
 	bool &startSequence, bool mayCoalesce) {
 	EnsureUndoRoom();
 	//Platform::DebugPrintf("%% %d action %d %d %d\n", at, position, lengthData, currentAction);
@@ -393,11 +399,7 @@ const char *CellBuffer::InsertString(int position, const char *s, int insertLeng
 		if (collectingUndo) {
 			// Save into the undo/redo stack, but only the characters - not the formatting
 			// This takes up about half load time
-			data = new char[insertLength];
-			for (int i = 0; i < insertLength; i++) {
-				data[i] = s[i];
-			}
-			uh.AppendAction(insertAction, position, data, insertLength, startSequence);
+			uh.AppendAction(insertAction, position, s, insertLength, startSequence);
 		}
 
 		BasicInsertString(position, s, insertLength);
@@ -439,10 +441,8 @@ const char *CellBuffer::DeleteChars(int position, int deleteLength, bool &startS
 	if (!readOnly) {
 		if (collectingUndo) {
 			// Save into the undo/redo stack, but only the characters - not the formatting
-			data = new char[deleteLength];
-			for (int i = 0; i < deleteLength; i++) {
-				data[i] = substance.ValueAt(position + i);
-			}
+			// The gap would be moved to position anyway for the deletion so this doesn't cost extra
+			const char *data = substance.RangePointer(position, deleteLength);
 			uh.AppendAction(removeAction, position, data, deleteLength, startSequence);
 		}
 


Modified: scintilla/src/CellBuffer.h
4 files changed, 2 insertions(+), 2 deletions(-)
===================================================================
@@ -80,7 +80,7 @@ class Action {
 
 	Action();
 	~Action();
-	void Create(actionType at_, int position_=0, char *data_=0, int lenData_=0, bool mayCoalesce_=true);
+	void Create(actionType at_, int position_=0, const char *data_=0, int lenData_=0, bool mayCoalesce_=true);
 	void Destroy();
 	void Grab(Action *source);
 };
@@ -105,7 +105,7 @@ class UndoHistory {
 	UndoHistory();
 	~UndoHistory();
 
-	void AppendAction(actionType at, int position, char *data, int length, bool &startSequence, bool mayCoalesce=true);
+	void AppendAction(actionType at, int position, const char *data, int length, bool &startSequence, bool mayCoalesce=true);
 
 	void BeginUndoAction();
 	void EndUndoAction();


Modified: scintilla/src/ContractionState.cxx
2 files changed, 2 insertions(+), 0 deletions(-)
===================================================================
@@ -7,6 +7,8 @@
 
 #include <string.h>
 
+#include <algorithm>
+
 #include "Platform.h"
 
 #include "SplitVector.h"


Modified: scintilla/src/Decoration.cxx
2 files changed, 2 insertions(+), 0 deletions(-)
===================================================================
@@ -9,6 +9,8 @@
 #include <stdlib.h>
 #include <stdarg.h>
 
+#include <algorithm>
+
 #include "Platform.h"
 
 #include "Scintilla.h"


Modified: scintilla/src/Document.cxx
228 files changed, 66 insertions(+), 162 deletions(-)
===================================================================
@@ -13,6 +13,7 @@
 
 #include <string>
 #include <vector>
+#include <algorithm>
 
 #include "Platform.h"
 
@@ -102,8 +103,6 @@ int LexInterface::LineEndTypesSupported() {
 	useTabs = true;
 	tabIndents = true;
 	backspaceUnindents = false;
-	watchers = 0;
-	lenWatchers = 0;
 
 	matchesValid = false;
 	regex = 0;
@@ -122,16 +121,13 @@ int LexInterface::LineEndTypesSupported() {
 }
 
 Document::~Document() {
-	for (int i = 0; i < lenWatchers; i++) {
-		watchers[i].watcher->NotifyDeleted(this, watchers[i].userData);
+	for (std::vector<WatcherWithUserData>::iterator it = watchers.begin(); it != watchers.end(); ++it) {
+		it->watcher->NotifyDeleted(this, it->userData);
 	}
-	delete []watchers;
 	for (int j=0; j<ldSize; j++) {
 		delete perLineData[j];
 		perLineData[j] = 0;
 	}
-	watchers = 0;
-	lenWatchers = 0;
 	delete regex;
 	regex = 0;
 	delete pli;
@@ -309,9 +305,9 @@ int SCI_METHOD Document::LineEnd(int line) const {
 }
 
 void SCI_METHOD Document::SetErrorStatus(int status) {
-	// Tell the watchers the lexer has changed.
-	for (int i = 0; i < lenWatchers; i++) {
-		watchers[i].watcher->NotifyErrorOccurred(this, watchers[i].userData, status);
+	// Tell the watchers an error has occurred.
+	for (std::vector<WatcherWithUserData>::iterator it = watchers.begin(); it != watchers.end(); ++it) {
+		it->watcher->NotifyErrorOccurred(this, it->userData, status);
 	}
 }
 
@@ -420,7 +416,7 @@ void Document::GetHighlightDelimiters(HighlightDelimiter &highlightDelimiter, in
 	int lookLine = line;
 	int lookLineLevel = level;
 	int lookLineLevelNum = lookLineLevel & SC_FOLDLEVELNUMBERMASK;
-	while ((lookLine > 0) && ((lookLineLevel & SC_FOLDLEVELWHITEFLAG) || 
+	while ((lookLine > 0) && ((lookLineLevel & SC_FOLDLEVELWHITEFLAG) ||
 		((lookLineLevel & SC_FOLDLEVELHEADERFLAG) && (lookLineLevelNum >= (GetLevel(lookLine + 1) & SC_FOLDLEVELNUMBERMASK))))) {
 		lookLineLevel = GetLevel(--lookLine);
 		lookLineLevelNum = lookLineLevel & SC_FOLDLEVELNUMBERMASK;
@@ -453,8 +449,8 @@ void Document::GetHighlightDelimiters(HighlightDelimiter &highlightDelimiter, in
 		}
 	}
 	if (firstChangeableLineBefore == -1) {
-		for (lookLine = line - 1, lookLineLevel = GetLevel(lookLine), lookLineLevelNum = lookLineLevel & SC_FOLDLEVELNUMBERMASK; 
-			lookLine >= beginFoldBlock; 
+		for (lookLine = line - 1, lookLineLevel = GetLevel(lookLine), lookLineLevelNum = lookLineLevel & SC_FOLDLEVELNUMBERMASK;
+			lookLine >= beginFoldBlock;
 			lookLineLevel = GetLevel(--lookLine), lookLineLevelNum = lookLineLevel & SC_FOLDLEVELNUMBERMASK) {
 			if ((lookLineLevel & SC_FOLDLEVELWHITEFLAG) || (lookLineLevelNum > (level & SC_FOLDLEVELNUMBERMASK))) {
 				firstChangeableLineBefore = lookLine;
@@ -466,8 +462,8 @@ void Document::GetHighlightDelimiters(HighlightDelimiter &highlightDelimiter, in
 		firstChangeableLineBefore = beginFoldBlock - 1;
 
 	int firstChangeableLineAfter = -1;
-	for (lookLine = line + 1, lookLineLevel = GetLevel(lookLine), lookLineLevelNum = lookLineLevel & SC_FOLDLEVELNUMBERMASK; 
-		lookLine <= endFoldBlock; 
+	for (lookLine = line + 1, lookLineLevel = GetLevel(lookLine), lookLineLevelNum = lookLineLevel & SC_FOLDLEVELNUMBERMASK;
+		lookLine <= endFoldBlock;
 		lookLineLevel = GetLevel(++lookLine), lookLineLevelNum = lookLineLevel & SC_FOLDLEVELNUMBERMASK) {
 		if ((lookLineLevel & SC_FOLDLEVELHEADERFLAG) && (lookLineLevelNum < (GetLevel(lookLine + 1) & SC_FOLDLEVELNUMBERMASK))) {
 			firstChangeableLineAfter = lookLine;
@@ -715,7 +711,7 @@ bool SCI_METHOD Document::IsDBCSLeadByte(char ch) const {
 			// Shift_jis
 			return ((uch >= 0x81) && (uch <= 0x9F)) ||
 				((uch >= 0xE0) && (uch <= 0xFC));
-				// Lead bytes F0 to FC may be a Microsoft addition. 
+				// Lead bytes F0 to FC may be a Microsoft addition.
 		case 936:
 			// GBK
 			return (uch >= 0x81) && (uch <= 0xFE);
@@ -892,7 +888,7 @@ void * SCI_METHOD Document::ConvertToDocument() {
 int Document::Undo() {
 	int newPos = -1;
 	CheckReadOnly();
-	if (enteredModification == 0) {
+	if ((enteredModification == 0) && (cb.IsCollectingUndo())) {
 		enteredModification++;
 		if (!cb.IsReadOnly()) {
 			bool startSavePoint = cb.IsSavePoint();
@@ -977,7 +973,7 @@ int Document::Undo() {
 int Document::Redo() {
 	int newPos = -1;
 	CheckReadOnly();
-	if (enteredModification == 0) {
+	if ((enteredModification == 0) && (cb.IsCollectingUndo())) {
 		enteredModification++;
 		if (!cb.IsReadOnly()) {
 			bool startSavePoint = cb.IsSavePoint();
@@ -1050,11 +1046,6 @@ bool Document::InsertCString(int position, const char *s) {
 	return InsertString(position, s, static_cast<int>(s ? strlen(s) : 0));
 }
 
-void Document::ChangeChar(int pos, char ch) {
-	DeleteChars(pos, 1);
-	InsertChar(pos, ch);
-}
-
 void Document::DelChar(int pos) {@@ 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