diff --git a/Haskell-no-code.sublime-build b/Haskell-no-code.sublime-build index ce835d4..2bfc5db 100644 --- a/Haskell-no-code.sublime-build +++ b/Haskell-no-code.sublime-build @@ -1,5 +1,5 @@ { - "shell_cmd": "ghc -dynamic -fno-code \"$file\"", - "file_regex": "^(...*?):([0-9]*):?([0-9]*)", + "cmd": ["ghc", "-dynamic", "-fno-code", "$file"], + "file_regex": "^(.*):(\\d+):(\\d+):.*$", "selector": "source.haskell" } diff --git a/Haskell.sublime-syntax b/Haskell.sublime-syntax index d1ab2f5..db6fcb7 100644 --- a/Haskell.sublime-syntax +++ b/Haskell.sublime-syntax @@ -14,11 +14,9 @@ variables: decimal: '[{{digit}}][{{digit}}_]*' hexadecimal: '[{{hexit}}][{{hexit}}_]*' octal: '[{{octit}}][{{octit}}_]*' - type_head: '[A-Z]' - val_head: '[a-z_]' id_tail: '[a-zA-Z0-9_'']*' - type_id: '{{type_head}}{{id_tail}}' - val_id: '{{val_head}}{{id_tail}}' + type_id: '[A-Z]{{id_tail}}' + val_id: '[a-z_]{{id_tail}}' op_id: '[!#$%&*+./<=>?@\\\^|\-~:]+' contexts: @@ -98,7 +96,7 @@ contexts: scope: keyword.control.haskell - match: '\b([0-9]+\.[0-9]+([eE][+-]?[0-9]+)?|[0-9]+[eE][+-]?[0-9]+)\b' comment: Floats are always decimal - scope: constant.numeric.float.haskell + scope: constant.numeric.haskell - match: '\b([0-9]+|0([xX][0-9a-fA-F]+|[oO][0-7]+))\b' scope: constant.numeric.haskell - match: '^\s*(#)\s*\w+' @@ -181,20 +179,27 @@ contexts: 4: constant.character.escape.hexadecimal.haskell 5: constant.character.escape.control.haskell 6: punctuation.definition.string.end.haskell + - match: '^({{val_id}})\s*$' + captures: + 1: entity.name.function.haskell + comment: Dirty hack to capture function declarations where the type sig starts on the line below, potential for false-positives - match: '({{val_id}})\s*(::|∷)' comment: Function declarations with alphanumeric identifier captures: 1: entity.name.function.haskell 2: keyword.operator.haskell + - match: '^\(({{op_id}})\)\s*$' + captures: + 1: entity.name.function.haskell + comment: Dirty hack to capture function declarations where the type sig starts on the line below, potential for false-positives - match: '\(({{op_id}})\)\s*(::|∷)' comment: Function declarations with operator identifier captures: 1: entity.name.function.haskell 2: keyword.operator.haskell - match: '\b{{type_id}}' - scope: constant.other.haskell + scope: storage.type.haskell - include: comments - - include: infix_op - match: '{{op_id}}' scope: keyword.operator.haskell block_comment: @@ -215,31 +220,22 @@ contexts: - match: '--(?![!#$%&*+./<=>?@\\\^|~:])' scope: punctuation.definition.comment.haskell push: - - meta_scope: comment.line.double-dash.haskell + - meta_scope: comment.line.haskell - match: '$' pop: true - include: block_comment - infix_op: - - match: '(\({{op_id}}\)|\(,+\))' - comment: Infix operator in prefix position - scope: entity.name.function.infix.haskell module_exports: - match: '\(' push: + - include: comments + - match: '\b({{type_id}})(\(.[^\)]*\)|)' + captures: + 1: storage.type.haskell + - match: '{{op_id}}' + scope: keyword.operator.haskell - meta_scope: meta.declaration.exports.haskell - match: '\)' pop: true - - match: '\b{{val_id}}' - scope: entity.name.function.haskell - - match: '\b({{type_id}})\(..\)' - captures: - 1: storage.type.haskell - - match: '\b{{type_id}}' - scope: storage.type.haskell - - match: '\(({{op_id}})\)' - captures: - 1: entity.name.function.haskell - - include: comments module_name: - match: '{{type_id}}' scope: support.other.module.haskell diff --git a/syntax-test.hs b/syntax_test_haskell.hs similarity index 66% rename from syntax-test.hs rename to syntax_test_haskell.hs index 1d863a4..101c8a9 100644 --- a/syntax-test.hs +++ b/syntax_test_haskell.hs @@ -1,21 +1,28 @@ +-- SYNTAX TEST "Packages/Haskell/Haskell.sublime-syntax" {-# LANGUAGE FlexibleInstances, OverloadedStrings #-} +-- ^^^^^^^^ meta.preprocessor.haskell keyword.other.preprocessor module Main ( - Foo, +-- ^^^ keyword.other + Foo(str, int), +-- ^^^ meta.declaration.exports.haskell storage.type -- a nice comment in the module exports list Fooable(..), + DeriveMoreThanOne, +-- ^^^^^^^^^^^^^^^^^ meta.declaration.exports.haskell storage.type main, add, (-->), - (+:) +-- ^^^ meta.declaration.exports.haskell keyword.operator + (+:), +-- ^^^ meta.declaration.exports.haskell keyword.operator ) where - +-- ^^^^ keyword.other +import System.Exit (ExitCode(..), exitWith) +-- ^^^^^^^^ storage.type import Data.String +-- ^^^ keyword.other --- SublimeHaskell: --- doesn't handle 'do' block correctly, --- 'let' binding breaks subsequent lines, --- subsequent top-level declaration breaks main :: IO () main = do print (tryLet "this") @@ -24,23 +31,17 @@ main = do z <- pure 3 print (add x y z) putStrLn (str myFoo) + exitWith ExitSuccess -add :: Int -> Int -> Int -> Int +add + :: Int -> Int -> Int -> Int add x y z = x + y + z --- ST3: --- doesn't consider record fields to be definitions, --- doesn't correctly highlight derived class unless surrounded by parentheses --- SublimeHaskell: --- doesn't correctly highlight record fields beyond the first data Foo = Foo { str :: String , int :: Int } deriving Show --- SublimeHaskell: --- doens't correctly handle 'let' block, --- subsequent top-level declaration breaks tryLet :: String -> String tryLet this = let that = this ++ " that" @@ -51,18 +52,11 @@ tryLet this = emptyFoo :: Foo emptyFoo = Foo "" 0 --- ST3: --- incorrectly requires definition to follow signature, --- methods beyond the first method are not highlighted correctly, --- subsequent top-level declaration breaks --- doesn't consider operators to be definitions class Fooable a where toFoo :: a -> Foo fromFoo :: Foo -> a (<=>) :: Foo -> a -> Bool --- ST3: --- doesn't consider '&&' an operator instance Fooable Foo where toFoo = id fromFoo = id @@ -78,20 +72,12 @@ instance Fooable Int where fromFoo = int x <=> y = int x == y --- ST3 default: --- incorectly requires classes to have a 'where' clause, --- several subsequent top-level declarations break class Show a => Foolike a instance Foolike Foo instance Foolike a => Foolike [a] --- SimpleHaskell: --- misinterprets type annotations as definitions --- fixing this breaks record fields as definitions (see below) --- fixing this breaks classes with method on same line (see below) --- generally consider this break to be worth it, though pull requests welcomed myFoo :: Foo myFoo = Foo { str = multiLineString :: String @@ -100,8 +86,6 @@ myFoo = Foo -- where (this is to close the 'Foolike' declaration) --- ST3: doesn't recognize multi-line strings --- SublimeHaskell: doesn't handle multi-line strings correctly multiLineString :: IsString a => a multiLineString = "here\ @@ -110,10 +94,8 @@ multiLineString = \multiline\ \string" --- ST3: doesn't consider record fields to be definitions data OneLine a = OneLine { unOneLine :: a } --- ST3: doesn't consider class methods to be definitions when on same line class OneLiner a where oneLiner :: a -> OneLine a ---- @@ -163,7 +145,7 @@ someFunc' char int = replicate int char -- types with primes in their names newtype Foo' = Foo' { unFoo' :: Foo } --- operators and guards +-- operators, guards, and contexts (+:) :: Enum a => Int -> a -> a n +: x | n <= 0 = x