-
-
Notifications
You must be signed in to change notification settings - Fork 367
/
StylishHaskell.hs
97 lines (87 loc) · 4.1 KB
/
StylishHaskell.hs
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
{-# LANGUAGE CPP #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ViewPatterns #-}
module Ide.Plugin.StylishHaskell
( descriptor
, provider
, Log
)
where
import Control.Monad.Except (throwError)
import Control.Monad.IO.Class
import Data.Text (Text)
import qualified Data.Text as T
import Development.IDE hiding (getExtensions,
pluginHandlers)
import Development.IDE.Core.PluginUtils
import Development.IDE.GHC.Compat (ModSummary (ms_hspp_opts),
extensionFlags)
import qualified Development.IDE.GHC.Compat.Util as Util
import GHC.LanguageExtensions.Type
import Ide.Plugin.Error (PluginError (PluginInternalError))
import Ide.PluginUtils
import Ide.Types hiding (Config)
import Language.Haskell.Stylish
import Language.LSP.Protocol.Types as LSP
import System.Directory
import System.FilePath
data Log
= LogLanguageExtensionFromDynFlags
instance Pretty Log where
pretty = \case
LogLanguageExtensionFromDynFlags -> "stylish-haskell uses the language extensions from DynFlags"
descriptor :: Recorder (WithPriority Log) -> PluginId -> PluginDescriptor IdeState
descriptor recorder plId = (defaultPluginDescriptor plId desc)
{ pluginHandlers = mkFormattingHandlers (provider recorder)
}
where
desc = "Provides formatting of Haskell files via stylish-haskell. Built with stylish-haskell-" <> VERSION_stylish_haskell
-- | Formatter provider of stylish-haskell.
-- Formats the given source in either a given Range or the whole Document.
-- If the provider fails an error is returned that can be displayed to the user.
provider :: Recorder (WithPriority Log) -> FormattingHandler IdeState
provider recorder ide _token typ contents fp _opts = do
(msrModSummary -> ms_hspp_opts -> dyn) <- runActionE "stylish-haskell" ide $ useE GetModSummary fp
let file = fromNormalizedFilePath fp
config <- liftIO $ loadConfigFrom file
mergedConfig <- liftIO $ getMergedConfig dyn config
let (range, selectedContents) = case typ of
FormatText -> (fullRange contents, contents)
FormatRange r -> (normalize r, extractTextInRange (extendToFullLines r) contents)
result = runStylishHaskell file mergedConfig selectedContents
case result of
Left err -> throwError $ PluginInternalError $ T.pack $ "stylishHaskellCmd: " ++ err
Right new -> pure $ LSP.InL [TextEdit range new]
where
getMergedConfig dyn config
| null (configLanguageExtensions config)
= do
logWith recorder Info LogLanguageExtensionFromDynFlags
pure
$ config
{ configLanguageExtensions = getExtensions dyn }
| otherwise
= pure config
getExtensions = map showExtension . Util.toList . extensionFlags
showExtension Cpp = "CPP"
showExtension other = show other
-- | Recursively search in every directory of the given filepath for .stylish-haskell.yaml.
-- If no such file has been found, return default config.
loadConfigFrom :: FilePath -> IO Config
loadConfigFrom file = do
currDir <- getCurrentDirectory
setCurrentDirectory (takeDirectory file)
config <- loadConfig (makeVerbose False) Nothing
setCurrentDirectory currDir
pure config
-- | Run stylish-haskell on the given text with the given configuration.
runStylishHaskell :: FilePath -- ^ Location of the file being formatted. Used for error message
-> Config -- ^ Configuration for stylish-haskell
-> Text -- ^ Text to format
-> Either String Text -- ^ Either formatted Text or an error message
runStylishHaskell file config = fmap fromLines . fmt . toLines
where
fromLines = T.pack . unlines
fmt = runSteps (configLanguageExtensions config) (Just file) (configSteps config)
toLines = lines . T.unpack