aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--lexers/LexHaskell.cxx112
1 files changed, 87 insertions, 25 deletions
diff --git a/lexers/LexHaskell.cxx b/lexers/LexHaskell.cxx
index 2e75c4015..24d8606c4 100644
--- a/lexers/LexHaskell.cxx
+++ b/lexers/LexHaskell.cxx
@@ -63,11 +63,10 @@ static inline bool IsAWordStart(const int ch) {
return (IsLowerCase(ch) || IsUpperCase(ch) || ch == '_');
}
-static inline bool IsAWordChar(const int ch, const bool magicHash) {
+static inline bool IsAWordChar(const int ch) {
return ( IsAlphaNumeric(ch)
|| ch == '_'
- || ch == '\''
- || (magicHash && ch == '#'));
+ || ch == '\'');
}
static inline bool IsAnOperatorChar(const int ch) {
@@ -76,7 +75,23 @@ static inline bool IsAnOperatorChar(const int ch) {
|| ch == '&' || ch == '*' || ch == '+' || ch == '-'
|| ch == '.' || ch == '/' || ch == ':' || ch == '<'
|| ch == '=' || ch == '>' || ch == '?' || ch == '@'
- || ch == '\\' || ch == '^' || ch == '|' || ch == '~');
+ || ch == '^' || ch == '|' || ch == '~' || ch == '\\');
+}
+
+static inline void skipNewline(StyleContext &sc) {
+ if (sc.Match('\r', '\n')) {
+ sc.Forward(2);
+ } else if (sc.ch == '\n' || sc.ch == '\r') {
+ sc.Forward();
+ }
+}
+
+static inline void skipMagicHash(StyleContext &sc, const bool magicHash, const bool twoHashes=false) {
+ if (magicHash && sc.ch == '#')
+ if (twoHashes && sc.chNext == '#')
+ sc.Forward(2);
+ else
+ sc.Forward();
}
static void ColorizeHaskellDoc(unsigned int startPos, int length, int initStyle,
@@ -86,9 +101,19 @@ static void ColorizeHaskellDoc(unsigned int startPos, int length, int initStyle,
WordList &ffi = *keywordlists[1];
// property lexer.haskell.allow.hash
- // Set to 1 to allow the # character in identifiers with the haskell lexer.
+ // Set to 1 to allow the # character in identifiers and literals with the
+ // haskell lexer.
// (GHC -XMagicHash extension)
const bool magicHash = styler.GetPropertyInt("lexer.haskell.allow.hash") != 0;
+ // property lexer.haskell.allow.quotes
+ // Set to 1 to enable highlighting of Template Haskell name quotations
+ // and promoted constructors
+ // (GHC -XTemplateHaskell and -XDataKinds extensions)
+ const bool allowQuotes = styler.GetPropertyInt("lexer.haskell.allow.quotes") != 0;
+ // property lexer.haskell.import.safe
+ // Set to 1 to allow keyword "safe" in imports
+ // (GHC SafeHaskell extensions)
+ const bool highlightSafe = styler.GetPropertyInt("lexer.haskell.import.safe") != 0;
const bool stylingWithinPreprocessor = styler.GetPropertyInt("styling.within.preprocessor") != 0;
StyleContext sc(startPos, length, initStyle, styler);
@@ -112,7 +137,7 @@ static void ColorizeHaskellDoc(unsigned int startPos, int length, int initStyle,
style = SCE_HA_CAPITAL;
}
- while(IsAnOperatorChar(sc.ch))
+ while (IsAnOperatorChar(sc.ch))
sc.Forward();
styler.ColourTo(sc.currentPos - 1, style);
@@ -122,9 +147,11 @@ static void ColorizeHaskellDoc(unsigned int startPos, int length, int initStyle,
else if (sc.state == SCE_HA_STRING) {
if (sc.ch == '\"') {
sc.Forward();
+ skipMagicHash(sc, magicHash);
sc.SetState(SCE_HA_DEFAULT);
} else if (sc.ch == '\\') {
- sc.Forward(2);
+ sc.Forward();
+ skipNewline(sc);
} else if (sc.atLineEnd) {
sc.SetState(SCE_HA_DEFAULT);
} else {
@@ -135,6 +162,7 @@ static void ColorizeHaskellDoc(unsigned int startPos, int length, int initStyle,
else if (sc.state == SCE_HA_CHARACTER) {
if (sc.ch == '\'') {
sc.Forward();
+ skipMagicHash(sc, magicHash);
sc.SetState(SCE_HA_DEFAULT);
} else if (sc.ch == '\\') {
sc.Forward(2);
@@ -156,29 +184,38 @@ static void ColorizeHaskellDoc(unsigned int startPos, int length, int initStyle,
if (sc.ch == '+' || sc.ch == '-')
sc.Forward();
} else {
+ skipMagicHash(sc, magicHash, true);
sc.SetState(SCE_HA_DEFAULT);
}
}
// Keyword or Identifier
else if (sc.state == SCE_HA_IDENTIFIER) {
+ int style = isupper(sc.ch) ? SCE_HA_CAPITAL : SCE_HA_IDENTIFIER;
+
+ sc.Forward();
+
while (sc.More()) {
- if (IsAWordChar(sc.ch, magicHash)) {
+ if (IsAWordChar(sc.ch)) {
+ sc.Forward();
+ } else if (sc.ch == '#' && magicHash) {
sc.Forward();
- } else if (xmode == SCE_HA_CAPITAL && sc.ch=='.') {
+ break;
+ } else if (style == SCE_HA_CAPITAL && sc.ch=='.') {
if (isupper(sc.chNext)) {
- xmode = SCE_HA_CAPITAL;
sc.Forward();
+ style = SCE_HA_CAPITAL;
} else if (IsAWordStart(sc.chNext)) {
- xmode = SCE_HA_IDENTIFIER;
sc.Forward();
+ style = SCE_HA_IDENTIFIER;
} else if (IsAnOperatorChar(sc.chNext)) {
- xmode = SCE_HA_OPERATOR;
sc.Forward();
+ style = sc.ch == ':' ? SCE_HA_CAPITAL : SCE_HA_OPERATOR;
+ while (IsAnOperatorChar(sc.ch))
+ sc.Forward();
+ break;
} else {
break;
}
- } else if (xmode == SCE_HA_OPERATOR && IsAnOperatorChar(sc.ch)) {
- sc.Forward();
} else {
break;
}
@@ -187,14 +224,12 @@ static void ColorizeHaskellDoc(unsigned int startPos, int length, int initStyle,
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) {
+ if (mode == HA_MODE_IMPORT1 || mode == HA_MODE_IMPORT3) {
style = SCE_HA_MODULE;
new_mode = HA_MODE_IMPORT2;
} else if (mode == HA_MODE_MODULE) {
@@ -204,6 +239,11 @@ static void ColorizeHaskellDoc(unsigned int startPos, int length, int initStyle,
strcmp(s,"qualified") == 0) {
style = SCE_HA_KEYWORD;
new_mode = HA_MODE_IMPORT1;
+ } else if (highlightSafe &&
+ mode == HA_MODE_IMPORT1 &&
+ strcmp(s,"safe") == 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;
@@ -235,7 +275,6 @@ static void ColorizeHaskellDoc(unsigned int startPos, int length, int initStyle,
|| strcmp(s,"data") == 0)
new_mode = HA_MODE_TYPE;
- xmode = 0;
sc.ChangeState(SCE_HA_DEFAULT);
mode = new_mode;
}
@@ -288,7 +327,8 @@ static void ColorizeHaskellDoc(unsigned int startPos, int length, int initStyle,
if (stylingWithinPreprocessor && !IsAWordStart(sc.ch)) {
sc.SetState(SCE_HA_DEFAULT);
} else if (sc.ch == '\\' && !stylingWithinPreprocessor) {
- sc.Forward(2);
+ sc.Forward();
+ skipNewline(sc);
} else if (sc.atLineEnd) {
sc.SetState(SCE_HA_DEFAULT);
} else {
@@ -332,14 +372,38 @@ static void ColorizeHaskellDoc(unsigned int startPos, int length, int initStyle,
xmode = 1;
}
// String
- else if (sc.Match('\"')) {
+ else if (sc.ch == '\"') {
sc.SetState(SCE_HA_STRING);
sc.Forward();
}
- // Character
- else if (sc.Match('\'')) {
- sc.SetState(SCE_HA_CHARACTER);
+ // Character or quoted name
+ else if (sc.ch == '\'') {
+ styler.ColourTo(sc.currentPos - 1, state);
sc.Forward();
+
+ int style = SCE_HA_CHARACTER;
+
+ if (allowQuotes) {
+ // Quoted type ''T
+ if (sc.ch=='\'' && IsAWordStart(sc.chNext)) {
+ sc.Forward();
+ style=SCE_HA_IDENTIFIER;
+ } else if (sc.chNext != '\'') {
+ // Quoted value or promoted constructor 'N
+ if (IsAWordStart(sc.ch)) {
+ style=SCE_HA_IDENTIFIER;
+ // Promoted constructor operator ':~>
+ } else if (sc.ch == ':') {
+ style=SCE_HA_OPERATOR;
+ // Promoted list or tuple '[T]
+ } else if (sc.ch == '[' || sc.ch== '(') {
+ styler.ColourTo(sc.currentPos - 1, SCE_HA_OPERATOR);
+ style=SCE_HA_DEFAULT;
+ }
+ }
+ }
+
+ sc.ChangeState(style);
}
// Preprocessor
else if (sc.atLineStart && sc.ch == '#') {
@@ -363,9 +427,7 @@ static void ColorizeHaskellDoc(unsigned int startPos, int length, int initStyle,
}
// 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();
} else {
if (sc.atLineEnd) {
// Remember the line state for future incremental lexing