-------------------------------------------------------------------------------- module Language.Haskell.Stylish.Step.UnicodeSyntax ( step ) where -------------------------------------------------------------------------------- import qualified Data.Map as M import qualified GHC.Hs as GHC import qualified GHC.Types.SrcLoc as GHC -------------------------------------------------------------------------------- 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 (everything) {- -------------------------------------------------------------------------------- unicodeReplacements :: Map String String unicodeReplacements = M.fromList [ ("::", "∷") , ("=>", "⇒") , ("->", "→") , ("<-", "←") , ("forall", "∀") , ("-<", "↢") , (">-", "↣") ] -} -------------------------------------------------------------------------------- -- Simple type that can do replacments on single lines (not spanning, removing -- or adding lines). newtype Replacement = Replacement { unReplacement :: M.Map Int [(Int, Int, String)] } deriving (Show) -------------------------------------------------------------------------------- instance Semigroup Replacement where Replacement l <> Replacement r = Replacement $ M.unionWith (++) l r -------------------------------------------------------------------------------- instance Monoid Replacement where mempty = Replacement mempty -------------------------------------------------------------------------------- mkReplacement :: GHC.RealSrcSpan -> String -> Replacement mkReplacement rss repl | GHC.srcSpanStartLine rss /= GHC.srcSpanEndLine rss = Replacement mempty | otherwise = Replacement $ M.singleton (GHC.srcSpanStartLine rss) [(GHC.srcSpanStartCol rss, GHC.srcSpanEndCol rss, repl)] -------------------------------------------------------------------------------- applyReplacement :: Replacement -> [String] -> [String] applyReplacement (Replacement repl) ls = do (i, l) <- zip [1 ..] ls case M.lookup i repl of Nothing -> pure l Just repls -> pure $ go repls l where go [] l = l go ((xstart, xend, x) : repls) l = let l' = take (xstart - 1) l ++ x ++ drop (xend - 1) l in go (adjust (xstart, xend, x) <$> repls) l' adjust (xstart, xend, x) (ystart, yend, y) | ystart > xend = let offset = length x - (xend - xstart) in (ystart + offset, yend + offset, y) | otherwise = (ystart, yend, y) -------------------------------------------------------------------------------- hsTyReplacements :: GHC.HsType GHC.GhcPs -> Replacement hsTyReplacements (GHC.HsFunTy xann arr _ _) | GHC.HsUnrestrictedArrow GHC.NormalSyntax <- arr , GHC.AddRarrowAnn (GHC.EpaSpan loc) <- GHC.anns xann = mkReplacement loc "→" hsTyReplacements (GHC.HsQualTy _ (Just ctx) _) | Just arrow <- GHC.ac_darrow . GHC.anns . GHC.ann $ GHC.getLoc ctx , (GHC.NormalSyntax, GHC.EpaSpan loc) <- arrow = mkReplacement loc "⇒" hsTyReplacements _ = mempty -------------------------------------------------------------------------------- hsSigReplacements :: GHC.Sig GHC.GhcPs -> Replacement hsSigReplacements (GHC.TypeSig ann _ _) | GHC.AddEpAnn GHC.AnnDcolon epaLoc <- GHC.asDcolon $ GHC.anns ann , GHC.EpaSpan loc <- epaLoc = mkReplacement loc "∷" hsSigReplacements _ = mempty -------------------------------------------------------------------------------- step :: Bool -> String -> Step step = (makeStep "UnicodeSyntax" .) . step' -------------------------------------------------------------------------------- step' :: Bool -> String -> Lines -> Module -> Lines step' alp lg ls modu = applyChanges (if alp then addLanguagePragma lg "UnicodeSyntax" modu else []) $ applyReplacement replacement ls where replacement = foldMap hsTyReplacements (everything modu) <> foldMap hsSigReplacements (everything modu)