Dear Geany Hackers,
I am using Haskell for most of my work and I want to have better
syntactic highlighting for it. After I successfully compiled and
installed Geany on my computer I did some fixes in the lexer. The
patch is attached.
This is the list of problems that I fixed:
- some keywords were not listed in filetypes.haskell
- in Haskell there are some words that are keywords only in some
context. For example here:
import Foo as Bar
'as' is a keyword but in all other contexts it is a normal
identifier. There are some other keywords like that
- The highligthting was failing if the operators are not separated by
spaces. For example here:
10+20
'+' is not highlighted. It worked fine only if I write 10 + 20.
- There was highlighting for data types, classes and instances but it
didn't work correctly. For example:
class Foo x where ....
here Foo is highlighted as class name. Unfortunately this worked
correctly only for very simple cases. For example
this is also correct declaration:
class Eq x => Foo x where
but in this case Eq will be highlighted which the right class name
is Foo. Since this case could be solved only by implementing
a full parser, I just removed this feature. It is not very useful anyway.
I hope that this patch will be added in the main repository. Let me
know if there is some special procedure for sending patches.
Best Regards,
Krasimir
Index: scintilla/include/SciLexer.h
===================================================================
--- scintilla/include/SciLexer.h (revision 5106)
+++ scintilla/include/SciLexer.h (working copy)
@@ -963,17 +963,14 @@
#define SCE_HA_NUMBER 3
#define SCE_HA_STRING 4
#define SCE_HA_CHARACTER 5
-#define SCE_HA_CLASS 6
-#define SCE_HA_MODULE 7
-#define SCE_HA_CAPITAL 8
-#define SCE_HA_DATA 9
-#define SCE_HA_IMPORT 10
-#define SCE_HA_OPERATOR 11
-#define SCE_HA_INSTANCE 12
-#define SCE_HA_COMMENTLINE 13
-#define SCE_HA_COMMENTBLOCK 14
-#define SCE_HA_COMMENTBLOCK2 15
-#define SCE_HA_COMMENTBLOCK3 16
+#define SCE_HA_MODULE 6
+#define SCE_HA_CAPITAL 7
+#define SCE_HA_DATA 8
+#define SCE_HA_OPERATOR 9
+#define SCE_HA_COMMENTLINE 10
+#define SCE_HA_COMMENTBLOCK 11
+#define SCE_HA_COMMENTBLOCK2 12
+#define SCE_HA_COMMENTBLOCK3 13
#define SCE_T3_DEFAULT 0
#define SCE_T3_X_DEFAULT 1
#define SCE_T3_PREPROCESSOR 2
Index: scintilla/LexHaskell.cxx
===================================================================
--- scintilla/LexHaskell.cxx (revision 5106)
+++ scintilla/LexHaskell.cxx (working copy)
@@ -7,6 +7,7 @@
*
* Written by Tobias Engvall - tumm at dtek dot chalmers dot se
*
+ * Various bug fixes by Krasimir Angelov
*
* TODO:
* * Implement a folder :)
@@ -48,9 +49,13 @@
// Max level of nested comments
#define SCE_HA_COMMENTMAX SCE_HA_COMMENTBLOCK3
+#define SCE_HA_IN_IMPORT1 0x100
+#define SCE_HA_IN_IMPORT2 0x200
+#define SCE_HA_IN_IMPORT3 0x300
+#define SCE_HA_IN_MODULE 0x400
+#define SCE_HA_IN_FFI 0x500
+#define SCE_HA_IN_TYPE 0x600
-enum kwType { kwOther, kwClass, kwData, kwInstance, kwImport, kwModule, kwType};
-
static inline bool IsNewline(const int ch) {
return (ch == '\n' || ch == '\r');
}
@@ -73,146 +78,184 @@
WordList *keywordlists[], Accessor &styler) {
WordList &keywords = *keywordlists[0];
+ WordList &ffi = *keywordlists[1];
- int kwLast = kwOther;
-
StyleContext sc(startPos, length, initStyle, styler);
- for (; sc.More(); sc.Forward()) {
+ while (sc.More()) {
+ int style = sc.state & 0xFF;
+ int mode = sc.state & ~0xFF;
// Check for state end
+
// Operator
- if (sc.state == SCE_HA_OPERATOR) {
- kwLast = kwOther;
- sc.SetState(SCE_HA_DEFAULT);
+ if (style == SCE_HA_OPERATOR) {
+ if (isascii(sc.ch) && isoperator(static_cast<char>(sc.ch))) {
+ sc.Forward();
+ } else {
+ styler.ColourTo(sc.currentPos - 1, style);
+ sc.ChangeState(SCE_HA_DEFAULT);
+ }
}
// String
- else if (sc.state == SCE_HA_STRING) {
+ else if (style == SCE_HA_STRING) {
if (sc.ch == '\"') {
- sc.ForwardSetState(SCE_HA_DEFAULT);
+ styler.ColourTo(sc.currentPos, style);
+ sc.ChangeState(SCE_HA_DEFAULT | mode);
} else if (sc.ch == '\\') {
sc.Forward();
}
+ sc.Forward();
}
// Char
- else if (sc.state == SCE_HA_CHARACTER) {
+ else if (style == SCE_HA_CHARACTER) {
if (sc.ch == '\'') {
- sc.ForwardSetState(SCE_HA_DEFAULT);
+ styler.ColourTo(sc.currentPos, style);
+ sc.ChangeState(SCE_HA_DEFAULT | mode);
} else if (sc.ch == '\\') {
sc.Forward();
}
+ sc.Forward();
}
// Number
- else if (sc.state == SCE_HA_NUMBER) {
- if (!IsADigit(sc.ch)) {
- sc.SetState(SCE_HA_DEFAULT);
+ else if (style == SCE_HA_NUMBER) {
+ if (IsADigit(sc.ch)) {
+ sc.Forward();
+ } else {
+ styler.ColourTo(sc.currentPos - 1, style);
+ sc.ChangeState(SCE_HA_DEFAULT);
}
}
- // Types, constructors, etc.
- else if (sc.state == SCE_HA_CAPITAL) {
- if (!IsAWordChar(sc.ch) || sc.ch == '.') {
- sc.SetState(SCE_HA_DEFAULT);
- }
- }
// Identifier
- else if (sc.state == SCE_HA_IDENTIFIER) {
- if (!IsAWordChar(sc.ch)) {
+ else if (style == SCE_HA_IDENTIFIER) {
+ if (IsAWordChar(sc.ch)) {
+ sc.Forward();
+ } else {
char s[100];
sc.GetCurrent(s, sizeof(s));
- int style = SCE_HA_IDENTIFIER;
- if ((kwLast == kwImport) || (strcmp(s,"qualified") == 0) || (strcmp(s,"as") == 0)) {
- style = SCE_HA_IMPORT;
- } else if (keywords.InList(s)) {
+ int new_mode = 0;
+ if (keywords.InList(s)) {
style = SCE_HA_KEYWORD;
- } else if (kwLast == kwData) {
- style = SCE_HA_DATA;
- } else if (kwLast == kwClass) {
- style = SCE_HA_CLASS;
- } else if (kwLast == kwModule) {
- style = SCE_HA_MODULE;
} else if (isupper(s[0])) {
- style = SCE_HA_CAPITAL;
- }
- sc.ChangeState(style);
- sc.SetState(SCE_HA_DEFAULT);
- if (style == SCE_HA_KEYWORD) {
- if (0 == strcmp(s, "class"))
- kwLast = kwClass;
- else if (0 == strcmp(s, "data"))
- kwLast = kwData;
- else if (0 == strcmp(s, "instance"))
- kwLast = kwInstance;
- else if (0 == strcmp(s, "import"))
- kwLast = kwImport;
- else if (0 == strcmp(s, "module"))
- kwLast = kwModule;
+ if (mode >= SCE_HA_IN_IMPORT1 && mode <= SCE_HA_IN_IMPORT3) {
+ style = SCE_HA_MODULE;
+ new_mode = SCE_HA_IN_IMPORT2;
+ } else if (mode == SCE_HA_IN_MODULE)
+ style = SCE_HA_MODULE;
else
- kwLast = kwOther;
- } else if (style == SCE_HA_CLASS || style == SCE_HA_IMPORT ||
- style == SCE_HA_MODULE || style == SCE_HA_CAPITAL ||
- style == SCE_HA_DATA || style == SCE_HA_INSTANCE) {
- kwLast = kwOther;
+ style = SCE_HA_CAPITAL;
+ } else if (mode == SCE_HA_IN_IMPORT1 &&
+ strcmp(s,"qualified") == 0) {
+ style = SCE_HA_KEYWORD;
+ new_mode = SCE_HA_IN_IMPORT1;
+ } else if (mode == SCE_HA_IN_IMPORT2) {
+ if (strcmp(s,"as") == 0) {
+ style = SCE_HA_KEYWORD;
+ new_mode = SCE_HA_IN_IMPORT3;
+ } else if (strcmp(s,"hiding") == 0) {
+ style = SCE_HA_KEYWORD;
+ }
+ } else if (mode == SCE_HA_IN_FFI) {
+ if (ffi.InList(s)) {
+ style = SCE_HA_KEYWORD;
+ new_mode = SCE_HA_IN_FFI;
+ }
}
+ else if (mode == SCE_HA_IN_TYPE) {
+ if (strcmp(s,"family") == 0)
+ style = SCE_HA_KEYWORD;
+ }
+ styler.ColourTo(sc.currentPos - 1, style);
+ if (strcmp(s,"import") == 0 && mode != SCE_HA_IN_FFI)
+ new_mode = SCE_HA_IN_IMPORT1;
+ else if (strcmp(s,"module") == 0)
+ new_mode = SCE_HA_IN_MODULE;
+ else if (strcmp(s,"foreign") == 0)
+ new_mode = SCE_HA_IN_FFI;
+ else if (strcmp(s,"type") == 0)
+ new_mode = SCE_HA_IN_TYPE;
+ sc.ChangeState(SCE_HA_DEFAULT | new_mode);
}
}
+
// Comments
// Oneliner
- else if (sc.state == SCE_HA_COMMENTLINE) {
- if (IsNewline(sc.ch))
- sc.SetState(SCE_HA_DEFAULT);
+ else if (style == SCE_HA_COMMENTLINE) {
+ if (IsNewline(sc.ch)) {
+ styler.ColourTo(sc.currentPos - 1, style);
+ sc.ChangeState(SCE_HA_DEFAULT | mode);
+ } else {
+ sc.Forward();
+ }
}
// Nested
- else if (sc.state >= SCE_HA_COMMENTBLOCK) {
+ else if (style >= SCE_HA_COMMENTBLOCK) {
if (sc.Match("{-")) {
- if (sc.state < SCE_HA_COMMENTMAX)
- sc.SetState(sc.state + 1);
+ styler.ColourTo(sc.currentPos - 1, style);
+ if (style < SCE_HA_COMMENTMAX)
+ sc.ChangeState((style + 1) | mode);
+ sc.Forward(2);
}
else if (sc.Match("-}")) {
+ sc.Forward(2);
+ styler.ColourTo(sc.currentPos - 1, style);
+ if (style == SCE_HA_COMMENTBLOCK)
+ sc.ChangeState(SCE_HA_DEFAULT | mode);
+ else
+ sc.ChangeState((style - 1) | mode);
+ } else {
sc.Forward();
- if (sc.state == SCE_HA_COMMENTBLOCK)
- sc.ForwardSetState(SCE_HA_DEFAULT);
- else
- sc.ForwardSetState(sc.state - 1);
}
}
// New state?
- if (sc.state == SCE_HA_DEFAULT) {
+ if (style == SCE_HA_DEFAULT) {
// Digit
if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
- sc.SetState(SCE_HA_NUMBER);
+ styler.ColourTo(sc.currentPos - 1, style);
+ sc.Forward();
+ sc.ChangeState(SCE_HA_NUMBER);
if (sc.ch == '0' && (sc.chNext == 'X' || sc.chNext == 'x')) { // Match anything starting with "0x" or "0X", too
- sc.Forward(1);
+ sc.Forward();
}
}
// Comment line
else if (sc.Match("--")) {
- sc.SetState(SCE_HA_COMMENTLINE);
+ styler.ColourTo(sc.currentPos - 1, style);
+ sc.Forward(2);
+ sc.ChangeState(SCE_HA_COMMENTLINE | mode);
// Comment block
}
else if (sc.Match("{-")) {
- sc.SetState(SCE_HA_COMMENTBLOCK);
+ styler.ColourTo(sc.currentPos - 1, style);
+ sc.Forward(2);
+ sc.ChangeState(SCE_HA_COMMENTBLOCK | mode);
}
// String
else if (sc.Match('\"')) {
- sc.SetState(SCE_HA_STRING);
+ styler.ColourTo(sc.currentPos - 1, style);
+ sc.Forward();
+ sc.ChangeState(SCE_HA_STRING | mode);
}
// Character
else if (sc.Match('\'')) {
- sc.SetState(SCE_HA_CHARACTER);
+ styler.ColourTo(sc.currentPos - 1, style);
+ sc.Forward();
+ sc.ChangeState(SCE_HA_CHARACTER | mode);
}
- // Stringstart
- else if (sc.Match('\"')) {
- sc.SetState(SCE_HA_STRING);
- }
// Operator
else if (isascii(sc.ch) && isoperator(static_cast<char>(sc.ch))) {
- sc.SetState(SCE_HA_OPERATOR);
+ styler.ColourTo(sc.currentPos - 1, style);
+ sc.Forward();
+ sc.ChangeState(SCE_HA_OPERATOR);
}
// Keyword
else if (IsAWordStart(sc.ch)) {
- sc.SetState(SCE_HA_IDENTIFIER);
+ styler.ColourTo(sc.currentPos - 1, style);
+ sc.Forward();
+ sc.ChangeState(SCE_HA_IDENTIFIER | mode);
+ } else {
+ sc.Forward();
}
-
}
}
sc.Complete();
Index: src/highlighting.c
===================================================================
--- src/highlighting.c (revision 5106)
+++ src/highlighting.c (working copy)
@@ -2365,7 +2365,7 @@
static void styleset_haskell_init(gint ft_id, GKeyFile *config, GKeyFile *config_home)
{
- new_styleset(ft_id, 17);
+ new_styleset(ft_id, 13);
get_keyfile_style(config, config_home, "default", &style_sets[ft_id].styling[0]);
get_keyfile_style(config, config_home, "commentline", &style_sets[ft_id].styling[1]);
@@ -2374,20 +2374,17 @@
get_keyfile_style(config, config_home, "commentblock3", &style_sets[ft_id].styling[4]);
get_keyfile_style(config, config_home, "number", &style_sets[ft_id].styling[5]);
get_keyfile_style(config, config_home, "keyword", &style_sets[ft_id].styling[6]);
- get_keyfile_style(config, config_home, "import", &style_sets[ft_id].styling[7]);
- get_keyfile_style(config, config_home, "string", &style_sets[ft_id].styling[8]);
- get_keyfile_style(config, config_home, "character", &style_sets[ft_id].styling[9]);
- get_keyfile_style(config, config_home, "class", &style_sets[ft_id].styling[10]);
- get_keyfile_style(config, config_home, "operator", &style_sets[ft_id].styling[11]);
- get_keyfile_style(config, config_home, "identifier", &style_sets[ft_id].styling[12]);
- get_keyfile_style(config, config_home, "instance", &style_sets[ft_id].styling[13]);
- get_keyfile_style(config, config_home, "capital", &style_sets[ft_id].styling[14]);
- get_keyfile_style(config, config_home, "module", &style_sets[ft_id].styling[15]);
- get_keyfile_style(config, config_home, "data", &style_sets[ft_id].styling[16]);
+ get_keyfile_style(config, config_home, "string", &style_sets[ft_id].styling[7]);
+ get_keyfile_style(config, config_home, "character", &style_sets[ft_id].styling[8]);
+ get_keyfile_style(config, config_home, "operator", &style_sets[ft_id].styling[9]);
+ get_keyfile_style(config, config_home, "identifier", &style_sets[ft_id].styling[10]);
+ get_keyfile_style(config, config_home, "capital", &style_sets[ft_id].styling[11]);
+ get_keyfile_style(config, config_home, "module", &style_sets[ft_id].styling[12]);
- style_sets[ft_id].keywords = g_new(gchar*, 2);
+ style_sets[ft_id].keywords = g_new(gchar*, 3);
get_keyfile_keywords(config, config_home, "keywords", ft_id, 0);
- style_sets[ft_id].keywords[1] = NULL;
+ get_keyfile_keywords(config, config_home, "ffi", ft_id, 1);
+ style_sets[ft_id].keywords[2] = NULL;
}
@@ -2396,6 +2393,7 @@
apply_filetype_properties(sci, SCLEX_HASKELL, ft_id);
sci_set_keywords(sci, 0, style_sets[ft_id].keywords[0]);
+ sci_set_keywords(sci, 1, style_sets[ft_id].keywords[1]);
set_sci_style(sci, STYLE_DEFAULT, ft_id, 0);
set_sci_style(sci, SCE_HA_DEFAULT, ft_id, 0);
@@ -2405,16 +2403,12 @@
set_sci_style(sci, SCE_HA_COMMENTBLOCK3, ft_id, 4);
set_sci_style(sci, SCE_HA_NUMBER, ft_id, 5);
set_sci_style(sci, SCE_HA_KEYWORD, ft_id, 6);
- set_sci_style(sci, SCE_HA_IMPORT, ft_id, 7);
- set_sci_style(sci, SCE_HA_STRING, ft_id, 8);
- set_sci_style(sci, SCE_HA_CHARACTER, ft_id, 9);
- set_sci_style(sci, SCE_HA_CLASS, ft_id, 10);
- set_sci_style(sci, SCE_HA_OPERATOR, ft_id, 11);
- set_sci_style(sci, SCE_HA_IDENTIFIER, ft_id, 12);
- set_sci_style(sci, SCE_HA_INSTANCE, ft_id, 13);
- set_sci_style(sci, SCE_HA_CAPITAL, ft_id, 14);
- set_sci_style(sci, SCE_HA_MODULE, ft_id, 15);
- set_sci_style(sci, SCE_HA_DATA, ft_id, 16);
+ set_sci_style(sci, SCE_HA_STRING, ft_id, 7);
+ set_sci_style(sci, SCE_HA_CHARACTER, ft_id, 8);
+ set_sci_style(sci, SCE_HA_OPERATOR, ft_id, 9);
+ set_sci_style(sci, SCE_HA_IDENTIFIER, ft_id, 10);
+ set_sci_style(sci, SCE_HA_CAPITAL, ft_id, 11);
+ set_sci_style(sci, SCE_HA_MODULE, ft_id, 12);
}
Index: data/filetypes.haskell
===================================================================
--- data/filetypes.haskell (revision 5106)
+++ data/filetypes.haskell (working copy)
@@ -8,20 +8,17 @@
commentblock3=0x808080;0xffffff;false;false
number=0x007f00;0xffffff;false;false
keyword=0x00007f;0xffffff;true;false
-import=0x991111;0xffffff;false;false
string=0xff901e;0xffffff;false;false
character=0x7f007f;0xffffff;false;false
-class=0x0000d0;0xffffff;false;false
operator=0x301010;0xffffff;false;false
identifier=0x000000;0xffffff;false;false
-instance=0x000000;0xffffff;false;false
capital=0x635b00;0xffffff;false;false
module=0x007f7f;0xffffff;false;false
-data=0x000000;0xffffff;false;false
[keywords]
# all items must be in one line
-keywords=as case class data deriving do else if import in infixl infixr instance let module of primitive qualified then type where
+keywords=case class data default deriving do else if import in infix infixl infixr instance let module newtype of then type where forall mdo foreign rec proc
+ffi=import export label dynamic safe threadsafe unsafe stdcall ccall dotnet
[settings]
_______________________________________________
Geany-devel mailing list
[email protected]
http://lists.uvena.de/cgi-bin/mailman/listinfo/geany-devel