diff options
Diffstat (limited to 'lexers/LexHaskell.cxx')
| -rw-r--r-- | lexers/LexHaskell.cxx | 95 | 
1 files changed, 68 insertions, 27 deletions
| diff --git a/lexers/LexHaskell.cxx b/lexers/LexHaskell.cxx index 2d16e6934..8d7b6468d 100644 --- a/lexers/LexHaskell.cxx +++ b/lexers/LexHaskell.cxx @@ -10,13 +10,12 @@   *   *    Several bug fixes by Krasimir Angelov - kr.angelov at gmail.com   * - *    Improvements by kudah <kudahkukarek@gmail.com> + *    Improved by kudah <kudahkukarek@gmail.com>   *   *    TODO: - *    * Fold group declarations, comments, pragmas, #ifdefs, explicit layout, lists, tuples, quasi-quotes, splces, etc, etc, etc. - *    * Nice Character-lexing (stuff inside '\''), LexPython has - *      this. - * + *    * A proper lexical folder to fold group declarations, comments, pragmas, + *      #ifdefs, explicit layout, lists, tuples, quasi-quotes, splces, etc, etc, + *      etc.   *   *****************************************************************/  #include <stdlib.h> @@ -56,8 +55,17 @@ using namespace Scintilla;  #define INDENT_OFFSET       1 +static inline bool IsAlpha(const int ch) { +   return (ch >= 'a' && ch <= 'z') +       || (ch >= 'A' && ch <= 'Z'); +} + +static inline bool IsAnIdentifierStart(const int ch) { +   return (IsLowerCase(ch) || ch == '_'); +} +  static inline bool IsAWordStart(const int ch) { -   return (IsLowerCase(ch) || IsUpperCase(ch) || ch == '_'); +   return (IsAlpha(ch) || ch == '_');  }  static inline bool IsAWordChar(const int ch) { @@ -83,9 +91,14 @@ static inline bool IsCommentStyle(int style) {     return (style >= SCE_HA_COMMENTLINE && style <= SCE_HA_COMMENTBLOCK3);  } +inline int StyleFromNestLevel(const int nestLevel) { +      return SCE_HA_COMMENTBLOCK + (nestLevel % 3); +   } +  struct OptionsHaskell {     bool magicHash;     bool allowQuotes; +   bool implicitParams;     bool highlightSafe;     bool stylingWithinPreprocessor;     bool fold; @@ -94,9 +107,10 @@ struct OptionsHaskell {     bool foldImports;     bool foldIndentedImports;     OptionsHaskell() { -      magicHash = true; -      allowQuotes = true; -      highlightSafe = true; +      magicHash = true;       // Widespread use, enabled by default. +      allowQuotes = true;     // Widespread use, enabled by default. +      implicitParams = false; // Fell out of favor, seldom used, disabled. +      highlightSafe = true;   // Moderately used, doesn't hurt to enable.        stylingWithinPreprocessor = false;        fold = false;        foldComment = false; @@ -115,17 +129,23 @@ static const char * const haskellWordListDesc[] = {  struct OptionSetHaskell : public OptionSet<OptionsHaskell> {     OptionSetHaskell() {        DefineProperty("lexer.haskell.allow.hash", &OptionsHaskell::magicHash, -         "Set to 1 to allow the '#' character at the end of identifiers and " -         "literals with the haskell lexer (GHC -XMagicHash extension)"); +         "Set to 0 to disallow the '#' character at the end of identifiers and " +         "literals with the haskell lexer " +         "(GHC -XMagicHash extension)");        DefineProperty("lexer.haskell.allow.quotes", &OptionsHaskell::allowQuotes, -         "Set to 1 to enable highlighting of Template Haskell name quotations " +         "Set to 0 to disable highlighting of Template Haskell name quotations "           "and promoted constructors "           "(GHC -XTemplateHaskell and -XDataKinds extensions)"); +      DefineProperty("lexer.haskell.allow.questionmark", &OptionsHaskell::implicitParams, +         "Set to 1 to allow the '?' character at the start of identifiers " +         "with the haskell lexer " +         "(GHC & Hugs -XImplicitParams extension)"); +        DefineProperty("lexer.haskell.import.safe", &OptionsHaskell::highlightSafe, -         "Set to 1 to allow keyword \"safe\" in imports " -         "(GHC SafeHaskell extensions)"); +         "Set to 0 to disallow \"safe\" keyword in imports " +         "(GHC -XSafe, -XTrustworthy, -XUnsafe extensions)");        DefineProperty("styling.within.preprocessor", &OptionsHaskell::stylingWithinPreprocessor,           "For Haskell code, determines whether all preprocessor code is styled in the " @@ -271,6 +291,10 @@ void SCI_METHOD LexerHaskell::Lex(unsigned int startPos, int length, int initSty                                   ,IDocument *pAccess) {     LexAccessor styler(pAccess); +   // Do not leak onto next line +	if (initStyle == SCE_HA_STRINGEOL) +		initStyle = SCE_HA_DEFAULT; +     StyleContext sc(startPos, length, initStyle, styler);     int lineCurrent = styler.GetLine(startPos); @@ -295,6 +319,11 @@ void SCI_METHOD LexerHaskell::Lex(unsigned int startPos, int length, int initSty           lineCurrent++;        } +      if (sc.atLineStart && (sc.state == SCE_HA_STRING || sc.state == SCE_HA_CHARACTER)) { +			// Prevent SCE_HA_STRINGEOL from leaking back to previous line +			sc.SetState(sc.state); +		} +        // Handle line continuation generically.        if (sc.ch == '\\' &&           (  sc.state == SCE_HA_STRING @@ -338,8 +367,8 @@ void SCI_METHOD LexerHaskell::Lex(unsigned int startPos, int length, int initSty           } else if (sc.ch == '\\') {              sc.Forward(2);           } else if (sc.atLineEnd) { -            sc.SetState(SCE_HA_DEFAULT); -            sc.Forward(); // prevent double counting a line +            sc.ChangeState(SCE_HA_STRINGEOL); +            sc.ForwardSetState(SCE_HA_DEFAULT);           } else {              sc.Forward();           } @@ -353,8 +382,8 @@ void SCI_METHOD LexerHaskell::Lex(unsigned int startPos, int length, int initSty           } else if (sc.ch == '\\') {              sc.Forward(2);           } else if (sc.atLineEnd) { -            sc.SetState(SCE_HA_DEFAULT); -            sc.Forward(); // prevent double counting a line +            sc.ChangeState(SCE_HA_STRINGEOL); +            sc.ForwardSetState(SCE_HA_DEFAULT);           } else {              sc.Forward();           } @@ -415,7 +444,7 @@ void SCI_METHOD LexerHaskell::Lex(unsigned int startPos, int length, int initSty           if (keywords.InList(s)) {              style = SCE_HA_KEYWORD; -         } else if (isupper(s[0])) { +         } else if (style == SCE_HA_CAPITAL) {              if (mode == HA_MODE_IMPORT1 || mode == HA_MODE_IMPORT3) {                 style    = SCE_HA_MODULE;                 new_mode = HA_MODE_IMPORT2; @@ -481,17 +510,18 @@ void SCI_METHOD LexerHaskell::Lex(unsigned int startPos, int length, int initSty           }        }              // Nested -      else if (sc.state == SCE_HA_COMMENTBLOCK) { +      else if (IsCommentBlockStyle(sc.state)) {           if (sc.Match('{','-')) { +            sc.SetState(StyleFromNestLevel(nestLevel));              sc.Forward(2);              nestLevel++; -         } -         else if (sc.Match('-','}')) { +         } else if (sc.Match('-','}')) {              sc.Forward(2);              nestLevel--; -            if (nestLevel == 0) { -               sc.SetState(SCE_HA_DEFAULT); -            } +            sc.SetState( +               nestLevel == 0 +                  ? SCE_HA_DEFAULT +                  : StyleFromNestLevel(nestLevel - 1));           } else {              sc.Forward();           } @@ -508,7 +538,7 @@ void SCI_METHOD LexerHaskell::Lex(unsigned int startPos, int length, int initSty        }              // Preprocessor        else if (sc.state == SCE_HA_PREPROCESSOR) { -         if (options.stylingWithinPreprocessor && !IsAWordStart(sc.ch)) { +         if (options.stylingWithinPreprocessor && !IsAlpha(sc.ch)) {              sc.SetState(SCE_HA_DEFAULT);           } else if (sc.atLineEnd) {              sc.SetState(SCE_HA_DEFAULT); @@ -549,7 +579,7 @@ void SCI_METHOD LexerHaskell::Lex(unsigned int startPos, int length, int initSty           }           // Comment block           else if (sc.Match('{','-')) { -            sc.SetState(SCE_HA_COMMENTBLOCK); +            sc.SetState(StyleFromNestLevel(nestLevel));              sc.Forward(2);              nestLevel++;           } @@ -587,6 +617,17 @@ void SCI_METHOD LexerHaskell::Lex(unsigned int startPos, int length, int initSty              sc.ChangeState(style);           } +         // Operator starting with '?' or an implicit parameter +         else if (sc.ch == '?') { +            int style = SCE_HA_OPERATOR; + +            if (options.implicitParams && IsAnIdentifierStart(sc.chNext)) { +                  sc.Forward(); +                  style = SCE_HA_IDENTIFIER; +            } + +            sc.ChangeState(style); +         }           // Preprocessor           else if (sc.atLineStart && sc.ch == '#') {              mode = HA_MODE_DEFAULT; | 
