1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
--------------------------------------------------------------------------------
module Language.Haskell.Stylish.Step.UnicodeSyntax
( step
) where
--------------------------------------------------------------------------------
import Data.List (isPrefixOf,
sort)
import Data.Map (Map)
import qualified Data.Map as M
import Data.Maybe (maybeToList)
import GHC.Hs.Binds
import GHC.Hs.Extension (GhcPs)
import GHC.Hs.Types
--------------------------------------------------------------------------------
import Language.Haskell.Stylish.Block
import Language.Haskell.Stylish.Editor
import Language.Haskell.Stylish.Module
import Language.Haskell.Stylish.Step
import Language.Haskell.Stylish.Step.LanguagePragmas (addLanguagePragma)
import Language.Haskell.Stylish.Util
--------------------------------------------------------------------------------
unicodeReplacements :: Map String String
unicodeReplacements = M.fromList
[ ("::", "∷")
, ("=>", "⇒")
, ("->", "→")
, ("<-", "←")
, ("forall", "∀")
, ("-<", "↢")
, (">-", "↣")
]
--------------------------------------------------------------------------------
replaceAll :: [(Int, [(Int, String)])] -> [Change String]
replaceAll = map changeLine'
where
changeLine' (r, ns) = changeLine r $ \str -> return $
applyChanges
[ change (Block c ec) (const repl)
| (c, needle) <- sort ns
, let ec = c + length needle - 1
, repl <- maybeToList $ M.lookup needle unicodeReplacements
] str
--------------------------------------------------------------------------------
groupPerLine :: [((Int, Int), a)] -> [(Int, [(Int, a)])]
groupPerLine = M.toList . M.fromListWith (++) .
map (\((r, c), x) -> (r, [(c, x)]))
-- | Find symbol positions in the module. Currently only searches in type
-- signatures.
findSymbol :: Module -> Lines -> String -> [((Int, Int), String)]
findSymbol module' ls sym =
[ (pos, sym)
| TypeSig _ funLoc typeLoc <- everything (rawModuleDecls $ moduleDecls module') :: [Sig GhcPs]
, (funStart, _) <- infoPoints funLoc
, (_, typeEnd) <- infoPoints [hsSigWcType typeLoc]
, pos <- maybeToList $ between funStart typeEnd sym ls
]
--------------------------------------------------------------------------------
-- | Search for a needle in a haystack of lines. Only part the inside (startRow,
-- startCol), (endRow, endCol) is searched. The return value is the position of
-- the needle.
between :: (Int, Int) -> (Int, Int) -> String -> Lines -> Maybe (Int, Int)
between (startRow, startCol) (endRow, endCol) needle =
search (startRow, startCol) .
withLast (take endCol) .
withHead (drop $ startCol - 1) .
take (endRow - startRow + 1) .
drop (startRow - 1)
where
search _ [] = Nothing
search (r, _) ([] : xs) = search (r + 1, 1) xs
search (r, c) (x : xs)
| needle `isPrefixOf` x = Just (r, c)
| otherwise = search (r, c + 1) (tail x : xs)
--------------------------------------------------------------------------------
step :: Bool -> String -> Step
step = (makeStep "UnicodeSyntax" .) . step'
--------------------------------------------------------------------------------
step' :: Bool -> String -> Lines -> Module -> Lines
step' alp lg ls module' = applyChanges changes ls
where
changes = (if alp then addLanguagePragma lg "UnicodeSyntax" module' else []) ++
replaceAll perLine
toReplace = [ "::", "=>", "->" ]
perLine = sort $ groupPerLine $ concatMap (findSymbol module' ls) toReplace
|