kakoune/rc/base/haskell.kak
Dan Rosén ef1a1e6bd3 Improve Haskell highlighter
Import keywords are put in keyword face instead of meta face.
This leaves room for pragmas and macros to be in the meta face.

Operator keywords are put in keyword face too.

Finally, expression keywords are put in face attribute.
2017-08-22 16:29:27 +02:00

113 lines
5.1 KiB
Plaintext

# http://haskell.org
# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
# Detection
# ‾‾‾‾‾‾‾‾‾
hook global BufCreate .*[.](hs) %{
set buffer filetype haskell
}
# Highlighters
# ‾‾‾‾‾‾‾‾‾‾‾‾
add-highlighter -group / regions -default code haskell \
string '(?<!\'\\)(?<!\')"' (?<!\\)(\\\\)*" '' \
macro ^\h*?\K# (?<!\\)\n '' \
pragma \{-# \#-\} \{- \
comment \{- -\} \{- \
comment --(?![!#$%&*+./<>?@\\\^|~=]) $ ''
add-highlighter -group /haskell/string fill string
add-highlighter -group /haskell/comment fill comment
add-highlighter -group /haskell/pragma fill meta
add-highlighter -group /haskell/macro fill meta
# Use (?<!['\w]) and (?!['\w]) instead of \b because ' is valid in identifiers
add-highlighter -group /haskell/code regex (?<!['\w])0x+[A-Fa-f0-9]+ 0:value
add-highlighter -group /haskell/code regex (?<!['\w])\d+([.]\d+)? 0:value
add-highlighter -group /haskell/code regex (?<!['\w])(import|hiding|qualified|module)(?!['\w]) 0:keyword
add-highlighter -group /haskell/code regex (?<!['\w])(import)(?!['\w])[^\n]+(?<!['\w])(as)(?!['\w]) 2:keyword
add-highlighter -group /haskell/code regex (?<!['\w])(class|data|default|deriving|infix|infixl|infixr|instance|module|newtype|pattern|type|where)(?!['\w]) 0:keyword
add-highlighter -group /haskell/code regex (?<!['\w])(case|do|else|if|in|let|mdo|of|proc|rec|then)(?!['\w]) 0:attribute
# The complications below is because period has many uses:
# As function composition operator (possibly without spaces) like "." and "f.g"
# Hierarchical modules like "Data.Maybe"
# Qualified imports like "Data.Maybe.Just", "Data.Maybe.maybe", "Control.Applicative.<$>"
# Quantifier separator in "forall a . [a] -> [a]"
# Enum comprehensions like "[1..]" and "[a..b]" (making ".." and "Module..." illegal)
# matches uppercase identifiers: Monad Control.Monad
# not non-space separated dot: Just.const
add-highlighter -group /haskell/code regex \b(\u['\w]*\.)*\u['\w]*(?!['\w])(?![.\l]) 0:variable
# matches infix identifier: `mod` `Apa._T'M`
add-highlighter -group /haskell/code regex `\b(\u['\w]*\.)*[\w]['\w]*` 0:operator
# matches imported operators: M.! M.. Control.Monad.>>
# not operator keywords: M... M.->
add-highlighter -group /haskell/code regex \b\u['\w]*\.(?!([~=|:@\\]|<-|->|=>|\.\.|::)[^~<=>|:!?/.@$*&#%+\^\-\\])[~<=>|:!?/.@$*&#%+\^\-\\]+ 0:operator
# matches dot: .
# not possibly incomplete import: a.
# not other operators: !. .!
add-highlighter -group /haskell/code regex (?<![\w~<=>|:!?/.@$*&#%+\^\-\\])\.(?![~<=>|:!?/.@$*&#%+\^\-\\]) 0:operator
# matches other operators: ... > < <= ^ <*> <$> etc
# not dot: .
# not operator keywords: @ .. -> :: ~
add-highlighter -group /haskell/code regex (?<![~<=>|:!?/.@$*&#%+\^\-\\])(?!([~=|:.@\\]|<-|->|=>|\.\.|::)[^~<=>|:!?/.@$*&#%+\^\-\\])[~<=>|:!?/.@$*&#%+\^\-\\]+ 0:operator
# matches operator keywords: @ ->
add-highlighter -group /haskell/code regex (?<![~<=>|:!?/.@$*&#%+\^\-\\])(@|~|<-|->|=>|::|=|:|[|])(?![~<=>|:!?/.@$*&#%+\^\-\\]) 1:keyword
# matches: forall [..variables..] .
# not the variables
add-highlighter -group /haskell/code regex \b(forall)\b[^.\n]*?(\.) 1:keyword 2:keyword
# matches 'x' '\\' '\'' '\n' '\0'
# not incomplete literals: '\'
# not valid identifiers: w' _'
add-highlighter -group /haskell/code regex (?<!\w)'([^\\]|[\\]['"\w\d\\])' 0:string
# this has to come after operators so '-' etc is correct
# Commands
# ‾‾‾‾‾‾‾‾
# http://en.wikibooks.org/wiki/Haskell/Indentation
def -hidden haskell-filter-around-selections %{
# remove trailing white spaces
try %{ exec -draft -itersel <a-x> s \h+$ <ret> d }
}
def -hidden haskell-indent-on-new-line %{
eval -draft -itersel %{
# copy -- comments prefix and following white spaces
try %{ exec -draft k <a-x> s ^\h*\K--\h* <ret> y gh j P }
# preserve previous line indent
try %{ exec -draft \; K <a-&> }
# align to first clause
try %{ exec -draft \; k x X s ^\h*(if|then|else)?\h*(([\w']+\h+)+=)?\h*(case\h+[\w']+\h+of|do|let|where)\h+\K.* <ret> s \`|.\' <ret> & }
# filter previous line
try %{ exec -draft k : haskell-filter-around-selections <ret> }
# indent after lines beginning with condition or ending with expression or =(
try %{ exec -draft \; k x <a-k> ^\h*(if)|(case\h+[\w']+\h+of|do|let|where|[=(])$ <ret> j <a-gt> }
}
}
# Initialization
# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾
hook -group haskell-highlight global WinSetOption filetype=haskell %{ add-highlighter ref haskell }
hook global WinSetOption filetype=haskell %{
set window extra_word_chars "'"
hook window InsertEnd .* -group haskell-hooks haskell-filter-around-selections
hook window InsertChar \n -group haskell-indent haskell-indent-on-new-line
}
hook -group haskell-highlight global WinSetOption filetype=(?!haskell).* %{ remove-highlighter haskell }
hook global WinSetOption filetype=(?!haskell).* %{
remove-hooks window haskell-indent
remove-hooks window haskell-hooks
}