Branch: refs/heads/master Author: Colomban Wendling ban@herbesfolles.org Committer: Colomban Wendling ban@herbesfolles.org Date: Wed, 22 May 2013 01:38:38 UTC Commit: 788a57f6fcf6bdb152847aedfaaf09aadc7cce43 https://github.com/geany/geany/commit/788a57f6fcf6bdb152847aedfaaf09aadc7cce...
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@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).