Home Download Buy Blog Forum Support

ST 2/3 Haskell highlighting: various fixes inside

ST 2/3 Haskell highlighting: various fixes inside

Postby Senf on Mon Feb 18, 2013 9:58 pm

Haskell highlighting in Sublime 2/3 is not very good, so I just went to fix some of the stuff. You can find a file with some pathological examples at the end of this post, just paste it in Sublime and see what it looks like. Note that there are some of the class "it's a bug unless you can disable it" in in the list, just ignore those if you like them. A very brief description on how to fix the bug is also included, just edit your Haskell.tmLanguage file accordingly.

Fixed:
  • Comments in module declarations
  • Comments in imports
  • "import" or "module" inside an identifier doesn't break the whole layout anymore
  • Multiline strings aren't allowed in Haskell, but Sublime highlighted them as if they were (C-style)

Not fixed yet:
  • Multiple type constraints for one function
  • Multiline type declarations

Ideas on how to fix the remaining bugs are welcome.



Code: Select all
-- Sublime text Haskell highlighting issues



-- Comments in module declarations don't render properly
-- Fix: Add the following after the dict block containing "I don't know"
-- <dict>
--       <key>include</key>
--       <string>#comments</string>
-- </dict>
module Main (
      foo, -- This doesn't render as a comment
      bar
) where -- Works



-- Comments after imports don't work
-- Fix: Add the following after the #module_exports dict element:
-- <dict>
--       <key>include</key>
--       <string>#comments</string>
-- </dict>
import Data.List -- Comment
import Data.Maybe {- Comment -}



-- Class constraints are highlighted differently when they're parenthesized
-- Fix: Change
-- <string>\(\s*([A-Z][A-Za-z]*)\s+([a-z][A-Za-z_']*)\)\s*(=&gt;)</string>
-- to
-- <string>(?x) # x turns off whitespaces. This block matches a *single* constraint. Fix?
--       (\s*[A-Z][A-Za-z]*)\s+([a-z][A-Za-z_']*)\s*(=&gt;) # Non-parenthesized expression
--       |
--       \(\s*([A-Z][A-Za-z]*)\s+([a-z][A-Za-z_']*)\)\s*(=&gt;) # Parenthesized expression
-- </string>
cc  ::  (Monad a) => a -> a
cc' ::  Monad a  => a -> a



-- Custom types in type declarations have the wrong color
bar :: MyType a -> String -> String

-- Multiline type declarations render wrong
foo :: (Eq a) => MyType a -> String
    -> String



-- 'module' or 'import' in an identifier breaks highlighting.
-- Fix: change "(module)" to "\b(module)\b"
moduleInName = "This should render as a string, but doesn't.\n"
importInName = "This should render as a string, but doesn't.\n"



-- Strings over multiple lines have to be explicitly constructed using (++).
-- Fix: Go to the string section and change
--   <key>end</key>
--   <string>"</string>
-- to
--   <key>end</key>
--   <string>$|"</string>
baz = "You cannot write multiline
      strings directly in Haskell,
      but Sublime colors them like it."



-- Prelude names get special highlighting
-- Fix: Comment out the dict block containing 'length' and 'IO(Error)?'
qux :: IO Int -> Maybe Int
qux = length [1..10]
Senf
 
Posts: 5
Joined: Sun Sep 16, 2012 11:28 pm

Re: ST 2/3 Haskell highlighting: various fixes inside

Postby mgsloan on Sun Mar 10, 2013 11:52 am

Thanks a ton for this!! I was considering fixing this, because I need to work on a module that has a lot of uses of "module".

Probably would have been better to provide a diff.. Finding where to do those changes wasn't so trivial. Otherwise, great work! Some bugs I didn't know were there.

I fixed the multiline types by ending them on things that look like top level declarations, and fixed the constraints by removing special casing - constraints are near enough to types these days anyway. I hope some of these fixes make it to the main highlighter!

Finally, I added support for highlighting quasi-quotes as if they were multiline strings, and made $( parse as a keyword (even if the ending paren isn't opreatorized..)

Code: Select all
---Haskell.tmLanguageOld
+++ Haskell.tmLanguage
@@ -47,7 +47,7 @@
      </dict>
      <dict>
         <key>begin</key>
-         <string>(module)</string>
+         <string>\b(module)\b</string>
         <key>beginCaptures</key>
         <dict>
            <key>1</key>
@@ -193,6 +193,10 @@
               <key>include</key>
               <string>#module_exports</string>
            </dict>
+            <dict>
+               <key>include</key>
+               <string>#comments</string>
+            </dict>
         </array>
      </dict>
      <dict>
@@ -284,7 +288,7 @@
            </dict>
         </dict>
         <key>end</key>
-         <string>"</string>
+         <string>$|"</string>
         <key>endCaptures</key>
         <dict>
            <key>0</key>
@@ -314,6 +318,104 @@
               <string>\^[A-Z@\[\]\\\^_]</string>
               <key>name</key>
               <string>constant.character.escape.control.haskell</string>
+            </dict>
+         </array>
+      </dict>
+      <dict>
+         <key>comment</key>
+         <dict>Points out splices in ast quotes</dict>
+         <key>begin</key>
+         <string>\[(?:|e|d|t|p)\|</string>
+         <key>beginCaptures</key>
+         <dict>
+            <key>0</key>
+            <dict>
+               <key>name</key>
+               <string>keyword.other.quasibracket.haskell</string>
+            </dict>
+         </dict>
+         <key>end</key>
+         <string>(.*)(\|\])</string>
+         <key>endCaptures</key>
+         <dict>
+            <key>1</key>
+            <dict>
+               <key>name</key>
+               <string>string.quasiquoted.haskell</string>
+            </dict>
+            <key>2</key>
+            <dict>
+               <key>name</key>
+               <string>keyword.other.quasibracket.haskell</string>
+            </dict>
+         </dict>
+         <key>name</key>
+         <string>meta.other.quasiquote.haskell</string>
+         <key>patterns</key>
+         <array>
+            <dict>
+               <key>match</key>
+               <string>\$\(</string>
+               <key>name</key>
+               <string>keyword.other.splice.haskell</string>
+            </dict>
+            <dict>
+               <key>match</key>
+               <string>\$</string>
+               <key>name</key>
+               <string>string.quasiquoted.haskell</string>
+            </dict>
+            <dict>
+               <key>match</key>
+               <string>[^$]*</string>
+               <key>name</key>
+               <string>string.quasiquoted.haskell</string>
+            </dict>
+         </array>
+      </dict>
+      <dict>
+         <key>comment</key>
+         <string>Highlight the beginning of a splice.</string>
+         <key>match</key>
+         <string>\$\(</string>
+         <key>name</key>
+         <string>keyword.other.splice.haskell</string>
+      </dict>
+      <dict>
+         <key>begin</key>
+         <string>\[[a-zA-Z0-9_']*\|</string>
+         <key>beginCaptures</key>
+         <dict>
+            <key>0</key>
+            <dict>
+               <key>name</key>
+               <string>keyword.other.quasibracket.haskell</string>
+            </dict>
+         </dict>
+         <key>end</key>
+         <string>(.*)(\|\])</string>
+         <key>endCaptures</key>
+         <dict>
+            <key>1</key>
+            <dict>
+               <key>name</key>
+               <string>string.quasiquoted.haskell</string>
+            </dict>
+            <key>2</key>
+            <dict>
+               <key>name</key>
+               <string>keyword.other.quasibracket.haskell</string>
+            </dict>
+         </dict>
+         <key>name</key>
+         <string>meta.other.quasiquote.haskell</string>
+         <key>patterns</key>
+         <array>
+            <dict>
+               <key>match</key>
+               <string>.*</string>
+               <key>name</key>
+               <string>string.quasiquoted.haskell</string>
            </dict>
         </array>
      </dict>
@@ -385,7 +487,23 @@
            </dict>
         </dict>
         <key>end</key>
-         <string>$\n?</string>
+         <string>(?x)
+              ^(data|newtype|type|class|deriving)\s  # When a top level declaration starts
+            | ^[^=]*(=)[\sa-zA-Z0-9_\(]                # A function declaration
+         </string>
+         <key>endCaptures</key>
+         <dict>
+            <key>1</key>
+            <dict>
+               <key>name</key>
+               <string>keyword.other.haskell</string>
+            </dict>
+            <key>2</key>
+            <dict>
+               <key>name</key>
+               <string>keyword.operator.haskell</string>
+            </dict>
+         </dict>
         <key>name</key>
         <string>meta.function.type-declaration.haskell</string>
         <key>patterns</key>
@@ -395,12 +513,6 @@
               <string>#type_signature</string>
            </dict>
         </array>
-      </dict>
-      <dict>
-         <key>match</key>
-         <string>\b(Just|Nothing|Left|Right|True|False|LT|EQ|GT|\(\)|\[\])\b</string>
-         <key>name</key>
-         <string>support.constant.haskell</string>
      </dict>
      <dict>
         <key>match</key>
@@ -411,12 +523,6 @@
      <dict>
         <key>include</key>
         <string>#comments</string>
-      </dict>
-      <dict>
-         <key>match</key>
-         <string>\b(abs|acos|acosh|all|and|any|appendFile|applyM|asTypeOf|asin|asinh|atan|atan2|atanh|break|catch|ceiling|compare|concat|concatMap|const|cos|cosh|curry|cycle|decodeFloat|div|divMod|drop|dropWhile|elem|encodeFloat|enumFrom|enumFromThen|enumFromThenTo|enumFromTo|error|even|exp|exponent|fail|filter|flip|floatDigits|floatRadix|floatRange|floor|fmap|foldl|foldl1|foldr|foldr1|fromEnum|fromInteger|fromIntegral|fromRational|fst|gcd|getChar|getContents|getLine|head|id|init|interact|ioError|isDenormalized|isIEEE|isInfinite|isNaN|isNegativeZero|iterate|last|lcm|length|lex|lines|log|logBase|lookup|map|mapM|mapM_|max|maxBound|maximum|maybe|min|minBound|minimum|mod|negate|not|notElem|null|odd|or|otherwise|pi|pred|print|product|properFraction|putChar|putStr|putStrLn|quot|quotRem|read|readFile|readIO|readList|readLn|readParen|reads|readsPrec|realToFrac|recip|rem|repeat|replicate|return|reverse|round|scaleFloat|scanl|scanl1|scanr|scanr1|seq|sequence|sequence_|show|showChar|showList|showParen|showString|shows|showsPrec|significand|signum|sin|sinh|snd|span|splitAt|sqrt|subtract|succ|sum|tail|take|takeWhile|tan|tanh|toEnum|toInteger|toRational|truncate|uncurry|undefined|unlines|until|unwords|unzip|unzip3|userError|words|writeFile|zip|zip3|zipWith|zipWith3)\b</string>
-         <key>name</key>
-         <string>support.function.prelude.haskell</string>
      </dict>
      <dict>
         <key>include</key>
@@ -536,6 +642,10 @@
               <key>name</key>
               <string>meta.other.unknown.haskell</string>
            </dict>
+            <dict>
+               <key>include</key>
+               <string>#comments</string>
+            </dict>
         </array>
      </dict>
      <key>module_name</key>
@@ -568,30 +678,6 @@
         <key>patterns</key>
         <array>
            <dict>
-               <key>captures</key>
-               <dict>
-                  <key>1</key>
-                  <dict>
-                     <key>name</key>
-                     <string>entity.other.inherited-class.haskell</string>
-                  </dict>
-                  <key>2</key>
-                  <dict>
-                     <key>name</key>
-                     <string>variable.other.generic-type.haskell</string>
-                  </dict>
-                  <key>3</key>
-                  <dict>
-                     <key>name</key>
-                     <string>keyword.other.big-arrow.haskell</string>
-                  </dict>
-               </dict>
-               <key>match</key>
-               <string>\(\s*([A-Z][A-Za-z]*)\s+([a-z][A-Za-z_']*)\)\s*(=&gt;)</string>
-               <key>name</key>
-               <string>meta.class-constraint.haskell</string>
-            </dict>
-            <dict>
               <key>include</key>
               <string>#pragma</string>
            </dict>
@@ -606,12 +692,6 @@
               <string>=&gt;</string>
               <key>name</key>
               <string>keyword.other.big-arrow.haskell</string>
-            </dict>
-            <dict>
-               <key>match</key>
-               <string>\b(Int(eger)?|Maybe|Either|Bool|Float|Double|Char|String|Ordering|ShowS|ReadS|FilePath|IO(Error)?)\b</string>
-               <key>name</key>
-               <string>support.type.prelude.haskell</string>
            </dict>
            <dict>
               <key>match</key>
Last edited by mgsloan on Mon Mar 11, 2013 5:44 am, edited 8 times in total.
mgsloan
 
Posts: 2
Joined: Sat Jan 21, 2012 2:49 am

Re: ST 2/3 Haskell highlighting: various fixes inside

Postby mgsloan on Mon Mar 11, 2013 1:25 am

Updated the above post with a better regex for the end of type signatures, before it was broken for indented type signatures. It's still not perfect:

* Mulitple type declarations in a row (like in typeclasses) won't have the name of the function / (::) highlighted specially in the declarations that come after the first

* Highlighting of pattern matching broken immediately after type declaration

* Type declarations where (::) comes on the next line (a reasonably common style) don't highlight the type.
mgsloan
 
Posts: 2
Joined: Sat Jan 21, 2012 2:49 am

Re: ST 2/3 Haskell highlighting: various fixes inside

Postby Kaligule on Thu Dec 19, 2013 4:08 pm

Hi there,

I couldn't reproduce any of those highlighting errors, but I found some other ones:

Code: Select all
-- This is highlighted correctly:

function0 :: String -> String   -- function type declaration
function0 = id               -- function implementation

-- Syntax highlighting fails here...

class MyClass x where

   function1 :: x -> x      -- correctly highlighted
   function2 :: x -> x      -- is a function type declaration (should be colored like function 1)
   function3 :: x -> x      -- is a function type declaration (should be colored like function 1)
   function4 :: x -> x      -- is a function type declaration (should be colored like function 1)
   function4 = id         -- is colored corectly, as it is a defaultimplementation of function4
   function5 :: x -> x      -- is colored corectly
   function6 :: x -> x      -- is a function type declaration (should be colored like function 1)

-- ... and here

function7 :: String -> String
function7 = id



Scrrenshot of it:
http://imgur.com/Xb5Hofz

What should I do about it?
Kaligule
 
Posts: 1
Joined: Thu Dec 19, 2013 3:50 pm

Re: ST 2/3 Haskell highlighting: various fixes inside

Postby smugboy on Thu Apr 17, 2014 6:54 pm

I'm also wondering how to fix some syntax highlighting errors.

Image

Function name should be orange but turns out green in the data constructor definition. (:: isn't blue too)
Also, the function defined under the data Example doesn't have the orange highlighting(if I define another function then everything is fine).
smugboy
 
Posts: 1
Joined: Thu Apr 17, 2014 6:49 pm


Return to Technical Support

Who is online

Users browsing this forum: Exabot [Bot], Google [Bot] and 34 guests