Update Scintilla to version 3.3.1

This commit is contained in:
Colomban Wendling 2013-04-27 16:09:29 +02:00
parent 2dd389a14a
commit e88c03d266
40 changed files with 2288 additions and 728 deletions

View File

@ -22,6 +22,7 @@ lexers/LexForth.cxx \
lexers/LexFortran.cxx \
lexers/LexHTML.cxx \
lexers/LexHaskell.cxx \
lexers/LexLaTeX.cxx \
lexers/LexLisp.cxx \
lexers/LexLua.cxx \
lexers/LexMarkdown.cxx \

View File

@ -105,9 +105,11 @@ struct LOGFONT {
static GMutex *fontMutex = NULL;
static void InitializeGLIBThreads() {
#if !GLIB_CHECK_VERSION(2,31,0)
if (!g_thread_supported()) {
g_thread_init(NULL);
}
#endif
}
#endif
@ -115,7 +117,12 @@ static void FontMutexAllocate() {
#if USE_LOCK
if (!fontMutex) {
InitializeGLIBThreads();
#if GLIB_CHECK_VERSION(2,31,0)
fontMutex = g_new(GMutex, 1);
g_mutex_init(fontMutex);
#else
fontMutex = g_mutex_new();
#endif
}
#endif
}
@ -123,7 +130,12 @@ static void FontMutexAllocate() {
static void FontMutexFree() {
#if USE_LOCK
if (fontMutex) {
#if GLIB_CHECK_VERSION(2,31,0)
g_mutex_clear(fontMutex);
g_free(fontMutex);
#else
g_mutex_free(fontMutex);
#endif
fontMutex = NULL;
}
#endif
@ -143,8 +155,7 @@ static void FontMutexUnlock() {
#endif
}
// On GTK+ 1.x holds a GdkFont* but on GTK+ 2.x can hold a GdkFont* or a
// PangoFontDescription*.
// Holds a PangoFontDescription*.
class FontHandle {
XYPOSITION width[128];
encodingType et;

View File

@ -296,7 +296,7 @@ private:
static gboolean TimeOut(ScintillaGTK *sciThis);
static gboolean IdleCallback(ScintillaGTK *sciThis);
static gboolean StyleIdle(ScintillaGTK *sciThis);
virtual void QueueStyling(int upTo);
virtual void QueueIdleWork(WorkNeeded::workItems items, int upTo);
static void PopUpCB(GtkMenuItem *menuItem, ScintillaGTK *sciThis);
#if GTK_CHECK_VERSION(3,0,0)
@ -1138,6 +1138,7 @@ void ScintillaGTK::ScrollText(int linesToMove) {
//Platform::DebugPrintf("ScintillaGTK::ScrollText %d %d %0d,%0d %0d,%0d\n", linesToMove, diff,
// rc.left, rc.top, rc.right, rc.bottom);
GtkWidget *wi = PWidget(wText);
NotifyUpdateUI();
if (IS_WIDGET_REALIZED(wi)) {
gdk_window_scroll(WindowFromWidget(wi), 0, -diff);
@ -2740,7 +2741,9 @@ int ScintillaGTK::TimeOut(ScintillaGTK *sciThis) {
gboolean ScintillaGTK::IdleCallback(ScintillaGTK *sciThis) {
// Idler will be automatically stopped, if there is nothing
// to do while idle.
#ifndef GDK_VERSION_3_6
gdk_threads_enter();
#endif
bool ret = sciThis->Idle();
if (ret == false) {
// FIXME: This will remove the idler from GTK, we don't want to
@ -2748,23 +2751,29 @@ gboolean ScintillaGTK::IdleCallback(ScintillaGTK *sciThis) {
// returns false (although, it should be harmless).
sciThis->SetIdle(false);
}
#ifndef GDK_VERSION_3_6
gdk_threads_leave();
#endif
return ret;
}
gboolean ScintillaGTK::StyleIdle(ScintillaGTK *sciThis) {
#ifndef GDK_VERSION_3_6
gdk_threads_enter();
sciThis->IdleStyling();
#endif
sciThis->IdleWork();
#ifndef GDK_VERSION_3_6
gdk_threads_leave();
#endif
// Idler will be automatically stopped
return FALSE;
}
void ScintillaGTK::QueueStyling(int upTo) {
Editor::QueueStyling(upTo);
if (!styleNeeded.active) {
void ScintillaGTK::QueueIdleWork(WorkNeeded::workItems items, int upTo) {
Editor::QueueIdleWork(items, upTo);
if (!workNeeded.active) {
// Only allow one style needed to be queued
styleNeeded.active = true;
workNeeded.active = true;
g_idle_add_full(G_PRIORITY_HIGH_IDLE,
reinterpret_cast<GSourceFunc>(StyleIdle), this, NULL);
}

View File

@ -18,7 +18,7 @@ namespace Scintilla {
#define SCI_METHOD
#endif
enum { dvOriginal=0 };
enum { dvOriginal=0, dvLineEnd=1 };
class IDocument {
public:
@ -45,7 +45,12 @@ public:
virtual int SCI_METHOD GetLineIndentation(int line) = 0;
};
enum { lvOriginal=0 };
class IDocumentWithLineEnd : public IDocument {
public:
virtual int SCI_METHOD LineEnd(int line) const = 0;
};
enum { lvOriginal=0, lvSubStyles=1 };
class ILexer {
public:
@ -62,6 +67,18 @@ public:
virtual void * SCI_METHOD PrivateCall(int operation, void *pointer) = 0;
};
class ILexerWithSubStyles : public ILexer {
public:
virtual int SCI_METHOD LineEndTypesSupported() = 0;
virtual int SCI_METHOD AllocateSubStyles(int styleBase, int numberStyles) = 0;
virtual int SCI_METHOD SubStylesStart(int styleBase) = 0;
virtual int SCI_METHOD SubStylesLength(int styleBase) = 0;
virtual void SCI_METHOD FreeSubStyles() = 0;
virtual void SCI_METHOD SetIdentifiers(int style, const char *identifiers) = 0;
virtual int SCI_METHOD DistanceToSecondaryStyles() = 0;
virtual const char * SCI_METHOD GetSubStyleBases() = 0;
};
class ILoader {
public:
virtual int SCI_METHOD Release() = 0;

View File

@ -22,7 +22,7 @@
#define PLAT_WX 0
#define PLAT_QT 0
#define PLAT_FOX 0
#define PLAT_NCURSES 0
#define PLAT_CURSES 0
#if defined(FOX)
#undef PLAT_FOX
@ -32,9 +32,9 @@
#undef PLAT_WX
#define PLAT_WX 1
#elif defined(NCURSES)
#undef PLAT_NCURSES
#define PLAT_NCURSES 1
#elif defined(CURSES)
#undef PLAT_CURSES
#define PLAT_CURSES 1
#elif defined(SCINTILLA_QT)
#undef PLAT_QT

View File

@ -477,6 +477,7 @@
#define SCE_ERR_TIDY 19
#define SCE_ERR_JAVA_STACK 20
#define SCE_ERR_VALUE 21
#define SCE_ERR_GCC_INCLUDED_FROM 22
#define SCE_BAT_DEFAULT 0
#define SCE_BAT_COMMENT 1
#define SCE_BAT_WORD 2
@ -1019,6 +1020,8 @@
#define SCE_HA_COMMENTBLOCK 14
#define SCE_HA_COMMENTBLOCK2 15
#define SCE_HA_COMMENTBLOCK3 16
#define SCE_HA_PRAGMA 17
#define SCE_HA_PREPROCESSOR 18
#define SCE_T3_DEFAULT 0
#define SCE_T3_X_DEFAULT 1
#define SCE_T3_PREPROCESSOR 2
@ -1345,6 +1348,7 @@
#define SCE_MYSQL_USER2 19
#define SCE_MYSQL_USER3 20
#define SCE_MYSQL_HIDDENCOMMAND 21
#define SCE_MYSQL_PLACEHOLDER 22
#define SCE_PO_DEFAULT 0
#define SCE_PO_COMMENT 1
#define SCE_PO_MSGID 2

View File

@ -148,6 +148,7 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam,
#define SCI_MARKERDEFINEPIXMAP 2049
#define SCI_MARKERADDSET 2466
#define SCI_MARKERSETALPHA 2476
#define SC_MAX_MARGIN 4
#define SC_MARGIN_SYMBOL 0
#define SC_MARGIN_NUMBER 1
#define SC_MARGIN_BACK 2
@ -381,6 +382,7 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam,
#define SCI_POSITIONFROMLINE 2167
#define SCI_LINESCROLL 2168
#define SCI_SCROLLCARET 2169
#define SCI_SCROLLRANGE 2569
#define SCI_REPLACESEL 2170
#define SCI_SETREADONLY 2171
#define SCI_NULL 2172
@ -696,6 +698,11 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam,
#define SC_CASEINSENSITIVEBEHAVIOUR_IGNORECASE 1
#define SCI_AUTOCSETCASEINSENSITIVEBEHAVIOUR 2634
#define SCI_AUTOCGETCASEINSENSITIVEBEHAVIOUR 2635
#define SC_ORDER_PRESORTED 0
#define SC_ORDER_PERFORMSORT 1
#define SC_ORDER_CUSTOM 2
#define SCI_AUTOCSETORDER 2660
#define SCI_AUTOCGETORDER 2661
#define SCI_ALLOCATE 2446
#define SCI_TARGETASUTF8 2447
#define SCI_SETLENGTHFORENCODE 2448
@ -775,6 +782,8 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam,
#define SCI_ANNOTATIONGETVISIBLE 2549
#define SCI_ANNOTATIONSETSTYLEOFFSET 2550
#define SCI_ANNOTATIONGETSTYLEOFFSET 2551
#define SCI_RELEASEALLEXTENDEDSTYLES 2552
#define SCI_ALLOCATEEXTENDEDSTYLES 2553
#define UNDO_MAY_COALESCE 1
#define SCI_ADDUNDOACTION 2560
#define SCI_CHARPOSITIONFROMPOINT 2561
@ -853,6 +862,8 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam,
#define SCI_FINDINDICATORHIDE 2642
#define SCI_VCHOMEDISPLAY 2652
#define SCI_VCHOMEDISPLAYEXTEND 2653
#define SCI_GETCARETLINEVISIBLEALWAYS 2654
#define SCI_SETCARETLINEVISIBLEALWAYS 2655
#define SCI_STARTRECORD 3001
#define SCI_STOPRECORD 3002
#define SCI_SETLEXER 4001
@ -957,6 +968,21 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam,
#define SCN_AUTOCCANCELLED 2025
#define SCN_AUTOCCHARDELETED 2026
#define SCN_HOTSPOTRELEASECLICK 2027
#ifndef SCI_DISABLE_PROVISIONAL
#define SC_LINE_END_TYPE_DEFAULT 0
#define SC_LINE_END_TYPE_UNICODE 1
#define SCI_SETLINEENDTYPESALLOWED 2656
#define SCI_GETLINEENDTYPESALLOWED 2657
#define SCI_GETLINEENDTYPESACTIVE 2658
#define SCI_GETLINEENDTYPESSUPPORTED 4018
#define SCI_ALLOCATESUBSTYLES 4020
#define SCI_GETSUBSTYLESSTART 4021
#define SCI_GETSUBSTYLESLENGTH 4022
#define SCI_FREESUBSTYLES 4023
#define SCI_SETIDENTIFIERS 4024
#define SCI_DISTANCETOSECONDARYSTYLES 4025
#define SCI_GETSUBSTYLEBASES 4026
#endif
/* --Autogenerated -- end of section automatically generated from Scintilla.iface */
/* These structures are defined to be exactly the same shape as the Win32

View File

@ -326,6 +326,8 @@ fun void MarkerAddSet=2466(int line, int set)
# Set the alpha used for a marker that is drawn in the text area, not the margin.
set void MarkerSetAlpha=2476(int markerNumber, int alpha)
val SC_MAX_MARGIN=4
enu MarginType=SC_MARGIN_
val SC_MARGIN_SYMBOL=0
val SC_MARGIN_NUMBER=1
@ -922,6 +924,11 @@ fun void LineScroll=2168(int columns, int lines)
# Ensure the caret is visible.
fun void ScrollCaret=2169(,)
# Scroll the argument positions and the range between them into view giving
# priority to the primary position then the secondary position.
# This may be used to make a search match visible.
fun void ScrollRange=2569(position secondary, position primary)
# Replace the selected text with the argument text.
fun void ReplaceSel=2170(, string text)
@ -1835,6 +1842,17 @@ set void AutoCSetCaseInsensitiveBehaviour=2634(int behaviour,)
# Get auto-completion case insensitive behaviour.
get int AutoCGetCaseInsensitiveBehaviour=2635(,)
enu Ordering=SC_ORDER_
val SC_ORDER_PRESORTED=0
val SC_ORDER_PERFORMSORT=1
val SC_ORDER_CUSTOM=2
# Set the way autocompletion lists are ordered.
set void AutoCSetOrder=2660(int order,)
# Get the way autocompletion lists are ordered.
get int AutoCGetOrder=2661(,)
# Enlarge the document to a particular size of text bytes.
fun void Allocate=2446(int bytes,)
@ -2062,6 +2080,12 @@ set void AnnotationSetStyleOffset=2550(int style,)
# Get the start of the range of style numbers used for annotations
get int AnnotationGetStyleOffset=2551(,)
# Release all extended (>255) style numbers
fun void ReleaseAllExtendedStyles=2552(,)
# Allocate some extended (>255) style numbers and return the start of the range
fun int AllocateExtendedStyles=2553(int numberStyles,)
val UNDO_MAY_COALESCE=1
# Add a container action to the undo stack
@ -2267,6 +2291,12 @@ fun void VCHomeDisplay=2652(,)
# Like VCHomeDisplay but extending selection to new caret position.
fun void VCHomeDisplayExtend=2653(,)
# Is the caret line always visible?
get bool GetCaretLineVisibleAlways=2654(,)
# Sets the caret line to always visible.
set void SetCaretLineVisibleAlways=2655(bool alwaysVisible,)
# Start notifying the container of all key presses and commands.
fun void StartRecord=3001(,)
@ -2922,6 +2952,7 @@ val SCE_ERR_ABSF=18
val SCE_ERR_TIDY=19
val SCE_ERR_JAVA_STACK=20
val SCE_ERR_VALUE=21
val SCE_ERR_GCC_INCLUDED_FROM=22
# Lexical states for SCLEX_BATCH
lex Batch=SCLEX_BATCH SCE_BAT_
val SCE_BAT_DEFAULT=0
@ -3405,6 +3436,7 @@ val SCE_KIX_FUNCTIONS=8
val SCE_KIX_OPERATOR=9
val SCE_KIX_IDENTIFIER=31
# Lexical states for SCLEX_GUI4CLI
lex Gui4Cli=SCLEX_GUI4CLI SCE_GC_
val SCE_GC_DEFAULT=0
val SCE_GC_COMMENTLINE=1
val SCE_GC_COMMENTBLOCK=2
@ -3549,6 +3581,8 @@ val SCE_HA_COMMENTLINE=13
val SCE_HA_COMMENTBLOCK=14
val SCE_HA_COMMENTBLOCK2=15
val SCE_HA_COMMENTBLOCK3=16
val SCE_HA_PRAGMA=17
val SCE_HA_PREPROCESSOR=18
# Lexical states of SCLEX_TADS3
lex TADS3=SCLEX_TADS3 SCE_T3_
val SCE_T3_DEFAULT=0
@ -3913,6 +3947,7 @@ val SCE_MYSQL_USER1=18
val SCE_MYSQL_USER2=19
val SCE_MYSQL_USER3=20
val SCE_MYSQL_HIDDENCOMMAND=21
val SCE_MYSQL_PLACEHOLDER=22
# Lexical state for SCLEX_PO
lex Po=SCLEX_PO SCE_PO_
val SCE_PO_DEFAULT=0
@ -4242,6 +4277,50 @@ evt void AutoCCancelled=2025(void)
evt void AutoCCharDeleted=2026(void)
evt void HotSpotReleaseClick=2027(int modifiers, int position)
cat Provisional
# Line end types which may be used in addition to LF, CR, and CRLF
# SC_LINE_END_TYPE_UNICODE includes U+2028 Line Separator,
# U+2029 Paragraph Separator, and U+0085 Next Line
enu LineEndType=SC_LINE_END_TYPE_
val SC_LINE_END_TYPE_DEFAULT=0
val SC_LINE_END_TYPE_UNICODE=1
# Set the line end types that the application wants to use. May not be used if incompatible with lexer or encoding.
set void SetLineEndTypesAllowed=2656(int lineEndBitSet,)
# Get the line end types currently allowed.
get int GetLineEndTypesAllowed=2657(,)
# Get the line end types currently recognised. May be a subset of the allowed types due to lexer limitation.
get int GetLineEndTypesActive=2658(,)
# Bit set of LineEndType enumertion for which line ends beyond the standard
# LF, CR, and CRLF are supported by the lexer.
get int GetLineEndTypesSupported=4018(,)
# Allocate a set of sub styles for a particular base style, returning start of range
fun int AllocateSubStyles=4020(int styleBase, int numberStyles)
# The starting style number for the sub styles associated with a base style
get int GetSubStylesStart=4021(int styleBase,)
# The number of sub styles associated with a base style
get int GetSubStylesLength=4022(int styleBase,)
# Free allocated sub styles
fun void FreeSubStyles=4023(,)
# Set the identifiers that are shown in a particular style
set void SetIdentifiers=4024(int style, string identifiers)
# Where styles are duplicated by a feature such as active/inactive code
# return the distance between the two types.
get int DistanceToSecondaryStyles=4025(,)
# Get the set of base styles that can be extended with sub styles
get int GetSubStyleBases=4026(, stringresult styles)
cat Deprecated
# Deprecated in 2.21

View File

@ -30,6 +30,7 @@
#include "LexerModule.h"
#include "OptionSet.h"
#include "SparseState.h"
#include "SubStyles.h"
#ifdef SCI_NAMESPACE
using namespace Scintilla;
@ -65,9 +66,8 @@ static bool followsReturnKeyword(StyleContext &sc, LexAccessor &styler) {
int pos = (int) sc.currentPos;
int currentLine = styler.GetLine(pos);
int lineStartPos = styler.LineStart(currentLine);
char ch;
while (--pos > lineStartPos) {
ch = styler.SafeGetCharAt(pos);
char ch = styler.SafeGetCharAt(pos);
if (ch != ' ' && ch != '\t') {
break;
}
@ -87,11 +87,15 @@ static std::string GetRestOfLine(LexAccessor &styler, int start, bool allowSpace
std::string restOfLine;
int i =0;
char ch = styler.SafeGetCharAt(start, '\n');
while ((ch != '\r') && (ch != '\n')) {
int endLine = styler.LineEnd(styler.GetLine(start));
while (((start+i) < endLine) && (ch != '\r')) {
char chNext = styler.SafeGetCharAt(start + i + 1, '\n');
if (ch == '/' && (chNext == '/' || chNext == '*'))
break;
if (allowSpace || (ch != ' '))
restOfLine += ch;
i++;
ch = styler.SafeGetCharAt(start + i, '\n');
ch = chNext;
}
return restOfLine;
}
@ -127,8 +131,9 @@ struct PPDefinition {
int line;
std::string key;
std::string value;
PPDefinition(int line_, const std::string &key_, const std::string &value_) :
line(line_), key(key_), value(value_) {
bool isUndef;
PPDefinition(int line_, const std::string &key_, const std::string &value_, bool isUndef_ = false) :
line(line_), key(key_), value(value_), isUndef(isUndef_) {
}
};
@ -307,7 +312,9 @@ struct OptionSetCPP : public OptionSet<OptionsCPP> {
}
};
class LexerCPP : public ILexer {
static const char styleSubable[] = {SCE_C_IDENTIFIER, SCE_C_COMMENTDOCKEYWORD, 0};
class LexerCPP : public ILexerWithSubStyles {
bool caseSensitive;
CharacterSet setWord;
CharacterSet setNegationOp;
@ -326,6 +333,8 @@ class LexerCPP : public ILexer {
OptionSetCPP osCPP;
SparseState<std::string> rawStringTerminators;
enum { activeFlag = 0x40 };
enum { ssIdentifier, ssDocKeyword };
SubStyles subStyles;
public:
LexerCPP(bool caseSensitive_) :
caseSensitive(caseSensitive_),
@ -333,7 +342,8 @@ public:
setNegationOp(CharacterSet::setNone, "!"),
setArithmethicOp(CharacterSet::setNone, "+-/*%"),
setRelOp(CharacterSet::setNone, "=!<>"),
setLogicalOp(CharacterSet::setNone, "|&") {
setLogicalOp(CharacterSet::setNone, "|&"),
subStyles(styleSubable, 0x80, 0x40, activeFlag) {
}
virtual ~LexerCPP() {
}
@ -341,7 +351,7 @@ public:
delete this;
}
int SCI_METHOD Version() const {
return lvOriginal;
return lvSubStyles;
}
const char * SCI_METHOD PropertyNames() {
return osCPP.PropertyNames();
@ -364,6 +374,32 @@ public:
return 0;
}
int SCI_METHOD LineEndTypesSupported() {
return SC_LINE_END_TYPE_UNICODE;
};
int SCI_METHOD AllocateSubStyles(int styleBase, int numberStyles) {
return subStyles.Allocate(styleBase, numberStyles);
}
int SCI_METHOD SubStylesStart(int styleBase) {
return subStyles.Start(styleBase);
}
int SCI_METHOD SubStylesLength(int styleBase) {
return subStyles.Length(styleBase);
}
void SCI_METHOD FreeSubStyles() {
subStyles.Free();
}
void SCI_METHOD SetIdentifiers(int style, const char *identifiers) {
subStyles.SetIdentifiers(style, identifiers);
}
int SCI_METHOD DistanceToSecondaryStyles() {
return activeFlag;
}
const char * SCI_METHOD GetSubStyleBases() {
return styleSubable;
}
static ILexer *LexerFactoryCPP() {
return new LexerCPP(true);
}
@ -457,6 +493,8 @@ void SCI_METHOD LexerCPP::Lex(unsigned int startPos, int length, int initStyle,
CharacterSet setWordStart(CharacterSet::setAlpha, "_", 0x80, true);
CharacterSet setInvalidRawFirst(CharacterSet::setNone, " )\\\t\v\f\n");
if (options.identifiersAllowDollars) {
setWordStart.Add('$');
}
@ -468,6 +506,7 @@ void SCI_METHOD LexerCPP::Lex(unsigned int startPos, int length, int initStyle,
bool continuationLine = false;
bool isIncludePreprocessor = false;
bool isStringInPreprocessor = false;
bool inRERange = false;
int lineCurrent = styler.GetLine(startPos);
if ((MaskActive(initStyle) == SCE_C_PREPROCESSOR) ||
@ -475,15 +514,10 @@ void SCI_METHOD LexerCPP::Lex(unsigned int startPos, int length, int initStyle,
(MaskActive(initStyle) == SCE_C_COMMENTLINEDOC)) {
// Set continuationLine if last character of previous line is '\'
if (lineCurrent > 0) {
int chBack = styler.SafeGetCharAt(startPos-1, 0);
int chBack2 = styler.SafeGetCharAt(startPos-2, 0);
int lineEndChar = '!';
if (chBack2 == '\r' && chBack == '\n') {
lineEndChar = styler.SafeGetCharAt(startPos-3, 0);
} else if (chBack == '\n' || chBack == '\r') {
lineEndChar = chBack2;
int endLinePrevious = styler.LineEnd(lineCurrent - 1);
if (endLinePrevious > 0) {
continuationLine = styler.SafeGetCharAt(endLinePrevious-1) == '\\';
}
continuationLine = lineEndChar == '\\';
}
}
@ -497,7 +531,7 @@ void SCI_METHOD LexerCPP::Lex(unsigned int startPos, int length, int initStyle,
}
}
StyleContext sc(startPos, length, initStyle, styler, 0x7f);
StyleContext sc(startPos, length, initStyle, styler, static_cast<char>(0xff));
LinePPState preproc = vlls.ForLine(lineCurrent);
bool definitionsChanged = false;
@ -515,7 +549,10 @@ void SCI_METHOD LexerCPP::Lex(unsigned int startPos, int length, int initStyle,
std::map<std::string, std::string> preprocessorDefinitions = preprocessorDefinitionsStart;
for (std::vector<PPDefinition>::iterator itDef = ppDefineHistory.begin(); itDef != ppDefineHistory.end(); ++itDef) {
preprocessorDefinitions[itDef->key] = itDef->value;
if (itDef->isUndef)
preprocessorDefinitions.erase(itDef->key);
else
preprocessorDefinitions[itDef->key] = itDef->value;
}
std::string rawStringTerminator = rawStringTerminators.ValueAt(lineCurrent-1);
@ -523,6 +560,11 @@ void SCI_METHOD LexerCPP::Lex(unsigned int startPos, int length, int initStyle,
int activitySet = preproc.IsInactive() ? activeFlag : 0;
const WordClassifier &classifierIdentifiers = subStyles.Classifier(SCE_C_IDENTIFIER);
const WordClassifier &classifierDocKeyWords = subStyles.Classifier(SCE_C_COMMENTDOCKEYWORD);
int lineEndNext = styler.LineEnd(lineCurrent);
for (; sc.More();) {
if (sc.atLineStart) {
@ -541,6 +583,7 @@ void SCI_METHOD LexerCPP::Lex(unsigned int startPos, int length, int initStyle,
visibleChars = 0;
lastWordWasUUID = false;
isIncludePreprocessor = false;
inRERange = false;
if (preproc.IsInactive()) {
activitySet = activeFlag;
sc.SetState(sc.state | activitySet);
@ -549,6 +592,7 @@ void SCI_METHOD LexerCPP::Lex(unsigned int startPos, int length, int initStyle,
if (sc.atLineEnd) {
lineCurrent++;
lineEndNext = styler.LineEnd(lineCurrent);
vlls.Add(lineCurrent, preproc);
if (rawStringTerminator != "") {
rawSTNew.Set(lineCurrent-1, rawStringTerminator);
@ -557,11 +601,13 @@ void SCI_METHOD LexerCPP::Lex(unsigned int startPos, int length, int initStyle,
// Handle line continuation generically.
if (sc.ch == '\\') {
if (sc.chNext == '\n' || sc.chNext == '\r') {
if (static_cast<int>((sc.currentPos+1)) >= lineEndNext) {
lineCurrent++;
lineEndNext = styler.LineEnd(lineCurrent);
vlls.Add(lineCurrent, preproc);
sc.Forward();
if (sc.ch == '\r' && sc.chNext == '\n') {
// Even in UTF-8, \r and \n are separate
sc.Forward();
}
continuationLine = true;
@ -586,7 +632,7 @@ void SCI_METHOD LexerCPP::Lex(unsigned int startPos, int length, int initStyle,
}
break;
case SCE_C_IDENTIFIER:
if (!setWord.Contains(sc.ch) || (sc.ch == '.')) {
if (sc.atLineStart || sc.atLineEnd || !setWord.Contains(sc.ch) || (sc.ch == '.')) {
char s[1000];
if (caseSensitive) {
sc.GetCurrent(s, sizeof(s));
@ -600,11 +646,16 @@ void SCI_METHOD LexerCPP::Lex(unsigned int startPos, int length, int initStyle,
sc.ChangeState(SCE_C_WORD2|activitySet);
} else if (keywords4.InList(s)) {
sc.ChangeState(SCE_C_GLOBALCLASS|activitySet);
} else {
int subStyle = classifierIdentifiers.ValueFor(s);
if (subStyle >= 0) {
sc.ChangeState(subStyle|activitySet);
}
}
const bool literalString = sc.ch == '\"';
if (literalString || sc.ch == '\'') {
size_t lenS = strlen(s);
const bool raw = literalString && sc.chPrev == 'R';
const bool raw = literalString && sc.chPrev == 'R' && !setInvalidRawFirst.Contains(sc.chNext);
if (raw)
s[lenS--] = '\0';
bool valid =
@ -692,8 +743,15 @@ void SCI_METHOD LexerCPP::Lex(unsigned int startPos, int length, int initStyle,
} else {
sc.GetCurrentLowered(s, sizeof(s));
}
if (!IsASpace(sc.ch) || !keywords3.InList(s + 1)) {
if (!IsASpace(sc.ch)) {
sc.ChangeState(SCE_C_COMMENTDOCKEYWORDERROR|activitySet);
} else if (!keywords3.InList(s + 1)) {
int subStyleCDKW = classifierDocKeyWords.ValueFor(s+1);
if (subStyleCDKW >= 0) {
sc.ChangeState(subStyleCDKW|activitySet);
} else {
sc.ChangeState(SCE_C_COMMENTDOCKEYWORDERROR|activitySet);
}
}
sc.SetState(styleBeforeDCKeyword|activitySet);
}
@ -745,16 +803,18 @@ void SCI_METHOD LexerCPP::Lex(unsigned int startPos, int length, int initStyle,
case SCE_C_REGEX:
if (sc.atLineStart) {
sc.SetState(SCE_C_DEFAULT|activitySet);
} else if (sc.ch == '/') {
} else if (! inRERange && sc.ch == '/') {
sc.Forward();
while ((sc.ch < 0x80) && islower(sc.ch))
sc.Forward(); // gobble regex flags
sc.SetState(SCE_C_DEFAULT|activitySet);
} else if (sc.ch == '\\') {
// Gobble up the quoted character
if (sc.chNext == '\\' || sc.chNext == '/') {
sc.Forward();
}
} else if (sc.ch == '\\' && (static_cast<int>(sc.currentPos+1) < lineEndNext)) {
// Gobble up the escaped character
sc.Forward();
} else if (sc.ch == '[') {
inRERange = true;
} else if (sc.ch == ']') {
inRERange = false;
}
break;
case SCE_C_STRINGEOL:
@ -780,7 +840,7 @@ void SCI_METHOD LexerCPP::Lex(unsigned int startPos, int length, int initStyle,
}
break;
case SCE_C_UUID:
if (sc.ch == '\r' || sc.ch == '\n' || sc.ch == ')') {
if (sc.atLineEnd || sc.ch == ')') {
sc.SetState(SCE_C_DEFAULT|activitySet);
}
}
@ -788,6 +848,7 @@ void SCI_METHOD LexerCPP::Lex(unsigned int startPos, int length, int initStyle,
if (sc.atLineEnd && !atLineEndBeforeSwitch) {
// State exit processing consumed characters up to end of line.
lineCurrent++;
lineEndNext = styler.LineEnd(lineCurrent);
vlls.Add(lineCurrent, preproc);
}
@ -809,7 +870,7 @@ void SCI_METHOD LexerCPP::Lex(unsigned int startPos, int length, int initStyle,
} else {
sc.SetState(SCE_C_NUMBER|activitySet);
}
} else if (setWordStart.Contains(sc.ch) || (sc.ch == '@')) {
} else if (!sc.atLineEnd && (setWordStart.Contains(sc.ch) || (sc.ch == '@'))) {
if (lastWordWasUUID) {
sc.SetState(SCE_C_UUID|activitySet);
lastWordWasUUID = false;
@ -835,6 +896,7 @@ void SCI_METHOD LexerCPP::Lex(unsigned int startPos, int length, int initStyle,
&& (!setCouldBePostOp.Contains(chPrevNonWhite)
|| !FollowsPostfixOperator(sc, styler))) {
sc.SetState(SCE_C_REGEX|activitySet); // JavaScript's RegEx
inRERange = false;
} else if (sc.ch == '\"') {
if (sc.chPrev == 'R') {
styler.Flush();
@ -934,10 +996,22 @@ void SCI_METHOD LexerCPP::Lex(unsigned int startPos, int length, int initStyle,
}
}
}
} else if (sc.Match("undef")) {
if (options.updatePreprocessor && !preproc.IsInactive()) {
std::string restOfLine = GetRestOfLine(styler, sc.currentPos + 5, true);
std::vector<std::string> tokens = Tokenize(restOfLine);
std::string key;
if (tokens.size() >= 1) {
key = tokens[0];
preprocessorDefinitions.erase(key);
ppDefineHistory.push_back(PPDefinition(lineCurrent, key, "", true));
definitionsChanged = true;
}
}
}
}
}
} else if (isoperator(static_cast<char>(sc.ch))) {
} else if (isoperator(sc.ch)) {
sc.SetState(SCE_C_OPERATOR|activitySet);
}
}
@ -968,10 +1042,12 @@ void SCI_METHOD LexerCPP::Fold(unsigned int startPos, int length, int initStyle,
unsigned int endPos = startPos + length;
int visibleChars = 0;
bool inLineComment = false;
int lineCurrent = styler.GetLine(startPos);
int levelCurrent = SC_FOLDLEVELBASE;
if (lineCurrent > 0)
levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
unsigned int lineStartNext = styler.LineStart(lineCurrent+1);
int levelMinCurrent = levelCurrent;
int levelNext = levelCurrent;
char chNext = styler[startPos];
@ -984,11 +1060,13 @@ void SCI_METHOD LexerCPP::Fold(unsigned int startPos, int length, int initStyle,
int stylePrev = style;
style = styleNext;
styleNext = MaskActive(styler.StyleAt(i + 1));
bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
if (options.foldComment && options.foldCommentMultiline && IsStreamCommentStyle(style)) {
if (!IsStreamCommentStyle(stylePrev) && (stylePrev != SCE_C_COMMENTLINEDOC)) {
bool atEOL = i == (lineStartNext-1);
if ((style == SCE_C_COMMENTLINE) || (style == SCE_C_COMMENTLINEDOC))
inLineComment = true;
if (options.foldComment && options.foldCommentMultiline && IsStreamCommentStyle(style) && !inLineComment) {
if (!IsStreamCommentStyle(stylePrev)) {
levelNext++;
} else if (!IsStreamCommentStyle(styleNext) && (styleNext != SCE_C_COMMENTLINEDOC) && !atEOL) {
} else if (!IsStreamCommentStyle(styleNext) && !atEOL) {
// Comments don't end at end of line and the next character may be unstyled.
levelNext--;
}
@ -1052,6 +1130,7 @@ void SCI_METHOD LexerCPP::Fold(unsigned int startPos, int length, int initStyle,
styler.SetLevel(lineCurrent, lev);
}
lineCurrent++;
lineStartNext = styler.LineStart(lineCurrent+1);
levelCurrent = levelNext;
levelMinCurrent = levelCurrent;
if (atEOL && (i == static_cast<unsigned int>(styler.Length()-1))) {
@ -1059,6 +1138,7 @@ void SCI_METHOD LexerCPP::Fold(unsigned int startPos, int length, int initStyle,
styler.SetLevel(lineCurrent, (levelCurrent | levelCurrent << 16) | SC_FOLDLEVELWHITEFLAG);
}
visibleChars = 0;
inLineComment = false;
}
}
}
@ -1172,7 +1252,7 @@ bool LexerCPP::EvaluateExpression(const std::string &expr, const std::map<std::s
std::vector<std::string> tokens;
const char *cp = expr.c_str();
for (;;) {
if (setWord.Contains(*cp)) {
if (setWord.Contains(static_cast<unsigned char>(*cp))) {
word += *cp;
} else {
std::map<std::string, std::string>::const_iterator it = preprocessorDefinitions.find(word);
@ -1187,13 +1267,13 @@ bool LexerCPP::EvaluateExpression(const std::string &expr, const std::map<std::s
}
if ((*cp != ' ') && (*cp != '\t')) {
std::string op(cp, 1);
if (setRelOp.Contains(*cp)) {
if (setRelOp.Contains(cp[1])) {
if (setRelOp.Contains(static_cast<unsigned char>(*cp))) {
if (setRelOp.Contains(static_cast<unsigned char>(cp[1]))) {
op += cp[1];
cp++;
}
} else if (setLogicalOp.Contains(*cp)) {
if (setLogicalOp.Contains(cp[1])) {
} else if (setLogicalOp.Contains(static_cast<unsigned char>(*cp))) {
if (setLogicalOp.Contains(static_cast<unsigned char>(cp[1]))) {
op += cp[1];
cp++;
}

View File

@ -445,11 +445,6 @@ static int StateForScript(script_type scriptLanguage) {
return Result;
}
static inline bool ishtmlwordchar(int ch) {
return !isascii(ch) ||
(isalnum(ch) || ch == '.' || ch == '-' || ch == '_' || ch == ':' || ch == '!' || ch == '#');
}
static inline bool issgmlwordchar(int ch) {
return !isascii(ch) ||
(isalnum(ch) || ch == '.' || ch == '_' || ch == ':' || ch == '!' || ch == '#' || ch == '[');
@ -484,10 +479,6 @@ static bool isLineEnd(int ch) {
return ch == '\r' || ch == '\n';
}
static bool isOKBeforeRE(int ch) {
return (ch == '(') || (ch == '=') || (ch == ',');
}
static bool isMakoBlockEnd(const int ch, const int chNext, const char *blockType) {
if (strlen(blockType) == 0) {
return ((ch == '%') && (chNext == '>'));
@ -691,6 +682,8 @@ static void ColouriseHyperTextDoc(unsigned int startPos, int length, int initSty
const CharacterSet setHTMLWord(CharacterSet::setAlphaNum, ".-_:!#", 0x80, true);
const CharacterSet setTagContinue(CharacterSet::setAlphaNum, ".-_:!#[", 0x80, true);
const CharacterSet setAttributeContinue(CharacterSet::setAlphaNum, ".-_:!#/", 0x80, true);
// TODO: also handle + and - (except if they're part of ++ or --) and return keywords
const CharacterSet setOKBeforeJSRE(CharacterSet::setNone, "([{=,:;!%^&*|?~");
int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
int levelCurrent = levelPrev;
@ -905,7 +898,7 @@ static void ColouriseHyperTextDoc(unsigned int startPos, int length, int initSty
!IsScriptCommentState(state)) {
beforeLanguage = scriptLanguage;
scriptLanguage = segIsScriptingIndicator(styler, i + 2, i + 6, isXml ? eScriptXML : eScriptPHP);
if (scriptLanguage != eScriptPHP && isStringState(state)) continue;
if ((scriptLanguage != eScriptPHP) && (isStringState(state) || (state==SCE_H_COMMENT))) continue;
styler.ColourTo(i - 1, StateToPrint);
beforePreProc = state;
i++;
@ -1592,7 +1585,7 @@ static void ColouriseHyperTextDoc(unsigned int startPos, int length, int initSty
} else if (ch == '/' && chNext == '/') {
styler.ColourTo(i - 1, StateToPrint);
state = SCE_HJ_COMMENTLINE;
} else if (ch == '/' && isOKBeforeRE(chPrevNonWhite)) {
} else if (ch == '/' && setOKBeforeJSRE.Contains(chPrevNonWhite)) {
styler.ColourTo(i - 1, StateToPrint);
state = SCE_HJ_REGEX;
} else if (ch == '\"') {

View File

@ -9,6 +9,8 @@
*
* Several bug fixes by Krasimir Angelov - kr.angelov at gmail.com
*
* Improvements by kudah - kudahkukarek at gmail.com
*
* TODO:
* * Implement a folder :)
* * Nice Character-lexing (stuff inside '\''), LexPython has
@ -57,22 +59,24 @@ using namespace Scintilla;
#define HA_MODE_FFI 5
#define HA_MODE_TYPE 6
static inline bool IsNewline(const int ch) {
return (ch == '\n' || ch == '\r');
}
static inline bool IsWhitespace(const int ch) {
return ( ch == ' '
|| ch == '\t'
|| IsNewline(ch) );
}
static inline bool IsAWordStart(const int ch) {
return (ch < 0x80) && (isalnum(ch) || ch == '_');
return (IsLowerCase(ch) || IsUpperCase(ch) || ch == '_');
}
static inline bool IsAWordChar(const int ch) {
return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_' || ch == '\'');
static inline bool IsAWordChar(const int ch, const bool magicHash) {
return ( IsAlphaNumeric(ch)
|| ch == '_'
|| ch == '\''
|| (magicHash && 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 void ColorizeHaskellDoc(unsigned int startPos, int length, int initStyle,
@ -81,230 +85,293 @@ static void ColorizeHaskellDoc(unsigned int startPos, int length, int initStyle,
WordList &keywords = *keywordlists[0];
WordList &ffi = *keywordlists[1];
// 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;
StyleContext sc(startPos, length, initStyle, styler);
int lineCurrent = styler.GetLine(startPos);
int state = lineCurrent ? styler.GetLineState(lineCurrent-1)
: HA_MODE_DEFAULT;
int mode = state & 0xF;
int xmode = state >> 4;
int xmode = state >> 4; // obscure parameter. Means different things in different modes.
while (sc.More()) {
// Check for state end
// Operator
if (sc.state == SCE_HA_OPERATOR) {
if (isascii(sc.ch) && isoperator(static_cast<char>(sc.ch))) {
sc.Forward();
} else {
styler.ColourTo(sc.currentPos - 1, sc.state);
sc.ChangeState(SCE_HA_DEFAULT);
int style = SCE_HA_OPERATOR;
if (sc.ch == ':' &&
// except "::"
!(sc.chNext == ':' && !IsAnOperatorChar(sc.GetRelative(2)))) {
style = SCE_HA_CAPITAL;
}
while(IsAnOperatorChar(sc.ch))
sc.Forward();
styler.ColourTo(sc.currentPos - 1, style);
sc.ChangeState(SCE_HA_DEFAULT);
}
// String
else if (sc.state == SCE_HA_STRING) {
if (sc.ch == '\"') {
sc.Forward();
styler.ColourTo(sc.currentPos-1, sc.state);
sc.ChangeState(SCE_HA_DEFAULT);
sc.Forward();
sc.SetState(SCE_HA_DEFAULT);
} else if (sc.ch == '\\') {
sc.Forward(2);
} else if (sc.atLineEnd) {
styler.ColourTo(sc.currentPos-1, sc.state);
sc.ChangeState(SCE_HA_DEFAULT);
} else {
sc.Forward();
}
sc.SetState(SCE_HA_DEFAULT);
} else {
sc.Forward();
}
}
// Char
else if (sc.state == SCE_HA_CHARACTER) {
if (sc.ch == '\'') {
sc.Forward();
styler.ColourTo(sc.currentPos-1, sc.state);
sc.ChangeState(SCE_HA_DEFAULT);
sc.Forward();
sc.SetState(SCE_HA_DEFAULT);
} else if (sc.ch == '\\') {
sc.Forward(2);
} else if (sc.atLineEnd) {
styler.ColourTo(sc.currentPos-1, sc.state);
sc.ChangeState(SCE_HA_DEFAULT);
} else {
sc.Forward();
}
sc.SetState(SCE_HA_DEFAULT);
} else {
sc.Forward();
}
}
// Number
else if (sc.state == SCE_HA_NUMBER) {
if (IsADigit(sc.ch, xmode)) {
if (IsADigit(sc.ch, xmode) ||
(sc.ch=='.' && IsADigit(sc.chNext, xmode))) {
sc.Forward();
} else if ((xmode == 10) &&
(sc.ch == 'e' || sc.ch == 'E') &&
(IsADigit(sc.chNext) || sc.chNext == '+' || sc.chNext == '-')) {
sc.Forward();
if (sc.ch == '+' || sc.ch == '-')
sc.Forward();
sc.Forward();
if (sc.ch == '+' || sc.ch == '-')
sc.Forward();
} else {
styler.ColourTo(sc.currentPos - 1, sc.state);
sc.ChangeState(SCE_HA_DEFAULT);
sc.SetState(SCE_HA_DEFAULT);
}
}
// Identifier
// Keyword or Identifier
else if (sc.state == SCE_HA_IDENTIFIER) {
if (IsAWordChar(sc.ch)) {
sc.Forward();
} else {
char s[100];
sc.GetCurrent(s, sizeof(s));
int style = sc.state;
int new_mode = 0;
if (keywords.InList(s)) {
style = SCE_HA_KEYWORD;
} else if (isupper(s[0])) {
if (mode >= HA_MODE_IMPORT1 && mode <= HA_MODE_IMPORT3) {
style = SCE_HA_MODULE;
new_mode = HA_MODE_IMPORT2;
} else if (mode == HA_MODE_MODULE)
style = SCE_HA_MODULE;
else
style = SCE_HA_CAPITAL;
} else if (mode == HA_MODE_IMPORT1 &&
strcmp(s,"qualified") == 0) {
style = SCE_HA_KEYWORD;
new_mode = HA_MODE_IMPORT1;
} else if (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_FFI) {
if (ffi.InList(s)) {
style = SCE_HA_KEYWORD;
new_mode = HA_MODE_FFI;
while (sc.More()) {
if (IsAWordChar(sc.ch, magicHash)) {
sc.Forward();
} else if (xmode == SCE_HA_CAPITAL && sc.ch=='.') {
if (isupper(sc.chNext)) {
xmode = SCE_HA_CAPITAL;
sc.Forward();
} else if (IsAWordStart(sc.chNext)) {
xmode = SCE_HA_IDENTIFIER;
sc.Forward();
} else if (IsAnOperatorChar(sc.chNext)) {
xmode = SCE_HA_OPERATOR;
sc.Forward();
} else {
break;
}
} else if (xmode == SCE_HA_OPERATOR && IsAnOperatorChar(sc.ch)) {
sc.Forward();
} else {
break;
}
else if (mode == HA_MODE_TYPE) {
if (strcmp(s,"family") == 0)
style = SCE_HA_KEYWORD;
}
styler.ColourTo(sc.currentPos - 1, style);
if (strcmp(s,"import") == 0 && mode != HA_MODE_FFI)
new_mode = HA_MODE_IMPORT1;
else if (strcmp(s,"module") == 0)
new_mode = HA_MODE_MODULE;
else if (strcmp(s,"foreign") == 0)
new_mode = HA_MODE_FFI;
else if (strcmp(s,"type") == 0)
new_mode = HA_MODE_TYPE;
sc.ChangeState(SCE_HA_DEFAULT);
mode = new_mode;
}
char s[100];
sc.GetCurrent(s, sizeof(s));
int style = xmode;
int 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) {
style = SCE_HA_MODULE;
new_mode = HA_MODE_IMPORT2;
} else if (mode == HA_MODE_MODULE) {
style = SCE_HA_MODULE;
}
} else if (mode == HA_MODE_IMPORT1 &&
strcmp(s,"qualified") == 0) {
style = SCE_HA_KEYWORD;
new_mode = HA_MODE_IMPORT1;
} else if (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) {
if (strcmp(s,"family") == 0)
style = SCE_HA_KEYWORD;
}
if (mode == HA_MODE_FFI) {
if (ffi.InList(s)) {
style = SCE_HA_KEYWORD;
new_mode = HA_MODE_FFI;
}
}
styler.ColourTo(sc.currentPos - 1, style);
if (strcmp(s,"import") == 0 && mode != HA_MODE_FFI)
new_mode = HA_MODE_IMPORT1;
else if (strcmp(s,"module") == 0)
new_mode = HA_MODE_MODULE;
else if (strcmp(s,"foreign") == 0)
new_mode = HA_MODE_FFI;
else if (strcmp(s,"type") == 0
|| strcmp(s,"data") == 0)
new_mode = HA_MODE_TYPE;
xmode = 0;
sc.ChangeState(SCE_HA_DEFAULT);
mode = new_mode;
}
// Comments
// Oneliner
else if (sc.state == SCE_HA_COMMENTLINE) {
if (sc.atLineEnd) {
styler.ColourTo(sc.currentPos - 1, sc.state);
sc.ChangeState(SCE_HA_DEFAULT);
if (xmode == 1 && sc.ch != '-') {
xmode = 0;
if (IsAnOperatorChar(sc.ch))
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) {
if (sc.Match("{-")) {
if (sc.Match('{','-')) {
sc.Forward(2);
xmode++;
}
else if (sc.Match("-}")) {
else if (sc.Match('-','}')) {
sc.Forward(2);
xmode--;
if (xmode == 0) {
styler.ColourTo(sc.currentPos - 1, sc.state);
sc.ChangeState(SCE_HA_DEFAULT);
sc.SetState(SCE_HA_DEFAULT);
}
} else {
if (sc.atLineEnd) {
// Remember the line state for future incremental lexing
styler.SetLineState(lineCurrent, (xmode << 4) | mode);
lineCurrent++;
}
// 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("#-}")) {
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) {
sc.Forward(2);
} else if (sc.atLineEnd) {
sc.SetState(SCE_HA_DEFAULT);
} else {
sc.Forward();
}
}
// New state?
if (sc.state == SCE_HA_DEFAULT) {
// Digit
if (IsADigit(sc.ch) ||
(sc.ch == '.' && IsADigit(sc.chNext)) ||
(sc.ch == '-' && IsADigit(sc.chNext))) {
styler.ColourTo(sc.currentPos - 1, sc.state);
sc.ChangeState(SCE_HA_NUMBER);
if (IsADigit(sc.ch)) {
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);
xmode = 16;
} 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 "0x" or "0X", too
sc.Forward(2);
xmode = 8;
} else {
sc.Forward();
xmode = 10;
}
sc.Forward();
xmode = 10;
}
mode = HA_MODE_DEFAULT;
}
// Comment line
else if (sc.Match("--")) {
styler.ColourTo(sc.currentPos - 1, sc.state);
sc.Forward(2);
sc.ChangeState(SCE_HA_COMMENTLINE);
// Comment block
// Pragma
else if (sc.Match("{-#")) {
sc.SetState(SCE_HA_PRAGMA);
sc.Forward(3);
}
else if (sc.Match("{-")) {
styler.ColourTo(sc.currentPos - 1, sc.state);
// Comment line
else if (sc.Match('-','-')) {
sc.SetState(SCE_HA_COMMENTLINE);
sc.Forward(2);
xmode = 1;
}
// Comment block
else if (sc.Match('{','-')) {
sc.SetState(SCE_HA_COMMENTBLOCK);
sc.Forward(2);
sc.ChangeState(SCE_HA_COMMENTBLOCK);
xmode = 1;
}
// String
else if (sc.Match('\"')) {
styler.ColourTo(sc.currentPos - 1, sc.state);
sc.SetState(SCE_HA_STRING);
sc.Forward();
sc.ChangeState(SCE_HA_STRING);
}
// Character
else if (sc.Match('\'')) {
styler.ColourTo(sc.currentPos - 1, sc.state);
sc.SetState(SCE_HA_CHARACTER);
sc.Forward();
sc.ChangeState(SCE_HA_CHARACTER);
}
else if (sc.ch == '(' || sc.ch == ')' ||
sc.ch == '{' || sc.ch == '}' ||
sc.ch == '[' || sc.ch == ']') {
styler.ColourTo(sc.currentPos - 1, sc.state);
sc.Forward();
styler.ColourTo(sc.currentPos - 1, SCE_HA_OPERATOR);
mode = HA_MODE_DEFAULT;
}
// Operator
else if (isascii(sc.ch) && isoperator(static_cast<char>(sc.ch))) {
styler.ColourTo(sc.currentPos - 1, sc.state);
sc.Forward();
sc.ChangeState(SCE_HA_OPERATOR);
// Preprocessor
else if (sc.atLineStart && sc.ch == '#') {
mode = HA_MODE_DEFAULT;
}
// Keyword
else if (IsAWordStart(sc.ch)) {
styler.ColourTo(sc.currentPos - 1, sc.state);
sc.SetState(SCE_HA_PREPROCESSOR);
sc.Forward();
}
// Operator
else if (IsAnOperatorChar(sc.ch)) {
mode = HA_MODE_DEFAULT;
sc.SetState(SCE_HA_OPERATOR);
}
// Braces and punctuation
else if (sc.ch == ',' || sc.ch == ';'
|| sc.ch == '(' || sc.ch == ')'
|| sc.ch == '[' || sc.ch == ']'
|| sc.ch == '{' || sc.ch == '}') {
sc.SetState(SCE_HA_OPERATOR);
sc.Forward();
sc.SetState(SCE_HA_DEFAULT);
}
// Keyword or Identifier
else if (IsAWordStart(sc.ch)) {
xmode = isupper(sc.ch) ? SCE_HA_CAPITAL : SCE_HA_IDENTIFIER;
sc.SetState(SCE_HA_IDENTIFIER);
sc.Forward();
sc.ChangeState(SCE_HA_IDENTIFIER);
} else {
if (sc.atLineEnd) {
// Remember the line state for future incremental lexing
styler.SetLineState(lineCurrent, (xmode << 4) | mode);
lineCurrent++;
}
// Remember the line state for future incremental lexing
styler.SetLineState(lineCurrent, (xmode << 4) | mode);
lineCurrent++;
}
sc.Forward();
}
}

View File

@ -0,0 +1,539 @@
// Scintilla source code edit control
/** @file LexLaTeX.cxx
** Lexer for LaTeX2e.
**/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.
// Modified by G. HU in 2013. Added folding, syntax highting inside math environments, and changed some minor behaviors.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <assert.h>
#include <ctype.h>
#include <vector>
#include "ILexer.h"
#include "Scintilla.h"
#include "SciLexer.h"
#include "PropSetSimple.h"
#include "WordList.h"
#include "LexAccessor.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "CharacterSet.h"
#include "LexerModule.h"
#include "LexerBase.h"
#ifdef SCI_NAMESPACE
using namespace Scintilla;
#endif
using namespace std;
struct latexFoldSave {
latexFoldSave() : structLev(0) {
for (int i = 0; i < 8; ++i) openBegins[i] = 0;
}
latexFoldSave(const latexFoldSave &save) : structLev(save.structLev) {
for (int i = 0; i < 8; ++i) openBegins[i] = save.openBegins[i];
}
int openBegins[8];
int structLev;
};
class LexerLaTeX : public LexerBase {
private:
vector<int> modes;
void setMode(int line, int mode) {
if (line >= static_cast<int>(modes.size())) modes.resize(line + 1, 0);
modes[line] = mode;
}
int getMode(int line) {
if (line >= 0 && line < static_cast<int>(modes.size())) return modes[line];
return 0;
}
void truncModes(int numLines) {
if (static_cast<int>(modes.size()) > numLines * 2 + 256)
modes.resize(numLines + 128);
}
vector<latexFoldSave> saves;
void setSave(int line, const latexFoldSave &save) {
if (line >= static_cast<int>(saves.size())) saves.resize(line + 1);
saves[line] = save;
}
void getSave(int line, latexFoldSave &save) {
if (line >= 0 && line < static_cast<int>(saves.size())) save = saves[line];
else {
save.structLev = 0;
for (int i = 0; i < 8; ++i) save.openBegins[i] = 0;
}
}
void truncSaves(int numLines) {
if (static_cast<int>(saves.size()) > numLines * 2 + 256)
saves.resize(numLines + 128);
}
public:
static ILexer *LexerFactoryLaTeX() {
return new LexerLaTeX();
}
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);
};
static bool latexIsSpecial(int ch) {
return (ch == '#') || (ch == '$') || (ch == '%') || (ch == '&') || (ch == '_') ||
(ch == '{') || (ch == '}') || (ch == ' ');
}
static bool latexIsBlank(int ch) {
return (ch == ' ') || (ch == '\t');
}
static bool latexIsBlankAndNL(int ch) {
return (ch == ' ') || (ch == '\t') || (ch == '\r') || (ch == '\n');
}
static bool latexIsLetter(int ch) {
return isascii(ch) && isalpha(ch);
}
static bool latexIsTagValid(int &i, int l, Accessor &styler) {
while (i < l) {
if (styler.SafeGetCharAt(i) == '{') {
while (i < l) {
i++;
if (styler.SafeGetCharAt(i) == '}') {
return true;
} else if (!latexIsLetter(styler.SafeGetCharAt(i)) &&
styler.SafeGetCharAt(i)!='*') {
return false;
}
}
} else if (!latexIsBlank(styler.SafeGetCharAt(i))) {
return false;
}
i++;
}
return false;
}
static bool latexNextNotBlankIs(int i, Accessor &styler, char needle) {
char ch;
while (i < styler.Length()) {
ch = styler.SafeGetCharAt(i);
if (!latexIsBlankAndNL(ch) && ch != '*') {
if (ch == needle)
return true;
else
return false;
}
i++;
}
return false;
}
static bool latexLastWordIs(int start, Accessor &styler, const char *needle) {
unsigned int i = 0;
unsigned int l = static_cast<unsigned int>(strlen(needle));
int ini = start-l+1;
char s[32];
while (i < l && i < 31) {
s[i] = styler.SafeGetCharAt(ini + i);
i++;
}
s[i] = '\0';
return (strcmp(s, needle) == 0);
}
static bool latexLastWordIsMathEnv(int pos, Accessor &styler) {
int i, j;
char s[32];
const char *mathEnvs[] = { "align", "alignat", "flalign", "gather",
"multiline", "displaymath", "eqnarray", "equation" };
if (styler.SafeGetCharAt(pos) != '}') return false;
for (i = pos - 1; i >= 0; --i) {
if (styler.SafeGetCharAt(i) == '{') break;
if (pos - i >= 20) return false;
}
if (i < 0 || i == pos - 1) return false;
++i;
for (j = 0; i + j < pos; ++j)
s[j] = styler.SafeGetCharAt(i + j);
s[j] = '\0';
if (j == 0) return false;
if (s[j - 1] == '*') s[--j] = '\0';
for (i = 0; i < static_cast<int>(sizeof(mathEnvs) / sizeof(const char *)); ++i)
if (strcmp(s, mathEnvs[i]) == 0) return true;
return false;
}
static inline void latexStateReset(int &mode, int &state) {
switch (mode) {
case 1: state = SCE_L_MATH; break;
case 2: state = SCE_L_MATH2; break;
default: state = SCE_L_DEFAULT; break;
}
}
// There are cases not handled correctly, like $abcd\textrm{what is $x+y$}z+w$.
// But I think it's already good enough.
void SCI_METHOD LexerLaTeX::Lex(unsigned int startPos, int length, int initStyle, IDocument *pAccess) {
// startPos is assumed to be the first character of a line
Accessor styler(pAccess, &props);
styler.StartAt(startPos);
int mode = getMode(styler.GetLine(startPos) - 1);
int state = initStyle;
if (state == SCE_L_ERROR || state == SCE_L_SHORTCMD || state == SCE_L_SPECIAL) // should not happen
latexStateReset(mode, state);
char chNext = styler.SafeGetCharAt(startPos);
char chVerbatimDelim = '\0';
styler.StartSegment(startPos);
int lengthDoc = startPos + length;
for (int i = startPos; i < lengthDoc; i++) {
char ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
if (styler.IsLeadByte(ch)) {
i++;
chNext = styler.SafeGetCharAt(i + 1);
continue;
}
if (ch == '\r' || ch == '\n')
setMode(styler.GetLine(i), mode);
switch (state) {
case SCE_L_DEFAULT :
switch (ch) {
case '\\' :
styler.ColourTo(i - 1, state);
if (latexIsLetter(chNext)) {
state = SCE_L_COMMAND;
} else if (latexIsSpecial(chNext)) {
styler.ColourTo(i + 1, SCE_L_SPECIAL);
i++;
chNext = styler.SafeGetCharAt(i + 1);
} else if (chNext == '\r' || chNext == '\n') {
styler.ColourTo(i, SCE_L_ERROR);
} else {
styler.ColourTo(i + 1, SCE_L_SHORTCMD);
if (chNext == '(') {
mode = 1;
state = SCE_L_MATH;
} else if (chNext == '[') {
mode = 2;
state = SCE_L_MATH2;
}
i++;
chNext = styler.SafeGetCharAt(i + 1);
}
break;
case '$' :
styler.ColourTo(i - 1, state);
if (chNext == '$') {
styler.ColourTo(i + 1, SCE_L_SHORTCMD);
mode = 2;
state = SCE_L_MATH2;
i++;
chNext = styler.SafeGetCharAt(i + 1);
} else {
styler.ColourTo(i, SCE_L_SHORTCMD);
mode = 1;
state = SCE_L_MATH;
}
break;
case '%' :
styler.ColourTo(i - 1, state);
state = SCE_L_COMMENT;
break;
}
break;
// These 3 will never be reached.
case SCE_L_ERROR:
case SCE_L_SPECIAL:
case SCE_L_SHORTCMD:
break;
case SCE_L_COMMAND :
if (!latexIsLetter(chNext)) {
styler.ColourTo(i, state);
if (latexNextNotBlankIs(i + 1, styler, '[' )) {
state = SCE_L_CMDOPT;
} else if (latexLastWordIs(i, styler, "\\begin")) {
state = SCE_L_TAG;
} else if (latexLastWordIs(i, styler, "\\end")) {
state = SCE_L_TAG2;
} else if (latexLastWordIs(i, styler, "\\verb") && chNext != '*' && chNext != ' ') {
chVerbatimDelim = chNext;
state = SCE_L_VERBATIM;
} else {
latexStateReset(mode, state);
}
}
break;
case SCE_L_CMDOPT :
if (ch == ']') {
styler.ColourTo(i, state);
latexStateReset(mode, state);
}
break;
case SCE_L_TAG :
if (latexIsTagValid(i, lengthDoc, styler)) {
styler.ColourTo(i, state);
latexStateReset(mode, state);
if (latexLastWordIs(i, styler, "{verbatim}")) {
state = SCE_L_VERBATIM;
} else if (latexLastWordIs(i, styler, "{comment}")) {
state = SCE_L_COMMENT2;
} else if (latexLastWordIs(i, styler, "{math}") && mode == 0) {
mode = 1;
state = SCE_L_MATH;
} else if (latexLastWordIsMathEnv(i, styler) && mode == 0) {
mode = 2;
state = SCE_L_MATH2;
}
} else {
styler.ColourTo(i, SCE_L_ERROR);
latexStateReset(mode, state);
ch = styler.SafeGetCharAt(i);
if (ch == '\r' || ch == '\n') setMode(styler.GetLine(i), mode);
}
chNext = styler.SafeGetCharAt(i+1);
break;
case SCE_L_TAG2 :
if (latexIsTagValid(i, lengthDoc, styler)) {
styler.ColourTo(i, state);
latexStateReset(mode, state);
} else {
styler.ColourTo(i, SCE_L_ERROR);
latexStateReset(mode, state);
ch = styler.SafeGetCharAt(i);
if (ch == '\r' || ch == '\n') setMode(styler.GetLine(i), mode);
}
chNext = styler.SafeGetCharAt(i+1);
break;
case SCE_L_MATH :
switch (ch) {
case '\\' :
styler.ColourTo(i - 1, state);
if (latexIsLetter(chNext)) {
int match = i + 3;
if (latexLastWordIs(match, styler, "\\end")) {
match++;
if (latexIsTagValid(match, lengthDoc, styler)) {
if (latexLastWordIs(match, styler, "{math}"))
mode = 0;
}
}
state = SCE_L_COMMAND;
} else if (latexIsSpecial(chNext)) {
styler.ColourTo(i + 1, SCE_L_SPECIAL);
i++;
chNext = styler.SafeGetCharAt(i + 1);
} else if (chNext == '\r' || chNext == '\n') {
styler.ColourTo(i, SCE_L_ERROR);
} else {
if (chNext == ')') {
mode = 0;
state = SCE_L_DEFAULT;
}
styler.ColourTo(i + 1, SCE_L_SHORTCMD);
i++;
chNext = styler.SafeGetCharAt(i + 1);
}
break;
case '$' :
styler.ColourTo(i - 1, state);
styler.ColourTo(i, SCE_L_SHORTCMD);
mode = 0;
state = SCE_L_DEFAULT;
break;
case '%' :
styler.ColourTo(i - 1, state);
state = SCE_L_COMMENT;
break;
}
break;
case SCE_L_MATH2 :
switch (ch) {
case '\\' :
styler.ColourTo(i - 1, state);
if (latexIsLetter(chNext)) {
int match = i + 3;
if (latexLastWordIs(match, styler, "\\end")) {
match++;
if (latexIsTagValid(match, lengthDoc, styler)) {
if (latexLastWordIsMathEnv(match, styler))
mode = 0;
}
}
state = SCE_L_COMMAND;
} else if (latexIsSpecial(chNext)) {
styler.ColourTo(i + 1, SCE_L_SPECIAL);
i++;
chNext = styler.SafeGetCharAt(i + 1);
} else if (chNext == '\r' || chNext == '\n') {
styler.ColourTo(i, SCE_L_ERROR);
} else {
if (chNext == ']') {
mode = 0;
state = SCE_L_DEFAULT;
}
styler.ColourTo(i + 1, SCE_L_SHORTCMD);
i++;
chNext = styler.SafeGetCharAt(i + 1);
}
break;
case '$' :
styler.ColourTo(i - 1, state);
if (chNext == '$') {
styler.ColourTo(i + 1, SCE_L_SHORTCMD);
i++;
chNext = styler.SafeGetCharAt(i + 1);
mode = 0;
state = SCE_L_DEFAULT;
} else { // This may not be an error, e.g. \begin{equation}\text{$a$}\end{equation}
styler.ColourTo(i, SCE_L_SHORTCMD);
}
break;
case '%' :
styler.ColourTo(i - 1, state);
state = SCE_L_COMMENT;
break;
}
break;
case SCE_L_COMMENT :
if (ch == '\r' || ch == '\n') {
styler.ColourTo(i - 1, state);
latexStateReset(mode, state);
}
break;
case SCE_L_COMMENT2 :
if (ch == '\\') {
int match = i + 3;
if (latexLastWordIs(match, styler, "\\end")) {
match++;
if (latexIsTagValid(match, lengthDoc, styler)) {
if (latexLastWordIs(match, styler, "{comment}")) {
styler.ColourTo(i - 1, state);
state = SCE_L_COMMAND;
}
}
}
}
break;
case SCE_L_VERBATIM :
if (ch == '\\') {
int match = i + 3;
if (latexLastWordIs(match, styler, "\\end")) {
match++;
if (latexIsTagValid(match, lengthDoc, styler)) {
if (latexLastWordIs(match, styler, "{verbatim}")) {
styler.ColourTo(i - 1, state);
state = SCE_L_COMMAND;
}
}
}
} else if (chNext == chVerbatimDelim) {
styler.ColourTo(i + 1, state);
latexStateReset(mode, state);
chVerbatimDelim = '\0';
i++;
chNext = styler.SafeGetCharAt(i + 1);
} else if (chVerbatimDelim != '\0' && (ch == '\n' || ch == '\r')) {
styler.ColourTo(i, SCE_L_ERROR);
latexStateReset(mode, state);
chVerbatimDelim = '\0';
}
break;
}
}
if (lengthDoc == styler.Length()) truncModes(styler.GetLine(lengthDoc - 1));
styler.ColourTo(lengthDoc - 1, state);
styler.Flush();
}
static int latexFoldSaveToInt(const latexFoldSave &save) {
int sum = 0;
for (int i = 0; i <= save.structLev; ++i)
sum += save.openBegins[i];
return ((sum + save.structLev + SC_FOLDLEVELBASE) & SC_FOLDLEVELNUMBERMASK);
}
// Change folding state while processing a line
// Return the level before the first relevant command
void SCI_METHOD LexerLaTeX::Fold(unsigned int startPos, int length, int, IDocument *pAccess) {
const char *structWords[7] = {"part", "chapter", "section", "subsection",
"subsubsection", "paragraph", "subparagraph"};
Accessor styler(pAccess, &props);
unsigned int endPos = startPos + length;
int curLine = styler.GetLine(startPos);
latexFoldSave save;
getSave(curLine - 1, save);
do {
char ch, buf[16];
int i, j, lev = -1;
bool needFold = false;
for (i = static_cast<int>(startPos); i < static_cast<int>(endPos); ++i) {
ch = styler.SafeGetCharAt(i);
if (ch == '\r' || ch == '\n') break;
if (ch != '\\' || styler.StyleAt(i) != SCE_L_COMMAND) continue;
for (j = 0; j < 15 && i + 1 < static_cast<int>(endPos); ++j, ++i) {
buf[j] = styler.SafeGetCharAt(i + 1);
if (!latexIsLetter(buf[j])) break;
}
buf[j] = '\0';
if (strcmp(buf, "begin") == 0) {
if (lev < 0) lev = latexFoldSaveToInt(save);
++save.openBegins[save.structLev];
needFold = true;
}
else if (strcmp(buf, "end") == 0) {
while (save.structLev > 0 && save.openBegins[save.structLev] == 0)
--save.structLev;
if (lev < 0) lev = latexFoldSaveToInt(save);
if (save.openBegins[save.structLev] > 0) --save.openBegins[save.structLev];
}
else {
for (j = 0; j < 7; ++j)
if (strcmp(buf, structWords[j]) == 0) break;
if (j >= 7) continue;
save.structLev = j; // level before the command
for (j = save.structLev + 1; j < 8; ++j) {
save.openBegins[save.structLev] += save.openBegins[j];
save.openBegins[j] = 0;
}
if (lev < 0) lev = latexFoldSaveToInt(save);
++save.structLev; // level after the command
needFold = true;
}
}
if (lev < 0) lev = latexFoldSaveToInt(save);
if (needFold) lev |= SC_FOLDLEVELHEADERFLAG;
styler.SetLevel(curLine, lev);
setSave(curLine, save);
++curLine;
startPos = styler.LineStart(curLine);
if (static_cast<int>(startPos) == styler.Length()) {
lev = latexFoldSaveToInt(save);
styler.SetLevel(curLine, lev);
setSave(curLine, save);
truncSaves(curLine);
}
} while (startPos < endPos);
styler.Flush();
}
static const char *const emptyWordListDesc[] = {
0
};
LexerModule lmLatex(SCLEX_LATEX, LexerLaTeX::LexerFactoryLaTeX, "latex", emptyWordListDesc);

View File

@ -6,6 +6,12 @@
** Changes by Christoph Dalitz 2003/12/04:
** - added support for Octave
** - Strings can now be included both in single or double quotes
**
** Changes by John Donoghue 2012/04/02
** - added block comment (and nested block comments)
** - added ... displayed as a comment
** - removed unused IsAWord functions
** - added some comments
**/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.
@ -48,14 +54,6 @@ static bool IsOctaveComment(Accessor &styler, int pos, int len) {
return len > 0 && IsOctaveCommentChar(styler[pos]) ;
}
static inline bool IsAWordChar(const int ch) {
return (ch < 0x80) && (isalnum(ch) || ch == '_');
}
static inline bool IsAWordStart(const int ch) {
return (ch < 0x80) && (isalnum(ch) || ch == '_');
}
static void ColouriseMatlabOctaveDoc(
unsigned int startPos, int length, int initStyle,
WordList *keywordlists[], Accessor &styler,
@ -65,12 +63,41 @@ static void ColouriseMatlabOctaveDoc(
styler.StartAt(startPos);
// boolean for when the ' is allowed to be transpose vs the start/end
// of a string
bool transpose = false;
// approximate position of first non space character in a line
int nonSpaceColumn = -1;
// approximate column position of the current character in a line
int column = 0;
// use the line state of each line to store the block comment depth
int curLine = styler.GetLine(startPos);
int commentDepth = curLine > 0 ? styler.GetLineState(curLine-1) : 0;
StyleContext sc(startPos, length, initStyle, styler);
for (; sc.More(); sc.Forward()) {
for (; sc.More(); sc.Forward(), column++) {
if(sc.atLineStart) {
// set the line state to the current commentDepth
curLine = styler.GetLine(sc.currentPos);
styler.SetLineState(curLine, commentDepth);
// reset the column to 0, nonSpace to -1 (not set)
column = 0;
nonSpaceColumn = -1;
}
// save the column position of first non space character in a line
if((nonSpaceColumn == -1) && (! IsASpace(sc.ch)))
{
nonSpaceColumn = column;
}
// check for end of states
if (sc.state == SCE_MATLAB_OPERATOR) {
if (sc.chPrev == '.') {
if (sc.ch == '*' || sc.ch == '/' || sc.ch == '\\' || sc.ch == '^') {
@ -79,6 +106,10 @@ static void ColouriseMatlabOctaveDoc(
} else if (sc.ch == '\'') {
sc.ForwardSetState(SCE_MATLAB_DEFAULT);
transpose = true;
} else if(sc.ch == '.' && sc.chNext == '.') {
// we werent an operator, but a '...'
sc.ChangeState(SCE_MATLAB_COMMENT);
transpose = false;
} else {
sc.SetState(SCE_MATLAB_DEFAULT);
}
@ -121,15 +152,51 @@ static void ColouriseMatlabOctaveDoc(
} else if (sc.ch == '\"') {
sc.ForwardSetState(SCE_MATLAB_DEFAULT);
}
} else if (sc.state == SCE_MATLAB_COMMENT || sc.state == SCE_MATLAB_COMMAND) {
} else if (sc.state == SCE_MATLAB_COMMAND) {
if (sc.atLineEnd) {
sc.SetState(SCE_MATLAB_DEFAULT);
transpose = false;
}
} else if (sc.state == SCE_MATLAB_COMMENT) {
// end or start of a nested a block comment?
if( IsCommentChar(sc.ch) && sc.chNext == '}' && nonSpaceColumn == column) {
if(commentDepth > 0) commentDepth --;
curLine = styler.GetLine(sc.currentPos);
styler.SetLineState(curLine, commentDepth);
sc.Forward();
if (commentDepth == 0) {
sc.ForwardSetState(SCE_D_DEFAULT);
transpose = false;
}
}
else if( IsCommentChar(sc.ch) && sc.chNext == '{' && nonSpaceColumn == column)
{
commentDepth ++;
curLine = styler.GetLine(sc.currentPos);
styler.SetLineState(curLine, commentDepth);
sc.Forward();
transpose = false;
} else if(commentDepth == 0) {
// single line comment
if (sc.atLineEnd || sc.ch == '\r' || sc.ch == '\n') {
sc.SetState(SCE_MATLAB_DEFAULT);
transpose = false;
}
}
}
// check start of a new state
if (sc.state == SCE_MATLAB_DEFAULT) {
if (IsCommentChar(sc.ch)) {
// ncrement depth if we are a block comment
if(sc.chNext == '{' && nonSpaceColumn == column)
commentDepth ++;
curLine = styler.GetLine(sc.currentPos);
styler.SetLineState(curLine, commentDepth);
sc.SetState(SCE_MATLAB_COMMENT);
} else if (sc.ch == '!' && sc.chNext != '=' ) {
sc.SetState(SCE_MATLAB_COMMAND);

View File

@ -1,7 +1,6 @@
// Scintilla source code edit control
/** @file LexOthers.cxx
** Lexers for batch files, diff results, properties files, make files and error lists.
** Also lexer for LaTeX documents.
**/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.
@ -943,6 +942,10 @@ static int RecogniseErrorListLine(const char *lineBuffer, unsigned int lengthLin
strstr(lineBuffer, ".java:")) {
// Java stack back trace
return SCE_ERR_JAVA_STACK;
} else if (strstart(lineBuffer, "In file included from ") ||
strstart(lineBuffer, " from ")) {
// GCC showing include path to following error
return SCE_ERR_GCC_INCLUDED_FROM;
} else {
// Look for one of the following formats:
// GCC: <filename>:<line>:<message>
@ -1109,301 +1112,6 @@ static void ColouriseErrorListDoc(unsigned int startPos, int length, int, WordLi
}
}
static bool latexIsSpecial(int ch) {
return (ch == '#') || (ch == '$') || (ch == '%') || (ch == '&') || (ch == '_') ||
(ch == '{') || (ch == '}') || (ch == ' ');
}
static bool latexIsBlank(int ch) {
return (ch == ' ') || (ch == '\t');
}
static bool latexIsBlankAndNL(int ch) {
return (ch == ' ') || (ch == '\t') || (ch == '\r') || (ch == '\n');
}
static bool latexIsLetter(int ch) {
return isascii(ch) && isalpha(ch);
}
static bool latexIsTagValid(int &i, int l, Accessor &styler) {
while (i < l) {
if (styler.SafeGetCharAt(i) == '{') {
while (i < l) {
i++;
if (styler.SafeGetCharAt(i) == '}') {
return true;
} else if (!latexIsLetter(styler.SafeGetCharAt(i)) &&
styler.SafeGetCharAt(i)!='*') {
return false;
}
}
} else if (!latexIsBlank(styler.SafeGetCharAt(i))) {
return false;
}
i++;
}
return false;
}
static bool latexNextNotBlankIs(int i, int l, Accessor &styler, char needle) {
char ch;
while (i < l) {
ch = styler.SafeGetCharAt(i);
if (!latexIsBlankAndNL(ch) && ch != '*') {
if (ch == needle)
return true;
else
return false;
}
i++;
}
return false;
}
static bool latexLastWordIs(int start, Accessor &styler, const char *needle) {
unsigned int i = 0;
unsigned int l = static_cast<unsigned int>(strlen(needle));
int ini = start-l+1;
char s[32];
while (i < l && i < 32) {
s[i] = styler.SafeGetCharAt(ini + i);
i++;
}
s[i] = '\0';
return (strcmp(s, needle) == 0);
}
static void ColouriseLatexDoc(unsigned int startPos, int length, int initStyle,
WordList *[], Accessor &styler) {
styler.StartAt(startPos);
int state = initStyle;
char chNext = styler.SafeGetCharAt(startPos);
styler.StartSegment(startPos);
int lengthDoc = startPos + length;
char chVerbatimDelim = '\0';
for (int i = startPos; i < lengthDoc; i++) {
char ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
if (styler.IsLeadByte(ch)) {
i++;
chNext = styler.SafeGetCharAt(i + 1);
continue;
}
switch (state) {
case SCE_L_DEFAULT :
switch (ch) {
case '\\' :
styler.ColourTo(i - 1, state);
if (latexIsSpecial(chNext)) {
state = SCE_L_SPECIAL;
} else {
if (latexIsLetter(chNext)) {
state = SCE_L_COMMAND;
} else {
if (chNext == '(' || chNext == '[') {
styler.ColourTo(i-1, state);
styler.ColourTo(i+1, SCE_L_SHORTCMD);
state = SCE_L_MATH;
if (chNext == '[')
state = SCE_L_MATH2;
i++;
chNext = styler.SafeGetCharAt(i+1);
} else {
state = SCE_L_SHORTCMD;
}
}
}
break;
case '$' :
styler.ColourTo(i - 1, state);
state = SCE_L_MATH;
if (chNext == '$') {
state = SCE_L_MATH2;
i++;
chNext = styler.SafeGetCharAt(i + 1);
}
break;
case '%' :
styler.ColourTo(i - 1, state);
state = SCE_L_COMMENT;
break;
}
break;
case SCE_L_ERROR:
styler.ColourTo(i-1, state);
state = SCE_L_DEFAULT;
break;
case SCE_L_SPECIAL:
case SCE_L_SHORTCMD:
styler.ColourTo(i, state);
state = SCE_L_DEFAULT;
break;
case SCE_L_COMMAND :
if (!latexIsLetter(chNext)) {
styler.ColourTo(i, state);
state = SCE_L_DEFAULT;
if (latexNextNotBlankIs(i+1, lengthDoc, styler, '[' )) {
state = SCE_L_CMDOPT;
} else if (latexLastWordIs(i, styler, "\\begin")) {
state = SCE_L_TAG;
} else if (latexLastWordIs(i, styler, "\\end")) {
state = SCE_L_TAG2;
} else if (latexLastWordIs(i, styler, "\\verb") &&
chNext != '*' && chNext != ' ') {
chVerbatimDelim = chNext;
state = SCE_L_VERBATIM;
}
}
break;
case SCE_L_CMDOPT :
if (ch == ']') {
styler.ColourTo(i, state);
state = SCE_L_DEFAULT;
}
break;
case SCE_L_TAG :
if (latexIsTagValid(i, lengthDoc, styler)) {
styler.ColourTo(i, state);
state = SCE_L_DEFAULT;
if (latexLastWordIs(i, styler, "{verbatim}")) {
state = SCE_L_VERBATIM;
} else if (latexLastWordIs(i, styler, "{comment}")) {
state = SCE_L_COMMENT2;
} else if (latexLastWordIs(i, styler, "{math}")) {
state = SCE_L_MATH;
} else if (latexLastWordIs(i, styler, "{displaymath}")) {
state = SCE_L_MATH2;
} else if (latexLastWordIs(i, styler, "{equation}")) {
state = SCE_L_MATH2;
}
} else {
state = SCE_L_ERROR;
styler.ColourTo(i, state);
state = SCE_L_DEFAULT;
}
chNext = styler.SafeGetCharAt(i+1);
break;
case SCE_L_TAG2 :
if (latexIsTagValid(i, lengthDoc, styler)) {
styler.ColourTo(i, state);
state = SCE_L_DEFAULT;
} else {
state = SCE_L_ERROR;
}
chNext = styler.SafeGetCharAt(i+1);
break;
case SCE_L_MATH :
if (ch == '$') {
styler.ColourTo(i, state);
state = SCE_L_DEFAULT;
} else if (ch == '\\' && chNext == ')') {
styler.ColourTo(i-1, state);
styler.ColourTo(i+1, SCE_L_SHORTCMD);
i++;
chNext = styler.SafeGetCharAt(i+1);
state = SCE_L_DEFAULT;
} else if (ch == '\\') {
int match = i + 3;
if (latexLastWordIs(match, styler, "\\end")) {
match++;
if (latexIsTagValid(match, lengthDoc, styler)) {
if (latexLastWordIs(match, styler, "{math}")) {
styler.ColourTo(i-1, state);
state = SCE_L_COMMAND;
}
}
}
}
break;
case SCE_L_MATH2 :
if (ch == '$') {
if (chNext == '$') {
i++;
chNext = styler.SafeGetCharAt(i + 1);
styler.ColourTo(i, state);
state = SCE_L_DEFAULT;
} else {
styler.ColourTo(i, SCE_L_ERROR);
state = SCE_L_DEFAULT;
}
} else if (ch == '\\' && chNext == ']') {
styler.ColourTo(i-1, state);
styler.ColourTo(i+1, SCE_L_SHORTCMD);
i++;
chNext = styler.SafeGetCharAt(i+1);
state = SCE_L_DEFAULT;
} else if (ch == '\\') {
int match = i + 3;
if (latexLastWordIs(match, styler, "\\end")) {
match++;
if (latexIsTagValid(match, lengthDoc, styler)) {
if (latexLastWordIs(match, styler, "{displaymath}")) {
styler.ColourTo(i-1, state);
state = SCE_L_COMMAND;
} else if (latexLastWordIs(match, styler, "{equation}")) {
styler.ColourTo(i-1, state);
state = SCE_L_COMMAND;
}
}
}
}
break;
case SCE_L_COMMENT :
if (ch == '\r' || ch == '\n') {
styler.ColourTo(i - 1, state);
state = SCE_L_DEFAULT;
}
break;
case SCE_L_COMMENT2 :
if (ch == '\\') {
int match = i + 3;
if (latexLastWordIs(match, styler, "\\end")) {
match++;
if (latexIsTagValid(match, lengthDoc, styler)) {
if (latexLastWordIs(match, styler, "{comment}")) {
styler.ColourTo(i-1, state);
state = SCE_L_COMMAND;
}
}
}
}
break;
case SCE_L_VERBATIM :
if (ch == '\\') {
int match = i + 3;
if (latexLastWordIs(match, styler, "\\end")) {
match++;
if (latexIsTagValid(match, lengthDoc, styler)) {
if (latexLastWordIs(match, styler, "{verbatim}")) {
styler.ColourTo(i-1, state);
state = SCE_L_COMMAND;
}
}
}
} else if (chNext == chVerbatimDelim) {
styler.ColourTo(i+1, state);
state = SCE_L_DEFAULT;
chVerbatimDelim = '\0';
} else if (chVerbatimDelim != '\0' && (ch == '\n' || ch == '\r')) {
styler.ColourTo(i, SCE_L_ERROR);
state = SCE_L_DEFAULT;
chVerbatimDelim = '\0';
}
break;
}
}
styler.ColourTo(lengthDoc-1, state);
}
static const char *const batchWordListDesc[] = {
"Internal Commands",
"External Commands",
@ -1429,5 +1137,4 @@ LexerModule lmDiff(SCLEX_DIFF, ColouriseDiffDoc, "diff", FoldDiffDoc, emptyWordL
LexerModule lmProps(SCLEX_PROPERTIES, ColourisePropsDoc, "props", FoldPropsDoc, emptyWordListDesc);
LexerModule lmMake(SCLEX_MAKEFILE, ColouriseMakeDoc, "makefile", 0, emptyWordListDesc);
LexerModule lmErrorList(SCLEX_ERRORLIST, ColouriseErrorListDoc, "errorlist", 0, emptyWordListDesc);
LexerModule lmLatex(SCLEX_LATEX, ColouriseLatexDoc, "latex", 0, emptyWordListDesc);
LexerModule lmNull(SCLEX_NULL, ColouriseNullDoc, "null");

View File

@ -98,6 +98,12 @@ static void ColourisePODoc(unsigned int startPos, int length, int initStyle, Wor
// forward to the first non-white character on the line
bool atLineStart = sc.atLineStart;
if (atLineStart) {
// reset line state if it is set to comment state so empty lines don't get
// comment line state, and the folding code folds comments separately,
// and anyway the styling don't use line state for comments
if (curLineState == SCE_PO_COMMENT)
curLineState = SCE_PO_DEFAULT;
while (sc.More() && ! sc.atLineEnd && isspacechar(sc.ch))
sc.Forward();
}
@ -142,8 +148,66 @@ static void ColourisePODoc(unsigned int startPos, int length, int initStyle, Wor
sc.Complete();
}
static int FindNextNonEmptyLineState(unsigned int startPos, Accessor &styler) {
unsigned int length = styler.Length();
for (unsigned int i = startPos; i < length; i++) {
if (! isspacechar(styler[i])) {
return styler.GetLineState(styler.GetLine(i));
}
}
return 0;
}
static void FoldPODoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) {
if (! styler.GetPropertyInt("fold"))
return;
bool foldCompact = styler.GetPropertyInt("fold.compact") != 0;
bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
unsigned int endPos = startPos + length;
int curLine = styler.GetLine(startPos);
int lineState = styler.GetLineState(curLine);
int nextLineState;
int level = styler.LevelAt(curLine) & SC_FOLDLEVELNUMBERMASK;
int nextLevel;
int visible = 0;
int chNext = styler[startPos];
for (unsigned int i = startPos; i < endPos; i++) {
int ch = chNext;
chNext = styler.SafeGetCharAt(i+1);
if (! isspacechar(ch)) {
visible++;
} else if ((ch == '\r' && chNext != '\n') || ch == '\n' || i+1 >= endPos) {
int lvl = level;
int nextLine = curLine + 1;
nextLineState = styler.GetLineState(nextLine);
if ((lineState != SCE_PO_COMMENT || foldComment) &&
nextLineState == lineState &&
FindNextNonEmptyLineState(i, styler) == lineState)
nextLevel = SC_FOLDLEVELBASE + 1;
else
nextLevel = SC_FOLDLEVELBASE;
if (nextLevel > level)
lvl |= SC_FOLDLEVELHEADERFLAG;
if (visible == 0 && foldCompact)
lvl |= SC_FOLDLEVELWHITEFLAG;
styler.SetLevel(curLine, lvl);
lineState = nextLineState;
curLine = nextLine;
level = nextLevel;
visible = 0;
}
}
}
static const char *const poWordListDesc[] = {
0
};
LexerModule lmPO(SCLEX_PO, ColourisePODoc, "po", 0, poWordListDesc);
LexerModule lmPO(SCLEX_PO, ColourisePODoc, "po", FoldPODoc, poWordListDesc);

View File

@ -119,7 +119,7 @@ static int ClassifyWordRb(unsigned int start, unsigned int end, WordList &keywor
chAttr = SCE_RB_MODULE_NAME;
else if (0 == strcmp(prevWord, "def"))
chAttr = SCE_RB_DEFNAME;
else if (keywords.InList(s) && !followsDot(start - 1, styler)) {
else if (keywords.InList(s) && ((start == 0) || !followsDot(start - 1, styler))) {
if (keywordIsAmbiguous(s)
&& keywordIsModifier(s, start, styler)) {

View File

@ -12,6 +12,8 @@
namespace Scintilla {
#endif
enum EncodingType { enc8bit, encUnicode, encDBCS };
class LexAccessor {
private:
IDocument *pAccess;
@ -25,6 +27,7 @@ private:
int startPos;
int endPos;
int codePage;
enum EncodingType encodingType;
int lenDoc;
int mask;
char styleBuf[bufferSize];
@ -33,6 +36,7 @@ private:
char chWhile;
unsigned int startSeg;
int startPosStyling;
int documentVersion;
void Fill(int position) {
startPos = position - slopSize;
@ -51,9 +55,23 @@ private:
public:
LexAccessor(IDocument *pAccess_) :
pAccess(pAccess_), startPos(extremePosition), endPos(0),
codePage(pAccess->CodePage()), lenDoc(pAccess->Length()),
codePage(pAccess->CodePage()),
encodingType(enc8bit),
lenDoc(pAccess->Length()),
mask(127), validLen(0), chFlags(0), chWhile(0),
startSeg(0), startPosStyling(0) {
startSeg(0), startPosStyling(0),
documentVersion(pAccess->Version()) {
switch (codePage) {
case 65001:
encodingType = encUnicode;
break;
case 932:
case 936:
case 949:
case 950:
case 1361:
encodingType = encDBCS;
}
}
char operator[](int position) {
if (position < startPos || position >= endPos) {
@ -75,7 +93,9 @@ public:
bool IsLeadByte(char ch) {
return pAccess->IsDBCSLeadByte(ch);
}
EncodingType Encoding() const {
return encodingType;
}
bool Match(int pos, const char *s) {
for (int i=0; *s; i++) {
if (*s != SafeGetCharAt(pos+i))
@ -93,6 +113,19 @@ public:
int LineStart(int line) {
return pAccess->LineStart(line);
}
int LineEnd(int line) {
if (documentVersion >= dvLineEnd) {
return (static_cast<IDocumentWithLineEnd *>(pAccess))->LineEnd(line);
} else {
// Old interface means only '\r', '\n' and '\r\n' line ends.
int startNext = pAccess->LineStart(line+1);
char chLineEnd = SafeGetCharAt(startNext-1);
if (chLineEnd == '\n' && (SafeGetCharAt(startNext-2) == '\r'))
return startNext - 2;
else
return startNext - 1;
}
}
int LevelAt(int line) {
return pAccess->GetLevel(line);
}

View File

@ -1,5 +1,5 @@
// Scintilla source code edit control
/** @file LexerSimple.cxx
/** @file LexerBase.cxx
** A simple lexer with no state.
**/
// Copyright 1998-2010 by Neil Hodgson <neilh@scintilla.org>

View File

@ -74,11 +74,9 @@ int LexerModule::GetNumWordLists() const {
}
const char *LexerModule::GetWordListDescription(int index) const {
static const char *emptyStr = "";
assert(index < GetNumWordLists());
if (index >= GetNumWordLists()) {
return emptyStr;
return "";
} else {
return wordListDescriptions[index];
}

View File

@ -19,6 +19,30 @@ static inline int MakeLowerCase(int ch) {
return ch - 'A' + 'a';
}
inline int UnicodeCodePoint(const unsigned char *us) {
if (us[0] < 0xC2) {
return us[0];
} else if (us[0] < 0xE0) {
return ((us[0] & 0x1F) << 6) + (us[1] & 0x3F);
} else if (us[0] < 0xF0) {
return ((us[0] & 0xF) << 12) + ((us[1] & 0x3F) << 6) + (us[2] & 0x3F);
} else if (us[0] < 0xF5) {
return ((us[0] & 0x7) << 18) + ((us[1] & 0x3F) << 12) + ((us[2] & 0x3F) << 6) + (us[3] & 0x3F);
}
return us[0];
}
inline int BytesInUnicodeCodePoint(int codePoint) {
if (codePoint < 0x80)
return 1;
else if (codePoint < 0x800)
return 2;
else if (codePoint < 0x10000)
return 3;
else
return 4;
}
// All languages handled so far can treat all characters >= 0x80 as one class
// which just continues the current token or starts an identifier if in default.
// DBCS treated specially as the second character can be < 0x80 and hence
@ -26,23 +50,42 @@ static inline int MakeLowerCase(int ch) {
class StyleContext {
LexAccessor &styler;
unsigned int endPos;
unsigned int lengthDocument;
StyleContext &operator=(const StyleContext &);
void GetNextChar(unsigned int pos) {
chNext = static_cast<unsigned char>(styler.SafeGetCharAt(pos+1));
if (styler.IsLeadByte(static_cast<char>(chNext))) {
chNext = chNext << 8;
chNext |= static_cast<unsigned char>(styler.SafeGetCharAt(pos+2));
chNext = static_cast<unsigned char>(styler.SafeGetCharAt(pos+1, 0));
if (styler.Encoding() == encUnicode) {
if (chNext >= 0x80) {
unsigned char bytes[4] = { static_cast<unsigned char>(chNext), 0, 0, 0 };
for (int trail=1; trail<3; trail++) {
bytes[trail] = static_cast<unsigned char>(styler.SafeGetCharAt(pos+1+trail, 0));
if (!((bytes[trail] >= 0x80) && (bytes[trail] < 0xc0))) {
bytes[trail] = 0;
break;
}
}
chNext = UnicodeCodePoint(bytes);
}
} else if (styler.Encoding() == encDBCS) {
if (styler.IsLeadByte(static_cast<char>(chNext))) {
chNext = chNext << 8;
chNext |= static_cast<unsigned char>(styler.SafeGetCharAt(pos+2, 0));
}
}
// 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.
atLineEnd = (ch == '\r' && chNext != '\n') ||
(ch == '\n') ||
(currentPos >= endPos);
if (lineStartNext < styler.Length())
atLineEnd = static_cast<int>(pos) >= (lineStartNext-1);
else // Last line
atLineEnd = static_cast<int>(pos) >= lineStartNext;
}
public:
unsigned int currentPos;
int currentLine;
int lineStartNext;
bool atLineStart;
bool atLineEnd;
int state;
@ -55,6 +98,8 @@ public:
styler(styler_),
endPos(startPos + length),
currentPos(startPos),
currentLine(-1),
lineStartNext(-1),
atLineEnd(false),
state(initStyle & chMask), // Mask off all bits which aren't in the chMask.
chPrev(0),
@ -62,18 +107,30 @@ public:
chNext(0) {
styler.StartAt(startPos, chMask);
styler.StartSegment(startPos);
atLineStart = static_cast<unsigned int>(styler.LineStart(styler.GetLine(startPos))) == startPos;
currentLine = styler.GetLine(startPos);
lineStartNext = styler.LineStart(currentLine+1);
lengthDocument = static_cast<unsigned int>(styler.Length());
if (endPos == lengthDocument)
endPos++;
atLineStart = static_cast<unsigned int>(styler.LineStart(currentLine)) == startPos;
unsigned int pos = currentPos;
ch = static_cast<unsigned char>(styler.SafeGetCharAt(pos));
if (styler.IsLeadByte(static_cast<char>(ch))) {
pos++;
ch = ch << 8;
ch |= static_cast<unsigned char>(styler.SafeGetCharAt(pos));
ch = static_cast<unsigned char>(styler.SafeGetCharAt(pos, 0));
if (styler.Encoding() == encUnicode) {
// Get the current char
GetNextChar(pos-1);
ch = chNext;
pos += BytesInUnicodeCodePoint(ch) - 1;
} else if (styler.Encoding() == encDBCS) {
if (styler.IsLeadByte(static_cast<char>(ch))) {
pos++;
ch = ch << 8;
ch |= static_cast<unsigned char>(styler.SafeGetCharAt(pos, 0));
}
}
GetNextChar(pos);
}
void Complete() {
styler.ColourTo(currentPos - 1, state);
styler.ColourTo(currentPos - ((currentPos > lengthDocument) ? 2 : 1), state);
styler.Flush();
}
bool More() const {
@ -82,12 +139,28 @@ public:
void Forward() {
if (currentPos < endPos) {
atLineStart = atLineEnd;
if (atLineStart) {
currentLine++;
lineStartNext = styler.LineStart(currentLine+1);
}
chPrev = ch;
currentPos++;
if (ch >= 0x100)
if (styler.Encoding() == encUnicode) {
currentPos += BytesInUnicodeCodePoint(ch);
} else if (styler.Encoding() == encDBCS) {
currentPos++;
if (ch >= 0x100)
currentPos++;
} else {
currentPos++;
}
ch = chNext;
GetNextChar(currentPos + ((ch >= 0x100) ? 1 : 0));
if (styler.Encoding() == encUnicode) {
GetNextChar(currentPos + BytesInUnicodeCodePoint(ch)-1);
} else if (styler.Encoding() == encDBCS) {
GetNextChar(currentPos + ((ch >= 0x100) ? 1 : 0));
} else {
GetNextChar(currentPos);
}
} else {
atLineStart = false;
chPrev = ' ';
@ -105,19 +178,19 @@ public:
state = state_;
}
void SetState(int state_) {
styler.ColourTo(currentPos - 1, state);
styler.ColourTo(currentPos - ((currentPos > lengthDocument) ? 2 : 1), state);
state = state_;
}
void ForwardSetState(int state_) {
Forward();
styler.ColourTo(currentPos - 1, state);
styler.ColourTo(currentPos - ((currentPos > lengthDocument) ? 2 : 1), state);
state = state_;
}
int LengthCurrent() {
return currentPos - styler.GetStartSegment();
}
int GetRelative(int n) {
return static_cast<unsigned char>(styler.SafeGetCharAt(currentPos+n));
return static_cast<unsigned char>(styler.SafeGetCharAt(currentPos+n, 0));
}
bool Match(char ch0) const {
return ch == static_cast<unsigned char>(ch0);
@ -135,7 +208,7 @@ public:
return false;
s++;
for (int n=2; *s; n++) {
if (*s != styler.SafeGetCharAt(currentPos+n))
if (*s != styler.SafeGetCharAt(currentPos+n, 0))
return false;
s++;
}
@ -150,7 +223,7 @@ public:
s++;
for (int n=2; *s; n++) {
if (static_cast<unsigned char>(*s) !=
MakeLowerCase(static_cast<unsigned char>(styler.SafeGetCharAt(currentPos+n))))
MakeLowerCase(static_cast<unsigned char>(styler.SafeGetCharAt(currentPos+n, 0))))
return false;
s++;
}

View File

@ -0,0 +1,162 @@
// Scintilla source code edit control
/** @file SubStyles.h
** Manage substyles for a lexer.
**/
// Copyright 2012 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.
#ifndef SUBSTYLES_H
#define SUBSTYLES_H
#ifdef SCI_NAMESPACE
namespace Scintilla {
#endif
class WordClassifier {
int firstStyle;
int lenStyles;
std::map<std::string, int> wordToStyle;
public:
WordClassifier() : firstStyle(0), lenStyles(0) {
}
void Allocate(int firstStyle_, int lenStyles_) {
firstStyle = firstStyle_;
lenStyles = lenStyles_;
wordToStyle.clear();
}
int Start() const {
return firstStyle;
}
int Length() const {
return lenStyles;
}
void Clear() {
firstStyle = 0;
lenStyles = 0;
wordToStyle.clear();
}
int ValueFor(const std::string &s) const {
std::map<std::string, int>::const_iterator it = wordToStyle.find(s);
if (it != wordToStyle.end())
return it->second;
else
return -1;
}
bool IncludesStyle(int style) const {
return (style >= firstStyle) && (style < (firstStyle + lenStyles));
}
void SetIdentifiers(int style, const char *identifiers) {
while (*identifiers) {
const char *cpSpace = identifiers;
while (*cpSpace && *cpSpace != ' ')
cpSpace++;
std::string word(identifiers, cpSpace - identifiers);
wordToStyle[word] = style;
identifiers = cpSpace;
if (*identifiers)
identifiers++;
}
}
};
class SubStyles {
int classifications;
const char *baseStyles;
int styleFirst;
int stylesAvailable;
int secondaryDistance;
int allocated;
std::vector<WordClassifier> classifiers;
int BlockFromBaseStyle(int baseStyle) const {
for (int b=0; b < classifications; b++) {
if (baseStyle == baseStyles[b])
return b;
}
return -1;
}
int BlockFromStyle(int style) const {
int b = 0;
for (std::vector<WordClassifier>::const_iterator it=classifiers.begin(); it != classifiers.end(); ++it) {
if (it->IncludesStyle(style))
return b;
b++;
}
return -1;
}
public:
SubStyles(const char *baseStyles_, int styleFirst_, int stylesAvailable_, int secondaryDistance_) :
classifications(0),
baseStyles(baseStyles_),
styleFirst(styleFirst_),
stylesAvailable(stylesAvailable_),
secondaryDistance(secondaryDistance_),
allocated(0) {
while (baseStyles[classifications]) {
classifications++;
classifiers.push_back(WordClassifier());
}
}
int Allocate(int styleBase, int numberStyles) {
int block = BlockFromBaseStyle(styleBase);
if (block >= 0) {
if ((allocated + numberStyles) > stylesAvailable)
return -1;
int startBlock = styleFirst + allocated;
allocated += numberStyles;
classifiers[block].Allocate(startBlock, numberStyles);
return startBlock;
} else {
return -1;
}
}
int Start(int styleBase) {
int block = BlockFromBaseStyle(styleBase);
return (block >= 0) ? classifiers[block].Start() : -1;
}
int Length(int styleBase) {
int block = BlockFromBaseStyle(styleBase);
return (block >= 0) ? classifiers[block].Length() : 0;
}
int DistanceToSecondaryStyles() const {
return secondaryDistance;
}
void SetIdentifiers(int style, const char *identifiers) {
int block = BlockFromStyle(style);
if (block >= 0)
classifiers[block].SetIdentifiers(style, identifiers);
}
void Free() {
allocated = 0;
for (std::vector<WordClassifier>::iterator it=classifiers.begin(); it != classifiers.end(); ++it)
it->Clear();
}
const WordClassifier &Classifier(int baseStyle) const {
return classifiers[BlockFromBaseStyle(baseStyle)];
}
};
#ifdef SCI_NAMESPACE
}
#endif
#endif

View File

@ -89,6 +89,7 @@ LexVerilog.o \
LexMarkdown.o \
LexMatlab.o \
LexD.o \
LexLaTeX.o \
LexLisp.o \
LexLua.o \
LexHaskell.o \

View File

@ -10,7 +10,9 @@
#include <stdio.h>
#include <assert.h>
#include <algorithm>
#include <string>
#include <vector>
#include "Platform.h"
@ -36,7 +38,8 @@ AutoComplete::AutoComplete() :
dropRestOfWord(false),
ignoreCaseBehaviour(SC_CASEINSENSITIVEBEHAVIOUR_RESPECTCASE),
widthLBDefault(100),
heightLBDefault(100) {
heightLBDefault(100),
autoSort(SC_ORDER_PRESORTED) {
lb = ListBox::Allocate();
stopChars[0] = '\0';
fillUpChars[0] = '\0';
@ -101,8 +104,91 @@ char AutoComplete::GetTypesep() const {
return typesep;
}
struct Sorter {
AutoComplete *ac;
const char *list;
std::vector<int> indices;
Sorter(AutoComplete *ac_, const char *list_) : ac(ac_), list(list_) {
int i = 0;
while (list[i]) {
indices.push_back(i); // word start
while (list[i] != ac->GetTypesep() && list[i] != ac->GetSeparator() && list[i])
++i;
indices.push_back(i); // word end
if (list[i] == ac->GetTypesep()) {
while (list[i] != ac->GetSeparator() && list[i])
++i;
}
if (list[i] == ac->GetSeparator()) {
++i;
// preserve trailing separator as blank entry
if (!list[i]) {
indices.push_back(i);
indices.push_back(i);
}
}
}
indices.push_back(i); // index of last position
}
bool operator()(int a, int b) {
int lenA = indices[a * 2 + 1] - indices[a * 2];
int lenB = indices[b * 2 + 1] - indices[b * 2];
int len = std::min(lenA, lenB);
int cmp;
if (ac->ignoreCase)
cmp = CompareNCaseInsensitive(list + indices[a * 2], list + indices[b * 2], len);
else
cmp = strncmp(list + indices[a * 2], list + indices[b * 2], len);
if (cmp == 0)
cmp = lenA - lenB;
return cmp < 0;
}
};
void AutoComplete::SetList(const char *list) {
lb->SetList(list, separator, typesep);
if (autoSort == SC_ORDER_PRESORTED) {
lb->SetList(list, separator, typesep);
sortMatrix.clear();
for (int i = 0; i < lb->Length(); ++i)
sortMatrix.push_back(i);
return;
}
Sorter IndexSort(this, list);
sortMatrix.clear();
for (int i = 0; i < (int)IndexSort.indices.size() / 2; ++i)
sortMatrix.push_back(i);
std::sort(sortMatrix.begin(), sortMatrix.end(), IndexSort);
if (autoSort == SC_ORDER_CUSTOM || sortMatrix.size() < 2) {
lb->SetList(list, separator, typesep);
PLATFORM_ASSERT(lb->Length() == static_cast<int>(sortMatrix.size()));
return;
}
std::string sortedList;
char item[maxItemLen];
for (size_t i = 0; i < sortMatrix.size(); ++i) {
int wordLen = IndexSort.indices[sortMatrix[i] * 2 + 2] - IndexSort.indices[sortMatrix[i] * 2];
strncpy(item, list + IndexSort.indices[sortMatrix[i] * 2], wordLen);
if ((i+1) == sortMatrix.size()) {
// Last item so remove separator if present
if ((wordLen > 0) && (item[wordLen-1] == separator))
wordLen--;
} else {
// Item before last needs a separator
if ((wordLen == 0) || (item[wordLen-1] != separator)) {
item[wordLen] = separator;
wordLen++;
}
}
item[wordLen] = '\0';
sortedList += item;
}
for (int i = 0; i < (int)sortMatrix.size(); ++i)
sortMatrix[i] = i;
lb->SetList(sortedList.c_str(), separator, typesep);
}
int AutoComplete::GetSelection() const {
@ -149,7 +235,7 @@ void AutoComplete::Select(const char *word) {
while ((start <= end) && (location == -1)) { // Binary searching loop
int pivot = (start + end) / 2;
char item[maxItemLen];
lb->GetValue(pivot, item, maxItemLen);
lb->GetValue(sortMatrix[pivot], item, maxItemLen);
int cond;
if (ignoreCase)
cond = CompareNCaseInsensitive(word, item, lenWord);
@ -158,7 +244,7 @@ void AutoComplete::Select(const char *word) {
if (!cond) {
// Find first match
while (pivot > start) {
lb->GetValue(pivot-1, item, maxItemLen);
lb->GetValue(sortMatrix[pivot-1], item, maxItemLen);
if (ignoreCase)
cond = CompareNCaseInsensitive(word, item, lenWord);
else
@ -172,7 +258,7 @@ void AutoComplete::Select(const char *word) {
&& ignoreCaseBehaviour == SC_CASEINSENSITIVEBEHAVIOUR_RESPECTCASE) {
// Check for exact-case match
for (; pivot <= end; pivot++) {
lb->GetValue(pivot, item, maxItemLen);
lb->GetValue(sortMatrix[pivot], item, maxItemLen);
if (!strncmp(word, item, lenWord)) {
location = pivot;
break;
@ -187,9 +273,24 @@ void AutoComplete::Select(const char *word) {
start = pivot + 1;
}
}
if (location == -1 && autoHide)
Cancel();
else
lb->Select(location);
if (location == -1) {
if (autoHide)
Cancel();
else
lb->Select(-1);
} else {
if (autoSort == SC_ORDER_CUSTOM) {
// Check for a logically earlier match
char item[maxItemLen];
for (int i = location + 1; i <= end; ++i) {
lb->GetValue(sortMatrix[i], item, maxItemLen);
if (CompareNCaseInsensitive(word, item, lenWord))
break;
if (sortMatrix[i] < sortMatrix[location] && !strncmp(word, item, lenWord))
location = i;
}
}
lb->Select(sortMatrix[location]);
}
}

View File

@ -21,6 +21,7 @@ class AutoComplete {
char separator;
char typesep; // Type seperator
enum { maxItemLen=1000 };
std::vector<int> sortMatrix;
public:
@ -36,6 +37,11 @@ public:
unsigned int ignoreCaseBehaviour;
int widthLBDefault;
int heightLBDefault;
/** SC_ORDER_PRESORTED: Assume the list is presorted; selection will fail if it is not alphabetical<br />
* SC_ORDER_PERFORMSORT: Sort the list alphabetically; start up performance cost for sorting<br />
* SC_ORDER_CUSTOM: Handle non-alphabetical entries; start up performance cost for generating a sorted lookup table
*/
int autoSort;
AutoComplete();
~AutoComplete();

View File

@ -16,6 +16,7 @@
#include "SplitVector.h"
#include "Partitioning.h"
#include "CellBuffer.h"
#include "UniConversion.h"
#ifdef SCI_NAMESPACE
using namespace Scintilla;
@ -331,6 +332,7 @@ void UndoHistory::CompletedRedoStep() {
CellBuffer::CellBuffer() {
readOnly = false;
utf8LineEnds = 0;
collectingUndo = true;
}
@ -458,6 +460,13 @@ void CellBuffer::Allocate(int newSize) {
style.ReAllocate(newSize);
}
void CellBuffer::SetLineEndTypes(int utf8LineEnds_) {
if (utf8LineEnds != utf8LineEnds_) {
utf8LineEnds = utf8LineEnds_;
ResetLineEnds();
}
}
void CellBuffer::SetPerLine(PerLine *pl) {
lv.SetPerLine(pl);
}
@ -501,11 +510,63 @@ void CellBuffer::RemoveLine(int line) {
lv.RemoveLine(line);
}
bool CellBuffer::UTF8LineEndOverlaps(int position) const {
unsigned char bytes[] = {
static_cast<unsigned char>(substance.ValueAt(position-2)),
static_cast<unsigned char>(substance.ValueAt(position-1)),
static_cast<unsigned char>(substance.ValueAt(position)),
static_cast<unsigned char>(substance.ValueAt(position+1)),
};
return UTF8IsSeparator(bytes) || UTF8IsSeparator(bytes+1) || UTF8IsNEL(bytes+1);
}
void CellBuffer::ResetLineEnds() {
// Reinitialize line data -- too much work to preserve
lv.Init();
int position = 0;
int length = Length();
int lineInsert = 1;
bool atLineStart = true;
lv.InsertText(lineInsert-1, length);
unsigned char chBeforePrev = 0;
unsigned char chPrev = 0;
for (int i = 0; i < length; i++) {
unsigned char ch = substance.ValueAt(position + i);
if (ch == '\r') {
InsertLine(lineInsert, (position + i) + 1, atLineStart);
lineInsert++;
} else if (ch == '\n') {
if (chPrev == '\r') {
// Patch up what was end of line
lv.SetLineStart(lineInsert - 1, (position + i) + 1);
} else {
InsertLine(lineInsert, (position + i) + 1, atLineStart);
lineInsert++;
}
} else if (utf8LineEnds) {
unsigned char back3[3] = {chBeforePrev, chPrev, ch};
if (UTF8IsSeparator(back3) || UTF8IsNEL(back3+1)) {
InsertLine(lineInsert, (position + i) + 1, atLineStart);
lineInsert++;
}
}
chBeforePrev = chPrev;
chPrev = ch;
}
}
void CellBuffer::BasicInsertString(int position, const char *s, int insertLength) {
if (insertLength == 0)
return;
PLATFORM_ASSERT(insertLength > 0);
unsigned char chAfter = substance.ValueAt(position);
bool breakingUTF8LineEnd = false;
if (utf8LineEnds && UTF8IsTrailByte(chAfter)) {
breakingUTF8LineEnd = UTF8LineEndOverlaps(position);
}
substance.InsertFromArray(position, s, 0, insertLength);
style.InsertValue(position, insertLength, 0);
@ -513,14 +574,17 @@ void CellBuffer::BasicInsertString(int position, const char *s, int insertLength
bool atLineStart = lv.LineStart(lineInsert-1) == position;
// Point all the lines after the insertion point further along in the buffer
lv.InsertText(lineInsert-1, insertLength);
char chPrev = substance.ValueAt(position - 1);
char chAfter = substance.ValueAt(position + insertLength);
unsigned char chBeforePrev = substance.ValueAt(position - 2);
unsigned char chPrev = substance.ValueAt(position - 1);
if (chPrev == '\r' && chAfter == '\n') {
// Splitting up a crlf pair at position
InsertLine(lineInsert, position, false);
lineInsert++;
}
char ch = ' ';
if (breakingUTF8LineEnd) {
RemoveLine(lineInsert);
}
unsigned char ch = ' ';
for (int i = 0; i < insertLength; i++) {
ch = s[i];
if (ch == '\r') {
@ -534,7 +598,14 @@ void CellBuffer::BasicInsertString(int position, const char *s, int insertLength
InsertLine(lineInsert, (position + i) + 1, atLineStart);
lineInsert++;
}
} else if (utf8LineEnds) {
unsigned char back3[3] = {chBeforePrev, chPrev, ch};
if (UTF8IsSeparator(back3) || UTF8IsNEL(back3+1)) {
InsertLine(lineInsert, (position + i) + 1, atLineStart);
lineInsert++;
}
}
chBeforePrev = chPrev;
chPrev = ch;
}
// Joining two lines where last insertion is cr and following substance starts with lf
@ -543,6 +614,22 @@ void CellBuffer::BasicInsertString(int position, const char *s, int insertLength
// End of line already in buffer so drop the newly created one
RemoveLine(lineInsert - 1);
}
} else if (utf8LineEnds && !UTF8IsAscii(chAfter)) {
// May have end of UTF-8 line end in buffer and start in insertion
for (int j = 0; j < UTF8SeparatorLength-1; j++) {
unsigned char chAt = substance.ValueAt(position + insertLength + j);
unsigned char back3[3] = {chBeforePrev, chPrev, chAt};
if (UTF8IsSeparator(back3)) {
InsertLine(lineInsert, (position + insertLength + j) + 1, atLineStart);
lineInsert++;
}
if ((j == 0) && UTF8IsNEL(back3+1)) {
InsertLine(lineInsert, (position + insertLength + j) + 1, atLineStart);
lineInsert++;
}
chBeforePrev = chPrev;
chPrev = chAt;
}
}
}
@ -560,9 +647,9 @@ void CellBuffer::BasicDeleteChars(int position, int deleteLength) {
int lineRemove = lv.LineFromPosition(position) + 1;
lv.InsertText(lineRemove-1, - (deleteLength));
char chPrev = substance.ValueAt(position - 1);
char chBefore = chPrev;
char chNext = substance.ValueAt(position);
unsigned char chPrev = substance.ValueAt(position - 1);
unsigned char chBefore = chPrev;
unsigned char chNext = substance.ValueAt(position);
bool ignoreNL = false;
if (chPrev == '\r' && chNext == '\n') {
// Move back one
@ -570,8 +657,13 @@ void CellBuffer::BasicDeleteChars(int position, int deleteLength) {
lineRemove++;
ignoreNL = true; // First \n is not real deletion
}
if (utf8LineEnds && UTF8IsTrailByte(chNext)) {
if (UTF8LineEndOverlaps(position)) {
RemoveLine(lineRemove);
}
}
char ch = chNext;
unsigned char ch = chNext;
for (int i = 0; i < deleteLength; i++) {
chNext = substance.ValueAt(position + i + 1);
if (ch == '\r') {
@ -584,6 +676,14 @@ void CellBuffer::BasicDeleteChars(int position, int deleteLength) {
} else {
RemoveLine(lineRemove);
}
} else if (utf8LineEnds) {
if (!UTF8IsAscii(ch)) {
unsigned char next3[3] = {ch, chNext,
static_cast<unsigned char>(substance.ValueAt(position + i + 2))};
if (UTF8IsSeparator(next3) || UTF8IsNEL(next3)) {
RemoveLine(lineRemove);
}
}
}
ch = chNext;

View File

@ -98,6 +98,9 @@ class UndoHistory {
void EnsureUndoRoom();
// Private so UndoHistory objects can not be copied
UndoHistory(const UndoHistory &);
public:
UndoHistory();
~UndoHistory();
@ -136,12 +139,15 @@ private:
SplitVector<char> substance;
SplitVector<char> style;
bool readOnly;
int utf8LineEnds;
bool collectingUndo;
UndoHistory uh;
LineVector lv;
bool UTF8LineEndOverlaps(int position) const;
void ResetLineEnds();
/// Actions without undo
void BasicInsertString(int position, const char *s, int insertLength);
void BasicDeleteChars(int position, int deleteLength);
@ -162,6 +168,8 @@ public:
int Length() const;
void Allocate(int newSize);
int GetLineEndTypes() const { return utf8LineEnds; }
void SetLineEndTypes(int utf8LineEnds_);
void SetPerLine(PerLine *pl);
int Lines() const;
int LineStart(int line) const;

View File

@ -66,7 +66,7 @@ int ContractionState::LinesDisplayed() const {
int ContractionState::DisplayFromDoc(int lineDoc) const {
if (OneToOne()) {
return lineDoc;
return (lineDoc <= linesInDocument) ? lineDoc : linesInDocument;
} else {
if (lineDoc > displayLines->Partitions())
lineDoc = displayLines->Partitions();

View File

@ -67,6 +67,17 @@ void LexInterface::Colourise(int start, int end) {
}
}
int LexInterface::LineEndTypesSupported() {
if (instance) {
int interfaceVersion = instance->Version();
if (interfaceVersion >= lvSubStyles) {
ILexerWithSubStyles *ssinstance = static_cast<ILexerWithSubStyles *>(instance);
return ssinstance->LineEndTypesSupported();
}
}
return 0;
}
Document::Document() {
refCount = 0;
pcf = NULL;
@ -76,6 +87,7 @@ Document::Document() {
eolMode = SC_EOL_LF;
#endif
dbcsCodePage = 0;
lineEndBitSet = SC_LINE_END_TYPE_DEFAULT;
stylingBits = 5;
stylingBitsMask = 0x1F;
stylingMask = 0;
@ -135,16 +147,40 @@ void Document::Init() {
}
}
int Document::LineEndTypesSupported() const {
if ((SC_CP_UTF8 == dbcsCodePage) && pli)
return pli->LineEndTypesSupported();
else
return 0;
}
bool Document::SetDBCSCodePage(int dbcsCodePage_) {
if (dbcsCodePage != dbcsCodePage_) {
dbcsCodePage = dbcsCodePage_;
SetCaseFolder(NULL);
cb.SetLineEndTypes(lineEndBitSet & LineEndTypesSupported());
return true;
} else {
return false;
}
}
bool Document::SetLineEndTypesAllowed(int lineEndBitSet_) {
if (lineEndBitSet != lineEndBitSet_) {
lineEndBitSet = lineEndBitSet_;
int lineEndBitSetActive = lineEndBitSet & LineEndTypesSupported();
if (lineEndBitSetActive != cb.GetLineEndTypes()) {
ModifiedAt(0);
cb.SetLineEndTypes(lineEndBitSetActive);
return true;
} else {
return false;
}
} else {
return false;
}
}
void Document::InsertLine(int line) {
for (int j=0; j<ldSize; j++) {
if (perLineData[j])
@ -245,11 +281,25 @@ int SCI_METHOD Document::LineStart(int line) const {
return cb.LineStart(line);
}
int Document::LineEnd(int line) const {
int SCI_METHOD Document::LineEnd(int line) const {
if (line == LinesTotal() - 1) {
return LineStart(line + 1);
} else {
int position = LineStart(line + 1) - 1;
int position = LineStart(line + 1);
if (SC_CP_UTF8 == dbcsCodePage) {
unsigned char bytes[] = {
static_cast<unsigned char>(cb.CharAt(position-3)),
static_cast<unsigned char>(cb.CharAt(position-2)),
static_cast<unsigned char>(cb.CharAt(position-1)),
};
if (UTF8IsSeparator(bytes)) {
return position - UTF8SeparatorLength;
}
if (UTF8IsNEL(bytes+1)) {
return position - UTF8NELLength;
}
}
position--; // Back over CR or LF
// When line terminator is CR+LF, may need to go back one more
if ((position > LineStart(line)) && (cb.CharAt(position - 1) == '\r')) {
position--;
@ -277,6 +327,10 @@ bool Document::IsLineEndPosition(int position) const {
return LineEnd(LineFromPosition(position)) == position;
}
bool Document::IsPositionInLineEnd(int position) const {
return position >= LineEnd(LineFromPosition(position));
}
int Document::VCHomePosition(int position) const {
int line = LineFromPosition(position);
int startPosition = LineStart(line);

View File

@ -186,6 +186,7 @@ public:
virtual ~LexInterface() {
}
void Colourise(int start, int end);
int LineEndTypesSupported();
bool UseContainerLexing() const {
return instance == 0;
}
@ -193,7 +194,7 @@ public:
/**
*/
class Document : PerLine, public IDocument, public ILoader {
class Document : PerLine, public IDocumentWithLineEnd, public ILoader {
public:
/** Used to pair watcher pointer with user data. */
@ -240,6 +241,7 @@ public:
int eolMode;
/// Can also be SC_CP_UTF8 to enable UTF-8 mode
int dbcsCodePage;
int lineEndBitSet;
int tabInChars;
int indentInChars;
int actualIndentInChars;
@ -256,12 +258,16 @@ public:
int SCI_METHOD Release();
virtual void Init();
int LineEndTypesSupported() const;
bool SetDBCSCodePage(int dbcsCodePage_);
int GetLineEndTypesAllowed() { return cb.GetLineEndTypes(); }
bool SetLineEndTypesAllowed(int lineEndBitSet_);
int GetLineEndTypesActive() { return cb.GetLineEndTypes(); }
virtual void InsertLine(int line);
virtual void RemoveLine(int line);
int SCI_METHOD Version() const {
return dvOriginal;
return dvLineEnd;
}
void SCI_METHOD SetErrorStatus(int status);
@ -338,9 +344,10 @@ public:
void DeleteAllMarks(int markerNum);
int LineFromHandle(int markerHandle);
int SCI_METHOD LineStart(int line) const;
int LineEnd(int line) const;
int SCI_METHOD LineEnd(int line) const;
int LineEndPosition(int position) const;
bool IsLineEndPosition(int position) const;
bool IsPositionInLineEnd(int position) const;
int VCHomePosition(int position) const;
int SCI_METHOD SetLevel(int line, int level);

View File

@ -9,6 +9,7 @@
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <assert.h>
#include <string>
@ -174,6 +175,7 @@ Editor::Editor() {
pixmapLine = 0;
pixmapSelMargin = 0;
pixmapSelPattern = 0;
pixmapSelPatternOffset1 = 0;
pixmapIndentGuide = 0;
pixmapIndentGuideHighlight = 0;
@ -249,6 +251,8 @@ void Editor::DropGraphics(bool freeObjects) {
pixmapSelMargin = 0;
delete pixmapSelPattern;
pixmapSelPattern = 0;
delete pixmapSelPatternOffset1;
pixmapSelPatternOffset1 = 0;
delete pixmapIndentGuide;
pixmapIndentGuide = 0;
delete pixmapIndentGuideHighlight;
@ -260,6 +264,8 @@ void Editor::DropGraphics(bool freeObjects) {
pixmapSelMargin->Release();
if (pixmapSelPattern)
pixmapSelPattern->Release();
if (pixmapSelPatternOffset1)
pixmapSelPatternOffset1->Release();
if (pixmapIndentGuide)
pixmapIndentGuide->Release();
if (pixmapIndentGuideHighlight)
@ -274,6 +280,8 @@ void Editor::AllocateGraphics() {
pixmapSelMargin = Surface::Allocate(technology);
if (!pixmapSelPattern)
pixmapSelPattern = Surface::Allocate(technology);
if (!pixmapSelPatternOffset1)
pixmapSelPatternOffset1 = Surface::Allocate(technology);
if (!pixmapIndentGuide)
pixmapIndentGuide = Surface::Allocate(technology);
if (!pixmapIndentGuideHighlight)
@ -307,13 +315,37 @@ void Editor::RefreshStyleData() {
}
}
Point Editor::GetVisibleOriginInMain() {
return Point(0,0);
}
Point Editor::DocumentPointFromView(Point ptView) {
Point ptDocument = ptView;
if (wMargin.GetID()) {
Point ptOrigin = GetVisibleOriginInMain();
ptDocument.x += ptOrigin.x;
ptDocument.y += ptOrigin.y;
} else {
ptDocument.x += xOffset;
ptDocument.y += topLine * vs.lineHeight;
}
return ptDocument;
}
int Editor::TopLineOfMain() {
if (wMargin.GetID())
return 0;
else
return topLine;
}
PRectangle Editor::GetClientRectangle() {
return wMain.GetClientPosition();
}
PRectangle Editor::GetTextRectangle() {
PRectangle rc = GetClientRectangle();
rc.left += vs.fixedColumnWidth;
rc.left += vs.textStart;
rc.right -= vs.rightMarginWidth;
return rc;
}
@ -436,7 +468,7 @@ Point Editor::LocationFromPosition(SelectionPosition pos) {
pt.y += vs.lineHeight;
}
}
pt.x += vs.fixedColumnWidth - xOffset;
pt.x += vs.textStart - xOffset;
}
pt.x += pos.VirtualSpace() * vs.styles[ll->EndLineStyle()].spaceWidth;
return pt;
@ -448,12 +480,12 @@ Point Editor::LocationFromPosition(int pos) {
int Editor::XFromPosition(int pos) {
Point pt = LocationFromPosition(pos);
return pt.x - vs.fixedColumnWidth + xOffset;
return pt.x - vs.textStart + xOffset;
}
int Editor::XFromPosition(SelectionPosition sp) {
Point pt = LocationFromPosition(sp);
return pt.x - vs.fixedColumnWidth + xOffset;
return pt.x - vs.textStart + xOffset;
}
int Editor::LineFromLocation(Point pt) {
@ -461,7 +493,7 @@ int Editor::LineFromLocation(Point pt) {
}
void Editor::SetTopLine(int topLineNew) {
if (topLine != topLineNew) {
if ((topLine != topLineNew) && (topLineNew >= 0)) {
topLine = topLineNew;
ContainerNeedsUpdate(SC_UPDATE_V_SCROLL);
}
@ -474,16 +506,14 @@ SelectionPosition Editor::SPositionFromLocation(Point pt, bool canReturnInvalid,
PRectangle rcClient = GetTextRectangle();
if (!rcClient.Contains(pt))
return SelectionPosition(INVALID_POSITION);
if (pt.x < vs.fixedColumnWidth)
if (pt.x < vs.textStart)
return SelectionPosition(INVALID_POSITION);
if (pt.y < 0)
return SelectionPosition(INVALID_POSITION);
}
pt.x = pt.x - vs.fixedColumnWidth + xOffset;
int visibleLine = pt.y / vs.lineHeight + topLine;
if (pt.y < 0) { // Division rounds towards 0
visibleLine = (static_cast<int>(pt.y) - (vs.lineHeight - 1)) / vs.lineHeight + topLine;
}
pt = DocumentPointFromView(pt);
pt.x = pt.x - vs.textStart;
int visibleLine = floor(pt.y / vs.lineHeight);
if (!canReturnInvalid && (visibleLine < 0))
visibleLine = 0;
int lineDoc = cs.DocFromDisplay(visibleLine);
@ -622,6 +652,8 @@ void Editor::Redraw() {
//Platform::DebugPrintf("Redraw all\n");
PRectangle rcClient = GetClientRectangle();
wMain.InvalidateRectangle(rcClient);
if (wMargin.GetID())
wMargin.InvalidateAll();
//wMain.InvalidateAll();
}
@ -631,7 +663,7 @@ void Editor::RedrawSelMargin(int line, bool allAfter) {
Redraw();
} else {
PRectangle rcSelMargin = GetClientRectangle();
rcSelMargin.right = vs.fixedColumnWidth;
rcSelMargin.right = rcSelMargin.left + vs.fixedColumnWidth;
if (line != -1) {
int position = pdoc->LineStart(line);
PRectangle rcLine = RectangleFromRange(position, position);
@ -651,7 +683,13 @@ void Editor::RedrawSelMargin(int line, bool allAfter) {
if (!allAfter)
rcSelMargin.bottom = rcLine.bottom;
}
wMain.InvalidateRectangle(rcSelMargin);
if (wMargin.GetID()) {
Point ptOrigin = GetVisibleOriginInMain();
rcSelMargin.Move(-ptOrigin.x, -ptOrigin.y);
wMargin.InvalidateRectangle(rcSelMargin);
} else {
wMain.InvalidateRectangle(rcSelMargin);
}
}
}
}
@ -669,15 +707,12 @@ PRectangle Editor::RectangleFromRange(int start, int end) {
PRectangle rcClient = GetTextRectangle();
PRectangle rc;
const int leftTextOverlap = ((xOffset == 0) && (vs.leftMarginWidth > 0)) ? 1 : 0;
rc.left = vs.fixedColumnWidth - leftTextOverlap;
rc.top = (minLine - topLine) * vs.lineHeight;
if (rc.top < 0)
rc.top = 0;
rc.left = vs.textStart - leftTextOverlap;
rc.top = (minLine - TopLineOfMain()) * vs.lineHeight;
if (rc.top < rcClient.top)
rc.top = rcClient.top;
rc.right = rcClient.right;
rc.bottom = (maxLine - topLine + 1) * vs.lineHeight;
// Ensure PRectangle is within 16 bit space
rc.top = Platform::Clamp(rc.top, -32000, 32000);
rc.bottom = Platform::Clamp(rc.bottom, -32000, 32000);
rc.bottom = (maxLine - TopLineOfMain() + 1) * vs.lineHeight;
return rc;
}
@ -782,6 +817,7 @@ void Editor::SetSelection(SelectionPosition currentPos_, SelectionPosition ancho
if (highlightDelimiter.NeedsDrawing(currentLine)) {
RedrawSelMargin();
}
QueueIdleWork(WorkNeeded::workUpdateUI);
}
void Editor::SetSelection(int currentPos_, int anchor_) {
@ -808,6 +844,7 @@ void Editor::SetSelection(SelectionPosition currentPos_) {
if (highlightDelimiter.NeedsDrawing(currentLine)) {
RedrawSelMargin();
}
QueueIdleWork(WorkNeeded::workUpdateUI);
}
void Editor::SetSelection(int currentPos_) {
@ -828,6 +865,7 @@ void Editor::SetEmptySelection(SelectionPosition currentPos_) {
if (highlightDelimiter.NeedsDrawing(currentLine)) {
RedrawSelMargin();
}
QueueIdleWork(WorkNeeded::workUpdateUI);
}
void Editor::SetEmptySelection(int currentPos_) {
@ -924,7 +962,8 @@ int Editor::MovePositionTo(SelectionPosition newPos, Selection::selTypes selt, b
// In case in need of wrapping to ensure DisplayFromDoc works.
if (currentLine >= wrapStart)
WrapLines(true, -1);
XYScrollPosition newXY = XYScrollToMakeVisible(true, true, true);
XYScrollPosition newXY = XYScrollToMakeVisible(
SelectionRange(posDrag.IsValid() ? posDrag : sel.RangeMain().caret), xysDefault);
if (simpleCaret && (newXY.xOffset == xOffset)) {
// simple vertical scroll then invalidate
ScrollTo(newXY.topLine);
@ -1195,17 +1234,22 @@ slop | strict | jumps | even | Caret can go to the margin | When
1 | 1 | 1 | 1 | No, kept out of UZ | moved to put caret at 3UZ of the margin
*/
Editor::XYScrollPosition Editor::XYScrollToMakeVisible(const bool useMargin, const bool vert, const bool horiz) {
Editor::XYScrollPosition Editor::XYScrollToMakeVisible(const SelectionRange range, const XYScrollOptions options) {
PRectangle rcClient = GetTextRectangle();
const SelectionPosition posCaret = posDrag.IsValid() ? posDrag : sel.RangeMain().caret;
const Point pt = LocationFromPosition(posCaret);
Point pt = LocationFromPosition(range.caret);
Point ptAnchor = LocationFromPosition(range.anchor);
const Point ptOrigin = GetVisibleOriginInMain();
pt.x += ptOrigin.x;
pt.y += ptOrigin.y;
ptAnchor.x += ptOrigin.x;
ptAnchor.y += ptOrigin.y;
const Point ptBottomCaret(pt.x, pt.y + vs.lineHeight - 1);
const int lineCaret = DisplayFromPosition(posCaret.Position());
XYScrollPosition newXY(xOffset, topLine);
// Vertical positioning
if (vert && (pt.y < rcClient.top || ptBottomCaret.y >= rcClient.bottom || (caretYPolicy & CARET_STRICT) != 0)) {
if ((options & xysVertical) && (pt.y < rcClient.top || ptBottomCaret.y >= rcClient.bottom || (caretYPolicy & CARET_STRICT) != 0)) {
const int lineCaret = DisplayFromPosition(range.caret.Position());
const int linesOnScreen = LinesOnScreen();
const int halfScreen = Platform::Maximum(linesOnScreen - 1, 2) / 2;
const bool bSlop = (caretYPolicy & CARET_SLOP) != 0;
@ -1219,7 +1263,7 @@ Editor::XYScrollPosition Editor::XYScrollToMakeVisible(const bool useMargin, con
int yMoveT, yMoveB;
if (bStrict) {
int yMarginT, yMarginB;
if (!useMargin) {
if (!(options & xysUseMargin)) {
// In drag mode, avoid moves
// otherwise, a double click will select several lines.
yMarginT = yMarginB = 0;
@ -1289,11 +1333,23 @@ Editor::XYScrollPosition Editor::XYScrollToMakeVisible(const bool useMargin, con
}
}
}
if (!(range.caret == range.anchor)) {
const int lineAnchor = DisplayFromPosition(range.anchor.Position());
if (lineAnchor < lineCaret) {
// Shift up to show anchor or as much of range as possible
newXY.topLine = std::min(newXY.topLine, lineAnchor);
newXY.topLine = std::max(newXY.topLine, lineCaret - LinesOnScreen());
} else {
// Shift down to show anchor or as much of range as possible
newXY.topLine = std::max(newXY.topLine, lineAnchor - LinesOnScreen());
newXY.topLine = std::min(newXY.topLine, lineCaret);
}
}
newXY.topLine = Platform::Clamp(newXY.topLine, 0, MaxScrollPos());
}
// Horizontal positioning
if (horiz && (wrapState == eWrapNone)) {
if ((options & xysHorizontal) && (wrapState == eWrapNone)) {
const int halfScreen = Platform::Maximum(rcClient.Width() - 4, 4) / 2;
const bool bSlop = (caretXPolicy & CARET_SLOP) != 0;
const bool bStrict = (caretXPolicy & CARET_STRICT) != 0;
@ -1304,7 +1360,7 @@ Editor::XYScrollPosition Editor::XYScrollToMakeVisible(const bool useMargin, con
int xMoveL, xMoveR;
if (bStrict) {
int xMarginL, xMarginR;
if (!useMargin) {
if (!(options & xysUseMargin)) {
// In drag mode, avoid moves unless very near of the margin
// otherwise, a simple click will select text.
xMarginL = xMarginR = 2;
@ -1393,6 +1449,21 @@ Editor::XYScrollPosition Editor::XYScrollToMakeVisible(const bool useMargin, con
newXY.xOffset += static_cast<int>(vs.aveCharWidth);
}
}
if (!(range.caret == range.anchor)) {
if (ptAnchor.x < pt.x) {
// Shift to left to show anchor or as much of range as possible
int maxOffset = ptAnchor.x + xOffset - rcClient.left - 1;
int minOffset = pt.x + xOffset - rcClient.right + 1;
newXY.xOffset = std::min(newXY.xOffset, maxOffset);
newXY.xOffset = std::max(newXY.xOffset, minOffset);
} else {
// Shift to right to show anchor or as much of range as possible
int minOffset = ptAnchor.x + xOffset - rcClient.right + 1;
int maxOffset = pt.x + xOffset - rcClient.left - 1;
newXY.xOffset = std::max(newXY.xOffset, minOffset);
newXY.xOffset = std::min(newXY.xOffset, maxOffset);
}
}
if (newXY.xOffset < 0) {
newXY.xOffset = 0;
}
@ -1425,8 +1496,13 @@ void Editor::SetXYScroll(XYScrollPosition newXY) {
}
}
void Editor::ScrollRange(SelectionRange range) {
SetXYScroll(XYScrollToMakeVisible(range, xysDefault));
}
void Editor::EnsureCaretVisible(bool useMargin, bool vert, bool horiz) {
SetXYScroll(XYScrollToMakeVisible(useMargin, vert, horiz));
SetXYScroll(XYScrollToMakeVisible(SelectionRange(posDrag.IsValid() ? posDrag : sel.RangeMain().caret),
static_cast<XYScrollOptions>((useMargin?xysUseMargin:0)|(vert?xysVertical:0)|(horiz?xysHorizontal:0))));
}
void Editor::ShowCaretAtCurrentPosition() {
@ -1542,8 +1618,8 @@ bool Editor::WrapLines(bool fullWrap, int priorityWrapLineStart) {
int lineDocTop = cs.DocFromDisplay(topLine);
int subLineTop = topLine - cs.DisplayFromDoc(lineDocTop);
PRectangle rcTextArea = GetClientRectangle();
rcTextArea.left = vs.fixedColumnWidth;
rcTextArea.right -= vs.rightMarginWidth;
rcTextArea.left = vs.textStart;
rcTextArea.right -= vs.textStart;
wrapWidth = rcTextArea.Width();
RefreshStyleData();
AutoSurface surface(this);
@ -1606,7 +1682,7 @@ void Editor::LinesJoin() {
UndoGroup ug(pdoc);
bool prevNonWS = true;
for (int pos = targetStart; pos < targetEnd; pos++) {
if (IsEOLChar(pdoc->CharAt(pos))) {
if (pdoc->IsPositionInLineEnd(pos)) {
targetEnd -= pdoc->LenChar(pos);
pdoc->DelChar(pos);
if (prevNonWS) {
@ -1753,7 +1829,12 @@ void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) {
if (vs.fixedColumnWidth == 0)
return;
RefreshPixMaps(surfWindow);
PRectangle rcMargin = GetClientRectangle();
Point ptOrigin = GetVisibleOriginInMain();
rcMargin.Move(0, -ptOrigin.y);
rcMargin.left = 0;
rcMargin.right = vs.fixedColumnWidth;
if (!rc.Intersects(rcMargin))
@ -1774,18 +1855,24 @@ void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) {
PRectangle rcSelMargin = rcMargin;
rcSelMargin.right = rcMargin.left;
if (rcSelMargin.bottom < rc.bottom)
rcSelMargin.bottom = rc.bottom;
for (int margin = 0; margin < vs.margins; margin++) {
for (int margin = 0; margin <= SC_MAX_MARGIN; margin++) {
if (vs.ms[margin].width > 0) {
rcSelMargin.left = rcSelMargin.right;
rcSelMargin.right = rcSelMargin.left + vs.ms[margin].width;
if (vs.ms[margin].style != SC_MARGIN_NUMBER) {
if (vs.ms[margin].mask & SC_MASK_FOLDERS)
if (vs.ms[margin].mask & SC_MASK_FOLDERS) {
// Required because of special way brush is created for selection margin
surface->FillRectangle(rcSelMargin, *pixmapSelPattern);
else {
// Ensure patterns line up when scrolling with separate margin view
// by choosing correctly aligned variant.
bool invertPhase = static_cast<int>(ptOrigin.y) & 1;
surface->FillRectangle(rcSelMargin,
invertPhase ? *pixmapSelPattern : *pixmapSelPatternOffset1);
} else {
ColourDesired colour;
switch (vs.ms[margin].style) {
case SC_MARGIN_BACK:
@ -1804,9 +1891,9 @@ void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) {
surface->FillRectangle(rcSelMargin, vs.styles[STYLE_LINENUMBER].back);
}
const int lineStartPaint = rcMargin.top / vs.lineHeight;
int visibleLine = topLine + lineStartPaint;
int yposScreen = lineStartPaint * vs.lineHeight;
const int lineStartPaint = (rcMargin.top + ptOrigin.y) / vs.lineHeight;
int visibleLine = TopLineOfMain() + lineStartPaint;
int yposScreen = lineStartPaint * vs.lineHeight - ptOrigin.y;
// Work out whether the top line is whitespace located after a
// lessening of fold level which implies a 'fold tail' but which should not
// be displayed until the last of a sequence of whitespace.
@ -1837,7 +1924,7 @@ void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) {
int folderEnd = SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND,
SC_MARKNUM_FOLDER);
while ((visibleLine < cs.LinesDisplayed()) && yposScreen < rcMargin.bottom) {
while ((visibleLine < cs.LinesDisplayed()) && yposScreen < rc.bottom) {
PLATFORM_ASSERT(visibleLine < cs.LinesDisplayed());
int lineDoc = cs.DocFromDisplay(visibleLine);
@ -1947,8 +2034,9 @@ void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) {
rcMarker.bottom = yposScreen + vs.lineHeight;
if (vs.ms[margin].style == SC_MARGIN_NUMBER) {
if (firstSubLine) {
char number[100];
sprintf(number, "%d", lineDoc + 1);
char number[100] = "";
if (lineDoc >= 0)
sprintf(number, "%d", lineDoc + 1);
if (foldFlags & SC_FOLDFLAG_LEVELNUMBERS) {
int lev = pdoc->GetLevel(lineDoc);
sprintf(number, "%c%c %03X %03X",
@ -2193,7 +2281,7 @@ void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayou
bool isBadUTF = isBadUTFNext;
isBadUTFNext = IsUnicodeMode() && BadUTF(ll->chars + charInLine + 1, numCharsInLine - charInLine - 1, trailBytes);
if ((ll->styles[charInLine] != ll->styles[charInLine + 1]) ||
isControl || isControlNext || isBadUTF || isBadUTFNext) {
isControl || isControlNext || isBadUTF || isBadUTFNext || ((charInLine+1) >= numCharsBeforeEOL)) {
ll->positions[startseg] = 0;
if (vstyle.styles[ll->styles[charInLine]].visible) {
if (isControl) {
@ -2213,7 +2301,7 @@ void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayou
ll->positions + startseg + 1);
}
lastSegItalics = false;
} else if (isBadUTF) {
} else if ((isBadUTF) || (charInLine >= numCharsBeforeEOL)) {
char hexits[4];
sprintf(hexits, "x%2X", ll->chars[charInLine] & 0xff);
ll->positions[charInLine + 1] =
@ -2504,7 +2592,15 @@ void Editor::DrawEOL(Surface *surface, ViewStyle &vsDraw, PRectangle rcLine, Lin
rcSegment.left = xStart + ll->positions[eolPos] - subLineStart + virtualSpace;
rcSegment.right = xStart + ll->positions[eolPos+1] - subLineStart + virtualSpace;
blobsWidth += rcSegment.Width();
const char *ctrlChar = ControlCharacterString(ll->chars[eolPos]);
char hexits[4];
const char *ctrlChar;
unsigned char chEOL = ll->chars[eolPos];
if (UTF8IsAscii(chEOL)) {
ctrlChar = ControlCharacterString(chEOL);
} else {
sprintf(hexits, "x%2X", chEOL);
ctrlChar = hexits;
}
int styleMain = ll->styles[eolPos];
ColourDesired textBack = TextBackground(vsDraw, overrideBackground, background, eolInSelection, false, styleMain, eolPos, ll);
ColourDesired textFore = vsDraw.styles[styleMain].fore;
@ -2743,7 +2839,7 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis
// the color for the highest numbered one is used.
bool overrideBackground = false;
ColourDesired background;
if (caret.active && vsDraw.showCaretLineBackground && (vsDraw.caretLineAlpha == SC_ALPHA_NOALPHA) && ll->containsCaret) {
if ((caret.active || vsDraw.alwaysShowCaretLineBackground) && vsDraw.showCaretLineBackground && (vsDraw.caretLineAlpha == SC_ALPHA_NOALPHA) && ll->containsCaret) {
overrideBackground = true;
background = vsDraw.caretLineBackground;
}
@ -2989,12 +3085,6 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis
textBack = vsDraw.whitespaceBackground;
surface->FillRectangle(rcSegment, textBack);
}
if ((vsDraw.viewWhitespace != wsInvisible) ||
(inIndentation && vsDraw.viewIndentationGuides != ivNone)) {
if (vsDraw.whitespaceForegroundSet)
textFore = vsDraw.whitespaceForeground;
surface->PenColour(textFore);
}
if (inIndentation && vsDraw.viewIndentationGuides == ivReal) {
for (int indentCount = (ll->positions[i] + epsilon) / indentWidth;
indentCount <= (ll->positions[i + 1] - epsilon) / indentWidth;
@ -3008,6 +3098,9 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis
}
if (vsDraw.viewWhitespace != wsInvisible) {
if (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways) {
if (vsDraw.whitespaceForegroundSet)
textFore = vsDraw.whitespaceForeground;
surface->PenColour(textFore);
PRectangle rcTab(rcSegment.left + 1, rcSegment.top + 4,
rcSegment.right - 1, rcSegment.bottom - vsDraw.maxDescent);
DrawTabArrow(surface, rcTab, rcSegment.top + vsDraw.lineHeight / 2);
@ -3193,7 +3286,7 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis
// Draw any translucent whole line states
rcSegment = rcLine;
if (caret.active && vsDraw.showCaretLineBackground && ll->containsCaret) {
if ((caret.active || vsDraw.alwaysShowCaretLineBackground) && vsDraw.showCaretLineBackground && ll->containsCaret) {
SimpleAlphaRectangle(surface, rcSegment, vsDraw.caretLineBackground, vsDraw.caretLineAlpha);
}
marks = pdoc->GetMark(line);
@ -3289,6 +3382,7 @@ void Editor::RefreshPixMaps(Surface *surfaceWindow) {
if (!pixmapSelPattern->Initialised()) {
const int patternSize = 8;
pixmapSelPattern->InitPixMap(patternSize, patternSize, surfaceWindow, wMain.GetID());
pixmapSelPatternOffset1->InitPixMap(patternSize, patternSize, surfaceWindow, wMain.GetID());
// This complex procedure is to reproduce the checkerboard dithered pattern used by windows
// for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half
// way between the chrome colour and the chrome highlight colour making a nice transition
@ -3315,10 +3409,12 @@ void Editor::RefreshPixMaps(Surface *surfaceWindow) {
}
pixmapSelPattern->FillRectangle(rcPattern, colourFMFill);
pixmapSelPatternOffset1->FillRectangle(rcPattern, colourFMStripes);
for (int y = 0; y < patternSize; y++) {
for (int x = y % 2; x < patternSize; x+=2) {
PRectangle rcPixel(x, y, x+1, y+1);
pixmapSelPattern->FillRectangle(rcPixel, colourFMStripes);
pixmapSelPatternOffset1->FillRectangle(rcPixel, colourFMFill);
}
}
}
@ -3446,22 +3542,20 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) {
StyleToPositionInView(PositionAfterArea(rcArea));
PRectangle rcClient = GetClientRectangle();
Point ptOrigin = GetVisibleOriginInMain();
//Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
// rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
int screenLinePaintFirst = rcArea.top / vs.lineHeight;
int xStart = vs.fixedColumnWidth - xOffset;
int xStart = vs.textStart - xOffset + ptOrigin.x;
int ypos = 0;
if (!bufferedDraw)
ypos += screenLinePaintFirst * vs.lineHeight;
int yposScreen = screenLinePaintFirst * vs.lineHeight;
bool paintAbandonedByStyling = paintState == paintAbandoned;
if (needUpdateUI) {
NotifyUpdateUI();
needUpdateUI = 0;
if (NotifyUpdateUI()) {
RefreshStyleData();
RefreshPixMaps(surfaceWindow);
}
@ -3486,12 +3580,20 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) {
surfaceWindow->SetClip(rcArea);
if (paintState != paintAbandoned) {
PaintSelMargin(surfaceWindow, rcArea);
PRectangle rcRightMargin = rcClient;
rcRightMargin.left = rcRightMargin.right - vs.rightMarginWidth;
if (rcArea.Intersects(rcRightMargin)) {
surfaceWindow->FillRectangle(rcRightMargin, vs.styles[STYLE_DEFAULT].back);
if (vs.marginInside) {
PaintSelMargin(surfaceWindow, rcArea);
PRectangle rcRightMargin = rcClient;
rcRightMargin.left = rcRightMargin.right - vs.rightMarginWidth;
if (rcArea.Intersects(rcRightMargin)) {
surfaceWindow->FillRectangle(rcRightMargin, vs.styles[STYLE_DEFAULT].back);
}
} else { // Else separate view so separate paint event but leftMargin included to allow overlap
PRectangle rcLeftMargin = rcArea;
rcLeftMargin.left = 0;
rcLeftMargin.right = rcLeftMargin.left + vs.leftMarginWidth;
if (rcArea.Intersects(rcLeftMargin)) {
surfaceWindow->FillRectangle(rcLeftMargin, vs.styles[STYLE_DEFAULT].back);
}
}
}
@ -3515,7 +3617,7 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) {
const int leftTextOverlap = ((xOffset == 0) && (vs.leftMarginWidth > 0)) ? 1 : 0;
// Do the painting
if (rcArea.right > vs.fixedColumnWidth - leftTextOverlap) {
if (rcArea.right > vs.textStart - leftTextOverlap) {
Surface *surface = surfaceWindow;
if (bufferedDraw) {
@ -3525,7 +3627,7 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) {
surface->SetUnicodeMode(IsUnicodeMode());
surface->SetDBCSMode(CodePage());
int visibleLine = topLine + screenLinePaintFirst;
int visibleLine = TopLineOfMain() + screenLinePaintFirst;
SelectionPosition posCaret = sel.RangeMain().caret;
if (posDrag.IsValid())
@ -3533,12 +3635,16 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) {
int lineCaret = pdoc->LineFromPosition(posCaret.Position());
PRectangle rcTextArea = rcClient;
rcTextArea.left = vs.fixedColumnWidth;
rcTextArea.right -= vs.rightMarginWidth;
if (vs.marginInside) {
rcTextArea.left += vs.textStart;
rcTextArea.right -= vs.rightMarginWidth;
} else {
rcTextArea = rcArea;
}
// Remove selection margin from drawing area so text will not be drawn
// on it in unbuffered mode.
if (!bufferedDraw) {
if (!bufferedDraw && vs.marginInside) {
PRectangle rcClipText = rcTextArea;
rcClipText.left -= leftTextOverlap;
surfaceWindow->SetClip(rcClipText);
@ -3632,8 +3738,8 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) {
DrawCarets(surface, vs, lineDoc, xStart, rcLine, ll, subLine);
if (bufferedDraw) {
Point from(vs.fixedColumnWidth-leftTextOverlap, 0);
PRectangle rcCopyArea(vs.fixedColumnWidth-leftTextOverlap, yposScreen,
Point from(vs.textStart-leftTextOverlap, 0);
PRectangle rcCopyArea(vs.textStart-leftTextOverlap, yposScreen,
rcClient.right - vs.rightMarginWidth, yposScreen + vs.lineHeight);
surfaceWindow->Copy(rcCopyArea, from, *pixmapLine);
}
@ -3657,10 +3763,10 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) {
// durPaint = 0.00000001;
// Right column limit indicator
PRectangle rcBeyondEOF = rcClient;
rcBeyondEOF.left = vs.fixedColumnWidth;
rcBeyondEOF.right = rcBeyondEOF.right - vs.rightMarginWidth;
rcBeyondEOF.top = (cs.LinesDisplayed() - topLine) * vs.lineHeight;
PRectangle rcBeyondEOF = (vs.marginInside) ? rcClient : rcArea;
rcBeyondEOF.left = vs.textStart;
rcBeyondEOF.right = rcBeyondEOF.right - ((vs.marginInside) ? vs.rightMarginWidth : 0);
rcBeyondEOF.top = (cs.LinesDisplayed() - TopLineOfMain()) * vs.lineHeight;
if (rcBeyondEOF.top < rcBeyondEOF.bottom) {
surfaceWindow->FillRectangle(rcBeyondEOF, vs.styles[STYLE_DEFAULT].back);
if (vs.edgeState == EDGE_LINE) {
@ -3718,7 +3824,7 @@ long Editor::FormatRange(bool draw, Sci_RangeToFormat *pfr) {
// Modify the view style for printing as do not normally want any of the transient features to be printed
// Printing supports only the line number margin.
int lineNumberIndex = -1;
for (int margin = 0; margin < ViewStyle::margins; margin++) {
for (int margin = 0; margin <= SC_MAX_MARGIN; margin++) {
if ((vsPrint.ms[margin].style == SC_MARGIN_NUMBER) && (vsPrint.ms[margin].width > 0)) {
lineNumberIndex = margin;
} else {
@ -3738,6 +3844,7 @@ long Editor::FormatRange(bool draw, Sci_RangeToFormat *pfr) {
vsPrint.whitespaceBackgroundSet = false;
vsPrint.whitespaceForegroundSet = false;
vsPrint.showCaretLineBackground = false;
vsPrint.alwaysShowCaretLineBackground = false;
// Don't highlight matching braces using indicators
vsPrint.braceHighlightIndicatorSet = false;
vsPrint.braceBadLightIndicatorSet = false;
@ -3813,7 +3920,7 @@ long Editor::FormatRange(bool draw, Sci_RangeToFormat *pfr) {
// Copy this line and its styles from the document into local arrays
// and determine the x position at which each character starts.
LineLayout ll(8000);
LineLayout ll(pdoc->LineStart(lineDoc+1)-pdoc->LineStart(lineDoc)+1);
LayoutLine(lineDoc, surfaceMeasure, vsPrint, &ll, widthPrint);
ll.containsCaret = false;
@ -3929,7 +4036,7 @@ void Editor::ChangeSize() {
SetScrollBars();
if (wrapState != eWrapNone) {
PRectangle rcTextArea = GetClientRectangle();
rcTextArea.left = vs.fixedColumnWidth;
rcTextArea.left = vs.textStart;
rcTextArea.right -= vs.rightMarginWidth;
if (wrapWidth != rcTextArea.Width()) {
NeedWrapping();
@ -3994,7 +4101,7 @@ void Editor::AddCharUTF(char *s, unsigned int len, bool treatAsDBCS) {
}
} else if (inOverstrike) {
if (positionInsert < pdoc->Length()) {
if (!IsEOLChar(pdoc->CharAt(positionInsert))) {
if (!pdoc->IsPositionInLineEnd(positionInsert)) {
pdoc->DelChar(positionInsert);
currentSel->ClearVirtualSpace();
}
@ -4239,7 +4346,7 @@ void Editor::Clear() {
else
sel.Range(r) = SelectionPosition(InsertSpace(sel.Range(r).caret.Position(), sel.Range(r).caret.VirtualSpace()));
}
if ((sel.Count() == 1) || !IsEOLChar(pdoc->CharAt(sel.Range(r).caret.Position()))) {
if ((sel.Count() == 1) || !pdoc->IsPositionInLineEnd(sel.Range(r).caret.Position())) {
pdoc->DelChar(sel.Range(r).caret.Position());
sel.Range(r).ClearVirtualSpace();
} // else multiple selection so don't eat line ends
@ -4417,11 +4524,16 @@ void Editor::NotifyHotSpotReleaseClick(int position, bool shift, bool ctrl, bool
NotifyParent(scn);
}
void Editor::NotifyUpdateUI() {
SCNotification scn = {0};
scn.nmhdr.code = SCN_UPDATEUI;
scn.updated = needUpdateUI;
NotifyParent(scn);
bool Editor::NotifyUpdateUI() {
if (needUpdateUI) {
SCNotification scn = {0};
scn.nmhdr.code = SCN_UPDATEUI;
scn.updated = needUpdateUI;
NotifyParent(scn);
needUpdateUI = 0;
return true;
}
return false;
}
void Editor::NotifyPainted() {
@ -4444,8 +4556,8 @@ void Editor::NotifyIndicatorClick(bool click, int position, bool shift, bool ctr
bool Editor::NotifyMarginClick(Point pt, bool shift, bool ctrl, bool alt) {
int marginClicked = -1;
int x = 0;
for (int margin = 0; margin < ViewStyle::margins; margin++) {
int x = vs.textStart - vs.fixedColumnWidth;
for (int margin = 0; margin <= SC_MAX_MARGIN; margin++) {
if ((pt.x >= x) && (pt.x < x + vs.ms[margin].width))
marginClicked = margin;
x += vs.ms[margin].width;
@ -4629,18 +4741,13 @@ void Editor::NotifyModified(Document *, DocModification mh, void *) {
}
}
//Platform::DebugPrintf("** %x Doc Changed\n", this);
// TODO: could invalidate from mh.startModification to end of screen
//InvalidateRange(mh.position, mh.position + mh.length);
if (paintState == notPainting && !CanDeferToLastStep(mh)) {
QueueStyling(pdoc->Length());
QueueIdleWork(WorkNeeded::workStyle, pdoc->Length());
Redraw();
}
} else {
//Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this,
// mh.position, mh.position + mh.length);
if (paintState == notPainting && mh.length && !CanEliminate(mh)) {
QueueStyling(mh.position + mh.length);
QueueIdleWork(WorkNeeded::workStyle, mh.position + mh.length);
InvalidateRange(mh.position, mh.position + mh.length);
}
}
@ -5168,6 +5275,8 @@ int Editor::KeyCommand(unsigned int iMessage) {
SelectionPosition spCaret = sel.RangeMain().caret;
spCaret.SetVirtualSpace(spCaret.VirtualSpace() - 1);
MovePositionTo(spCaret);
} else if (sel.MoveExtends() && sel.selType == Selection::selStream) {
MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() - 1), -1));
} else {
MovePositionTo(MovePositionSoVisible(
SelectionPosition((sel.LimitsForRectangularElseMain().start).Position() - 1), -1));
@ -5203,6 +5312,8 @@ int Editor::KeyCommand(unsigned int iMessage) {
SelectionPosition spCaret = sel.RangeMain().caret;
spCaret.SetVirtualSpace(spCaret.VirtualSpace() + 1);
MovePositionTo(spCaret);
} else if (sel.MoveExtends() && sel.selType == Selection::selStream) {
MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() + 1), 1));
} else {
MovePositionTo(MovePositionSoVisible(
SelectionPosition((sel.LimitsForRectangularElseMain().end).Position() + 1), 1));
@ -6099,7 +6210,8 @@ bool Editor::PointInSelMargin(Point pt) {
// Really means: "Point in a margin"
if (vs.fixedColumnWidth > 0) { // There is a margin
PRectangle rcSelMargin = GetClientRectangle();
rcSelMargin.right = vs.fixedColumnWidth - vs.leftMarginWidth;
rcSelMargin.right = vs.textStart - vs.leftMarginWidth;
rcSelMargin.left = vs.textStart - vs.fixedColumnWidth;
return rcSelMargin.Contains(pt);
} else {
return false;
@ -6108,7 +6220,7 @@ bool Editor::PointInSelMargin(Point pt) {
Window::Cursor Editor::GetMarginCursor(Point pt) {
int x = 0;
for (int margin = 0; margin < ViewStyle::margins; margin++) {
for (int margin = 0; margin <= SC_MAX_MARGIN; margin++) {
if ((pt.x >= x) && (pt.x < x + vs.ms[margin].width))
return static_cast<Window::Cursor>(vs.ms[margin].cursor);
x += vs.ms[margin].width;
@ -6489,6 +6601,8 @@ void Editor::ButtonMove(Point pt) {
// Autoscroll
PRectangle rcClient = GetClientRectangle();
Point ptOrigin = GetVisibleOriginInMain();
rcClient.Move(0, -ptOrigin.y);
int lineMove = DisplayFromPosition(movePos.Position());
if (pt.y > rcClient.bottom) {
ScrollTo(lineMove - LinesOnScreen() + 1);
@ -6688,7 +6802,7 @@ int Editor::PositionAfterArea(PRectangle rcArea) {
// Style to a position within the view. If this causes a change at end of last line then
// affects later lines so style all the viewed text.
void Editor::StyleToPositionInView(Position pos) {
int endWindow = PositionAfterArea(GetClientRectangle());
int endWindow = (vs.marginInside) ? (PositionAfterArea(GetClientRectangle())) : (pdoc->Length());
if (pos > endWindow)
pos = endWindow;
int styleAtEnd = pdoc->StyleAt(pos-1);
@ -6700,20 +6814,18 @@ void Editor::StyleToPositionInView(Position pos) {
}
}
void Editor::IdleStyling() {
void Editor::IdleWork() {
// Style the line after the modification as this allows modifications that change just the
// line of the modification to heal instead of propagating to the rest of the window.
StyleToPositionInView(pdoc->LineStart(pdoc->LineFromPosition(styleNeeded.upTo) + 2));
if (workNeeded.items & WorkNeeded::workStyle)
StyleToPositionInView(pdoc->LineStart(pdoc->LineFromPosition(workNeeded.upTo) + 2));
if (needUpdateUI) {
NotifyUpdateUI();
needUpdateUI = 0;
}
styleNeeded.Reset();
NotifyUpdateUI();
workNeeded.Reset();
}
void Editor::QueueStyling(int upTo) {
styleNeeded.NeedUpTo(upTo);
void Editor::QueueIdleWork(WorkNeeded::workItems items, int upTo) {
workNeeded.Need(items, upTo);
}
bool Editor::PaintContains(PRectangle rc) {
@ -6725,8 +6837,13 @@ bool Editor::PaintContains(PRectangle rc) {
}
bool Editor::PaintContainsMargin() {
if (wMargin.GetID()) {
// With separate margin view, paint of text view
// never contains margin.
return false;
}
PRectangle rcSelMargin = GetClientRectangle();
rcSelMargin.right = vs.fixedColumnWidth;
rcSelMargin.right = vs.textStart;
return PaintContains(rcSelMargin);
}
@ -6811,6 +6928,8 @@ void Editor::SetDocPointer(Document *document) {
braces[0] = invalidPosition;
braces[1] = invalidPosition;
vs.ReleaseAllExtendedStyles();
// Reset the contraction state to fully shown.
cs.Clear();
cs.InsertLines(0, pdoc->LinesTotal() - 1);
@ -6922,12 +7041,17 @@ void Editor::EnsureLineVisible(int lineDoc, bool enforcePolicy) {
WrapLines(true, -1);
if (!cs.GetVisible(lineDoc)) {
// Back up to find a non-blank line
int lookLine = lineDoc;
int lookLineLevel = pdoc->GetLevel(lookLine);
while ((lookLine > 0) && (lookLineLevel & SC_FOLDLEVELWHITEFLAG)) {
lookLineLevel = pdoc->GetLevel(--lookLine);
}
int lineParent = pdoc->GetFoldParent(lookLine);
if (lineParent < 0) {
// Backed up to a top level line, so try to find parent of initial line
lineParent = pdoc->GetFoldParent(lineDoc);
}
if (lineParent >= 0) {
if (lineDoc != lineParent)
EnsureLineVisible(lineParent, enforcePolicy);
@ -7040,7 +7164,7 @@ void Editor::AddStyledText(char *buffer, int appendLength) {
}
static bool ValidMargin(unsigned long wParam) {
return wParam < ViewStyle::margins;
return wParam <= SC_MAX_MARGIN;
}
static char *CharPtrFromSPtr(sptr_t lParam) {
@ -7398,7 +7522,7 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
case SCI_LINESCROLL:
ScrollTo(topLine + lParam);
HorizontalScrollTo(xOffset + wParam * vs.spaceWidth);
HorizontalScrollTo(xOffset + static_cast<int>(wParam) * vs.spaceWidth);
return 1;
case SCI_SETXOFFSET:
@ -7434,7 +7558,8 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
return 0;
} else {
Point pt = LocationFromPosition(lParam);
return pt.x;
// Convert to view-relative
return pt.x - vs.textStart + vs.fixedColumnWidth;
}
case SCI_POINTYFROMPOSITION:
@ -7771,6 +7896,21 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
pdoc->eolMode = wParam;
break;
case SCI_SETLINEENDTYPESALLOWED:
if (pdoc->SetLineEndTypesAllowed(wParam)) {
cs.Clear();
cs.InsertLines(0, pdoc->LinesTotal() - 1);
SetAnnotationHeights(0, pdoc->LinesTotal());
InvalidateStyleRedraw();
}
break;
case SCI_GETLINEENDTYPESALLOWED:
return pdoc->GetLineEndTypesAllowed();
case SCI_GETLINEENDTYPESACTIVE:
return pdoc->GetLineEndTypesActive();
case SCI_STARTSTYLING:
pdoc->StartStyling(wParam, static_cast<char>(lParam));
break;
@ -8037,6 +8177,8 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
verticalScrollBarVisible = wParam != 0;
SetScrollBars();
ReconfigureScrollBars();
if (verticalScrollBarVisible)
SetVerticalScrollPos();
}
break;
@ -8067,6 +8209,9 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
case SCI_SETCODEPAGE:
if (ValidCodePage(wParam)) {
if (pdoc->SetDBCSCodePage(wParam)) {
cs.Clear();
cs.InsertLines(0, pdoc->LinesTotal() - 1);
SetAnnotationHeights(0, pdoc->LinesTotal());
InvalidateStyleRedraw();
}
}
@ -8321,6 +8466,13 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
vs.showCaretLineBackground = wParam != 0;
InvalidateStyleRedraw();
break;
case SCI_GETCARETLINEVISIBLEALWAYS:
return vs.alwaysShowCaretLineBackground;
case SCI_SETCARETLINEVISIBLEALWAYS:
vs.alwaysShowCaretLineBackground = wParam != 0;
InvalidateStyleRedraw();
break;
case SCI_GETCARETLINEBACK:
return vs.caretLineBackground.AsLong();
case SCI_SETCARETLINEBACK:
@ -8409,6 +8561,10 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
EnsureLineVisible(wParam, true);
break;
case SCI_SCROLLRANGE:
ScrollRange(SelectionRange(lParam, wParam));
break;
case SCI_SEARCHANCHOR:
SearchAnchor();
break;
@ -9123,6 +9279,13 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
case SCI_ANNOTATIONGETSTYLEOFFSET:
return vs.annotationStyleOffset;
case SCI_RELEASEALLEXTENDEDSTYLES:
vs.ReleaseAllExtendedStyles();
break;
case SCI_ALLOCATEEXTENDEDSTYLES:
return vs.AllocateExtendedStyles(wParam);
case SCI_ADDUNDOACTION:
pdoc->AddUndoAction(wParam, lParam & UNDO_MAY_COALESCE);
break;

View File

@ -47,21 +47,30 @@ public:
/**
* When platform has a way to generate an event before painting,
* accumulate needed styling range in StyleNeeded to avoid unnecessary work.
* accumulate needed styling range and other work items in
* WorkNeeded to avoid unnecessary work inside paint handler
*/
class StyleNeeded {
class WorkNeeded {
public:
enum workItems {
workNone=0,
workStyle=1,
workUpdateUI=2
};
bool active;
enum workItems items;
Position upTo;
StyleNeeded() : active(false), upTo(0) {}
WorkNeeded() : active(false), items(workNone), upTo(0) {}
void Reset() {
active = false;
items = workNone;
upTo = 0;
}
void NeedUpTo(Position pos) {
if (upTo < pos)
void Need(workItems items_, Position pos) {
if ((items_ & workStyle) && (upTo < pos))
upTo = pos;
items = static_cast<workItems>(items | items_);
}
};
@ -95,6 +104,7 @@ public:
characterSet = characterSet_;
rectangular = rectangular_;
lineCopy = lineCopy_;
FixSelectionForClipboard();
}
void Copy(const char *s_, int len_, int codePage_, int characterSet_, bool rectangular_, bool lineCopy_) {
delete []s;
@ -108,10 +118,22 @@ public:
characterSet = characterSet_;
rectangular = rectangular_;
lineCopy = lineCopy_;
FixSelectionForClipboard();
}
void Copy(const SelectionText &other) {
Copy(other.s, other.len, other.codePage, other.characterSet, other.rectangular, other.lineCopy);
}
private:
void FixSelectionForClipboard() {
// Replace null characters by spaces.
// To avoid that the content of the clipboard is truncated in the paste operation
// when the clipboard contains null characters.
for (int i = 0; i < len - 1; ++i) {
if (s[i] == '\0')
s[i] = ' ';
}
}
};
/**
@ -126,6 +148,7 @@ protected: // ScintillaBase subclass needs access to much of Editor
/** On GTK+, Scintilla is a container widget holding two scroll bars
* whereas on Windows there is just one window with both scroll bars turned on. */
Window wMain; ///< The Scintilla parent window
Window wMargin; ///< May be separate when using a scroll view for wMain
/** Style resources may be expensive to allocate so are cached between uses.
* When a style attribute is changed, this cache is flushed. */
@ -177,6 +200,7 @@ protected: // ScintillaBase subclass needs access to much of Editor
Surface *pixmapLine;
Surface *pixmapSelMargin;
Surface *pixmapSelPattern;
Surface *pixmapSelPatternOffset1;
Surface *pixmapIndentGuide;
Surface *pixmapIndentGuideHighlight;
@ -228,7 +252,7 @@ protected: // ScintillaBase subclass needs access to much of Editor
PRectangle rcPaint;
bool paintingAllText;
bool willRedrawAll;
StyleNeeded styleNeeded;
WorkNeeded workNeeded;
int modEventMask;
@ -286,6 +310,11 @@ protected: // ScintillaBase subclass needs access to much of Editor
void DropGraphics(bool freeObjects);
void AllocateGraphics();
// The top left visible point in main window coordinates. Will be 0,0 except for
// scroll views where it will be equivalent to the current scroll position.
virtual Point GetVisibleOriginInMain();
Point DocumentPointFromView(Point ptView); // Convert a point from view space to document
int TopLineOfMain(); // Return the line at Main's y coordinate 0
virtual PRectangle GetClientRectangle();
PRectangle GetTextRectangle();
@ -352,10 +381,19 @@ protected: // ScintillaBase subclass needs access to much of Editor
int xOffset;
int topLine;
XYScrollPosition(int xOffset_, int topLine_) : xOffset(xOffset_), topLine(topLine_) {}
bool operator==(const XYScrollPosition &other) const {
return (xOffset == other.xOffset) && (topLine == other.topLine);
}
};
XYScrollPosition XYScrollToMakeVisible(const bool useMargin, const bool vert, const bool horiz);
enum XYScrollOptions {
xysUseMargin=0x1,
xysVertical=0x2,
xysHorizontal=0x4,
xysDefault=xysUseMargin|xysVertical|xysHorizontal};
XYScrollPosition XYScrollToMakeVisible(const SelectionRange range, const XYScrollOptions options);
void SetXYScroll(XYScrollPosition newXY);
void EnsureCaretVisible(bool useMargin=true, bool vert=true, bool horiz=true);
void ScrollRange(SelectionRange range);
void ShowCaretAtCurrentPosition();
void DropCaret();
void InvalidateCaret();
@ -439,7 +477,7 @@ protected: // ScintillaBase subclass needs access to much of Editor
void NotifyHotSpotClicked(int position, bool shift, bool ctrl, bool alt);
void NotifyHotSpotDoubleClicked(int position, bool shift, bool ctrl, bool alt);
void NotifyHotSpotReleaseClick(int position, bool shift, bool ctrl, bool alt);
void NotifyUpdateUI();
bool NotifyUpdateUI();
void NotifyPainted();
void NotifyIndicatorClick(bool click, int position, bool shift, bool ctrl, bool alt);
bool NotifyMarginClick(Point pt, bool shift, bool ctrl, bool alt);
@ -518,8 +556,8 @@ protected: // ScintillaBase subclass needs access to much of Editor
int PositionAfterArea(PRectangle rcArea);
void StyleToPositionInView(Position pos);
void IdleStyling();
virtual void QueueStyling(int upTo);
virtual void IdleWork();
virtual void QueueIdleWork(WorkNeeded::workItems items, int upTo=0);
virtual bool PaintContains(PRectangle rc);
bool PaintContainsMargin();

View File

@ -6,6 +6,7 @@
// The License.txt file describes the conditions under which this software may be distributed.
#include <string.h>
#include <math.h>
#include <vector>
#include <map>
@ -112,8 +113,8 @@ void LineMarker::Draw(Surface *surface, PRectangle &rcWhole, Font &fontForCharac
rc.bottom--;
int minDim = Platform::Minimum(rc.Width(), rc.Height());
minDim--; // Ensure does not go beyond edge
int centreX = (rc.right + rc.left) / 2;
int centreY = (rc.bottom + rc.top) / 2;
int centreX = floor((rc.right + rc.left) / 2.0);
int centreY = floor((rc.bottom + rc.top) / 2.0);
int dimOn2 = minDim / 2;
int dimOn4 = minDim / 4;
int blobSize = dimOn2-1;

View File

@ -130,6 +130,8 @@ class BreakFinder {
int subBreak;
Document *pdoc;
void Insert(int val);
// Private so BreakFinder objects can not be copied
BreakFinder(const BreakFinder &);
public:
// If a whole run is longer than lengthStartSubdivision then subdivide
// into smaller runs at spaces or punctuation.
@ -148,6 +150,8 @@ class PositionCache {
size_t size;
unsigned int clock;
bool allClear;
// Private so PositionCache objects can not be copied
PositionCache(const PositionCache &);
public:
PositionCache();
~PositionCache();

View File

@ -23,6 +23,8 @@ private:
void RemoveRun(int run);
void RemoveRunIfEmpty(int run);
void RemoveRunIfSameAsPrevious(int run);
// Private so RunStyles objects can not be copied
RunStyles(const RunStyles &);
public:
RunStyles();
~RunStyles();

View File

@ -193,6 +193,13 @@ void ScintillaBase::AutoCompleteDoubleClick(void *p) {
sci->AutoCompleteCompleted();
}
void ScintillaBase::AutoCompleteInsert(Position startPos, int removeLen, const char *text, int textLen) {
UndoGroup ug(pdoc);
pdoc->DeleteChars(startPos, removeLen);
pdoc->InsertString(startPos, text, textLen);
SetEmptySelection(startPos + textLen);
}
void ScintillaBase::AutoCompleteStart(int lenEntered, const char *list) {
//Platform::DebugPrintf("AutoComplete %s\n", list);
ct.CallTipCancel();
@ -203,15 +210,10 @@ void ScintillaBase::AutoCompleteStart(int lenEntered, const char *list) {
int lenInsert = typeSep ?
static_cast<int>(typeSep-list) : static_cast<int>(strlen(list));
if (ac.ignoreCase) {
SetEmptySelection(sel.MainCaret() - lenEntered);
pdoc->DeleteChars(sel.MainCaret(), lenEntered);
SetEmptySelection(sel.MainCaret());
pdoc->InsertString(sel.MainCaret(), list, lenInsert);
SetEmptySelection(sel.MainCaret() + lenInsert);
// May need to convert the case before invocation, so remove lenEntered characters
AutoCompleteInsert(sel.MainCaret() - lenEntered, lenEntered, list, lenInsert);
} else {
SetEmptySelection(sel.MainCaret());
pdoc->InsertString(sel.MainCaret(), list + lenEntered, lenInsert - lenEntered);
SetEmptySelection(sel.MainCaret() + lenInsert - lenEntered);
AutoCompleteInsert(sel.MainCaret(), 0, list + lenEntered, lenInsert - lenEntered);
}
ac.Cancel();
return;
@ -233,6 +235,11 @@ void ScintillaBase::AutoCompleteStart(int lenEntered, const char *list) {
Redraw();
pt = PointMainCaret();
}
if (wMargin.GetID()) {
Point ptOrigin = GetVisibleOriginInMain();
pt.x += ptOrigin.x;
pt.y += ptOrigin.y;
}
PRectangle rcac;
rcac.left = pt.x - ac.lb->CaretFromEdge();
if (pt.y >= rcPopupBounds.bottom - heightLB && // Wont fit below.
@ -356,15 +363,7 @@ void ScintillaBase::AutoCompleteCompleted() {
endPos = pdoc->ExtendWordSelect(endPos, 1, true);
if (endPos < firstPos)
return;
UndoGroup ug(pdoc);
if (endPos != firstPos) {
pdoc->DeleteChars(firstPos, endPos - firstPos);
}
SetEmptySelection(ac.posStart);
if (item != -1) {
pdoc->InsertCString(firstPos, selected.c_str());
SetEmptySelection(firstPos + static_cast<int>(selected.length()));
}
AutoCompleteInsert(firstPos, endPos - firstPos, selected.c_str(), static_cast<int>(selected.length()));
SetLastXChosen();
}
@ -398,6 +397,11 @@ void ScintillaBase::CallTipShow(Point pt, const char *defn) {
if (ct.UseStyleCallTip()) {
ct.SetForeBack(vs.styles[STYLE_CALLTIP].fore, vs.styles[STYLE_CALLTIP].back);
}
if (wMargin.GetID()) {
Point ptOrigin = GetVisibleOriginInMain();
pt.x += ptOrigin.x;
pt.y += ptOrigin.y;
}
PRectangle rc = ct.CallTipStart(sel.MainCaret(), pt,
vs.lineHeight,
defn,
@ -472,6 +476,7 @@ class LexState : public LexInterface {
const LexerModule *lexCurrent;
void SetLexerModule(const LexerModule *lex);
PropSetSimple props;
int interfaceVersion;
public:
int lexLanguage;
@ -491,6 +496,15 @@ public:
const char *PropGet(const char *key) const;
int PropGetInt(const char *key, int defaultValue=0) const;
int PropGetExpanded(const char *key, char *result) const;
int LineEndTypesSupported();
int AllocateSubStyles(int styleBase, int numberStyles);
int SubStylesStart(int styleBase);
int SubStylesLength(int styleBase);
void FreeSubStyles();
void SetIdentifiers(int style, const char *identifiers);
int DistanceToSecondaryStyles();
const char *GetSubStyleBases();
};
#ifdef SCI_NAMESPACE
@ -500,6 +514,7 @@ public:
LexState::LexState(Document *pdoc_) : LexInterface(pdoc_) {
lexCurrent = 0;
performingStyle = false;
interfaceVersion = lvOriginal;
lexLanguage = SCLEX_CONTAINER;
}
@ -523,9 +538,12 @@ void LexState::SetLexerModule(const LexerModule *lex) {
instance->Release();
instance = 0;
}
interfaceVersion = lvOriginal;
lexCurrent = lex;
if (lexCurrent)
if (lexCurrent) {
instance = lexCurrent->Create();
interfaceVersion = instance->Version();
}
pdoc->LexerChanged();
}
}
@ -630,6 +648,60 @@ int LexState::PropGetExpanded(const char *key, char *result) const {
return props.GetExpanded(key, result);
}
int LexState::LineEndTypesSupported() {
if (instance && (interfaceVersion >= lvSubStyles)) {
return static_cast<ILexerWithSubStyles *>(instance)->LineEndTypesSupported();
}
return 0;
}
int LexState::AllocateSubStyles(int styleBase, int numberStyles) {
if (instance && (interfaceVersion >= lvSubStyles)) {
return static_cast<ILexerWithSubStyles *>(instance)->AllocateSubStyles(styleBase, numberStyles);
}
return -1;
}
int LexState::SubStylesStart(int styleBase) {
if (instance && (interfaceVersion >= lvSubStyles)) {
return static_cast<ILexerWithSubStyles *>(instance)->SubStylesStart(styleBase);
}
return -1;
}
int LexState::SubStylesLength(int styleBase) {
if (instance && (interfaceVersion >= lvSubStyles)) {
return static_cast<ILexerWithSubStyles *>(instance)->SubStylesLength(styleBase);
}
return 0;
}
void LexState::FreeSubStyles() {
if (instance && (interfaceVersion >= lvSubStyles)) {
static_cast<ILexerWithSubStyles *>(instance)->FreeSubStyles();
}
}
void LexState::SetIdentifiers(int style, const char *identifiers) {
if (instance && (interfaceVersion >= lvSubStyles)) {
static_cast<ILexerWithSubStyles *>(instance)->SetIdentifiers(style, identifiers);
}
}
int LexState::DistanceToSecondaryStyles() {
if (instance && (interfaceVersion >= lvSubStyles)) {
return static_cast<ILexerWithSubStyles *>(instance)->DistanceToSecondaryStyles();
}
return 0;
}
const char *LexState::GetSubStyleBases() {
if (instance && (interfaceVersion >= lvSubStyles)) {
return static_cast<ILexerWithSubStyles *>(instance)->GetSubStyleBases();
}
return "";
}
#endif
void ScintillaBase::NotifyStyleToNeeded(int endStyleNeeded) {
@ -725,6 +797,13 @@ sptr_t ScintillaBase::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lPara
case SCI_AUTOCGETCASEINSENSITIVEBEHAVIOUR:
return ac.ignoreCaseBehaviour;
case SCI_AUTOCSETORDER:
ac.autoSort = wParam;
break;
case SCI_AUTOCGETORDER:
return ac.autoSort;
case SCI_USERLISTSHOW:
listType = wParam;
AutoCompleteStart(0, reinterpret_cast<const char *>(lParam));
@ -890,6 +969,31 @@ sptr_t ScintillaBase::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lPara
case SCI_DESCRIBEKEYWORDSETS:
return StringResult(lParam, DocumentLexState()->DescribeWordListSets());
case SCI_GETLINEENDTYPESSUPPORTED:
return DocumentLexState()->LineEndTypesSupported();
case SCI_ALLOCATESUBSTYLES:
return DocumentLexState()->AllocateSubStyles(wParam, lParam);
case SCI_GETSUBSTYLESSTART:
return DocumentLexState()->SubStylesStart(wParam);
case SCI_GETSUBSTYLESLENGTH:
return DocumentLexState()->SubStylesLength(wParam);
case SCI_FREESUBSTYLES:
DocumentLexState()->FreeSubStyles();
break;
case SCI_SETIDENTIFIERS:
DocumentLexState()->SetIdentifiers(wParam, reinterpret_cast<const char *>(lParam));
break;
case SCI_DISTANCETOSECONDARYSTYLES:
return DocumentLexState()->DistanceToSecondaryStyles();
case SCI_GETSUBSTYLEBASES:
return StringResult(lParam, DocumentLexState()->GetSubStyleBases());
#endif
default:

View File

@ -64,6 +64,7 @@ protected:
virtual void CancelModes();
virtual int KeyCommand(unsigned int iMessage);
void AutoCompleteInsert(Position startPos, int removeLen, const char *text, int textLen);
void AutoCompleteStart(int lenEntered, const char *list);
void AutoCompleteCancel();
void AutoCompleteMove(int delta);

View File

@ -26,3 +26,16 @@ inline bool UTF8IsAscii(int ch) {
enum { UTF8MaskWidth=0x7, UTF8MaskInvalid=0x8 };
int UTF8Classify(const unsigned char *us, int len);
// Line separator is U+2028 \xe2\x80\xa8
// Paragraph separator is U+2029 \xe2\x80\xa9
const int UTF8SeparatorLength = 3;
inline bool UTF8IsSeparator(const unsigned char *us) {
return (us[0] == 0xe2) && (us[1] == 0x80) && ((us[2] == 0xa8) || (us[2] == 0xa9));
}
// NEL is U+0085 \xc2\x85
const int UTF8NELLength = 2;
inline bool UTF8IsNEL(const unsigned char *us) {
return (us[0] == 0xc2) && (us[1] == 0x85);
}

View File

@ -6,6 +6,7 @@
// The License.txt file describes the conditions under which this software may be distributed.
#include <string.h>
#include <assert.h>
#include <vector>
#include <map>
@ -140,6 +141,7 @@ ViewStyle::ViewStyle(const ViewStyle &source) {
// Can't just copy fontname as its lifetime is relative to its owning ViewStyle
styles[sty].fontName = fontNames.Save(source.styles[sty].fontName);
}
nextExtendedStyle = source.nextExtendedStyle;
for (int mrk=0; mrk<=MARKER_MAX; mrk++) {
markers[mrk] = source.markers[mrk];
}
@ -180,6 +182,7 @@ ViewStyle::ViewStyle(const ViewStyle &source) {
caretcolour = source.caretcolour;
additionalCaretColour = source.additionalCaretColour;
showCaretLineBackground = source.showCaretLineBackground;
alwaysShowCaretLineBackground = source.alwaysShowCaretLineBackground;
caretLineBackground = source.caretLineBackground;
caretLineAlpha = source.caretLineAlpha;
edgecolour = source.edgecolour;
@ -190,11 +193,13 @@ ViewStyle::ViewStyle(const ViewStyle &source) {
someStylesForceCase = false;
leftMarginWidth = source.leftMarginWidth;
rightMarginWidth = source.rightMarginWidth;
for (int i=0; i < margins; i++) {
ms[i] = source.ms[i];
for (int margin=0; margin <= SC_MAX_MARGIN; margin++) {
ms[margin] = source.ms[margin];
}
maskInLine = source.maskInLine;
fixedColumnWidth = source.fixedColumnWidth;
marginInside = source.marginInside;
textStart = source.textStart;
zoomLevel = source.zoomLevel;
viewWhitespace = source.viewWhitespace;
whitespaceSize = source.whitespaceSize;
@ -224,6 +229,7 @@ void ViewStyle::Init(size_t stylesSize_) {
stylesSize = 0;
styles = NULL;
AllocStyles(stylesSize_);
nextExtendedStyle = 256;
fontNames.Clear();
ResetDefaultStyle();
@ -274,6 +280,7 @@ void ViewStyle::Init(size_t stylesSize_) {
caretcolour = ColourDesired(0, 0, 0);
additionalCaretColour = ColourDesired(0x7f, 0x7f, 0x7f);
showCaretLineBackground = false;
alwaysShowCaretLineBackground = false;
caretLineBackground = ColourDesired(0xff, 0xff, 0);
caretLineAlpha = SC_ALPHA_NOALPHA;
edgecolour = ColourDesired(0xc0, 0xc0, 0xc0);
@ -301,13 +308,15 @@ void ViewStyle::Init(size_t stylesSize_) {
ms[2].style = SC_MARGIN_SYMBOL;
ms[2].width = 0;
ms[2].mask = 0;
fixedColumnWidth = leftMarginWidth;
marginInside = true;
fixedColumnWidth = marginInside ? leftMarginWidth : 0;
maskInLine = 0xffffffff;
for (int margin=0; margin < margins; margin++) {
for (int margin=0; margin <= SC_MAX_MARGIN; margin++) {
fixedColumnWidth += ms[margin].width;
if (ms[margin].width > 0)
maskInLine &= ~ms[margin].mask;
}
textStart = marginInside ? fixedColumnWidth : leftMarginWidth;
zoomLevel = 0;
viewWhitespace = wsInvisible;
whitespaceSize = 1;
@ -354,6 +363,7 @@ void ViewStyle::Refresh(Surface &surface) {
CreateFont(styles[j]);
}
assert(frFirst);
frFirst->Realise(surface, zoomLevel, technology);
for (unsigned int k=0; k<stylesSize; k++) {
@ -381,13 +391,14 @@ void ViewStyle::Refresh(Surface &surface) {
aveCharWidth = styles[STYLE_DEFAULT].aveCharWidth;
spaceWidth = styles[STYLE_DEFAULT].spaceWidth;
fixedColumnWidth = leftMarginWidth;
fixedColumnWidth = marginInside ? leftMarginWidth : 0;
maskInLine = 0xffffffff;
for (int margin=0; margin < margins; margin++) {
for (int margin=0; margin <= SC_MAX_MARGIN; margin++) {
fixedColumnWidth += ms[margin].width;
if (ms[margin].width > 0)
maskInLine &= ~ms[margin].mask;
}
textStart = marginInside ? fixedColumnWidth : leftMarginWidth;
}
void ViewStyle::AllocStyles(size_t sizeNew) {
@ -409,6 +420,16 @@ void ViewStyle::AllocStyles(size_t sizeNew) {
stylesSize = sizeNew;
}
void ViewStyle::ReleaseAllExtendedStyles() {
nextExtendedStyle = 256;
}
int ViewStyle::AllocateExtendedStyles(int numberStyles) {
int startRange = static_cast<int>(nextExtendedStyle);
nextExtendedStyle += numberStyles;
return startRange;
}
void ViewStyle::EnsureStyle(size_t index) {
if (index >= stylesSize) {
size_t sizeNew = stylesSize * 2;
@ -467,4 +488,3 @@ void ViewStyle::CalcLargestMarkerHeight() {
}
}
}

View File

@ -32,6 +32,8 @@ private:
int size;
int max;
// Private so FontNames objects can not be copied
FontNames(const FontNames &);
public:
FontNames();
~FontNames();
@ -65,6 +67,7 @@ public:
FontRealised *frFirst;
size_t stylesSize;
Style *styles;
size_t nextExtendedStyle;
LineMarker markers[MARKER_MAX + 1];
int largestMarkerHeight;
Indicator indicators[INDIC_MAX + 1];
@ -101,12 +104,13 @@ public:
bool hotspotUnderline;
bool hotspotSingleLine;
/// Margins are ordered: Line Numbers, Selection Margin, Spacing Margin
enum { margins=5 };
int leftMarginWidth; ///< Spacing margin on left of text
int rightMarginWidth; ///< Spacing margin on right of text
int maskInLine; ///< Mask for markers to be put into text because there is nowhere for them to go in margin
MarginStyle ms[margins];
int fixedColumnWidth;
MarginStyle ms[SC_MAX_MARGIN+1];
int fixedColumnWidth; ///< Total width of margins
bool marginInside; ///< true: margin included in text view, false: separate views
int textStart; ///< Starting x position of text within the view
int zoomLevel;
WhiteSpaceVisibility viewWhitespace;
int whitespaceSize;
@ -115,6 +119,7 @@ public:
ColourDesired caretcolour;
ColourDesired additionalCaretColour;
bool showCaretLineBackground;
bool alwaysShowCaretLineBackground;
ColourDesired caretLineBackground;
int caretLineAlpha;
ColourDesired edgecolour;
@ -141,6 +146,8 @@ public:
void CreateFont(const FontSpecification &fs);
void Refresh(Surface &surface);
void AllocStyles(size_t sizeNew);
void ReleaseAllExtendedStyles();
int AllocateExtendedStyles(int numberStyles);
void EnsureStyle(size_t index);
void ResetDefaultStyle();
void ClearStyles();

View File

@ -1 +1 @@
323
331