This repository has been archived by the owner on Oct 7, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 208
/
Ormolu.hs
114 lines (105 loc) · 3.85 KB
/
Ormolu.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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE CPP #-}
module Haskell.Ide.Engine.Plugin.Ormolu
( ormoluDescriptor
)
where
import Haskell.Ide.Engine.MonadTypes
#if __GLASGOW_HASKELL__ >= 806
import Control.Exception
import Control.Monad
import Control.Monad.IO.Class ( liftIO
, MonadIO(..)
)
import Data.Aeson ( Value(Null) )
import Data.Char
import Data.List
import Data.Maybe
import qualified Data.Text as T
import GHC
import Ormolu
import Haskell.Ide.Engine.PluginUtils
import Haskell.Ide.Engine.Support.HieExtras
import HIE.Bios.Types
import qualified DynFlags as D
import qualified EnumSet as S
#endif
ormoluDescriptor :: PluginId -> PluginDescriptor
ormoluDescriptor plId = PluginDescriptor
{ pluginId = plId
, pluginName = "Ormolu"
, pluginDesc = "A formatter for Haskell source code."
, pluginCommands = []
, pluginCodeActionProvider = Nothing
, pluginDiagnosticProvider = Nothing
, pluginHoverProvider = Nothing
, pluginSymbolProvider = Nothing
, pluginFormattingProvider = Just provider
}
provider :: FormattingProvider
#if __GLASGOW_HASKELL__ >= 806
provider contents uri typ _ = pluginGetFile contents uri $ \fp -> do
opts <- lookupComponentOptions fp
let cradleOpts =
map DynOption
$ filter exop
$ join
$ maybeToList
$ componentOptions
<$> opts
fromDyn tcm _ () =
let
df = getDynFlags tcm
pp =
let p = D.sPgm_F $ D.settings df
in if null p then [] else ["-pgmF=" <> p]
pm = map (("-fplugin=" <>) . moduleNameString) $ D.pluginModNames df
ex = map (("-X" <>) . show) $ S.toList $ D.extensionFlags df
in
return $ map DynOption $ pp <> pm <> ex
fileOpts <- ifCachedModuleAndData fp cradleOpts fromDyn
let
conf o = Config o False False True False
fmt :: T.Text -> [DynOption] -> IdeM (Either OrmoluException T.Text)
fmt cont o =
liftIO $ try @OrmoluException (ormolu (conf o) fp $ T.unpack cont)
case typ of
FormatText -> ret (fullRange contents) <$> fmt contents cradleOpts
FormatRange r ->
let
txt = T.lines $ extractRange r contents
lineRange (Range (Position sl _) (Position el _)) =
Range (Position sl 0) $ Position el $ T.length $ last txt
hIsSpace (h : _) = T.all isSpace h
hIsSpace _ = True
fixS t = if hIsSpace txt && (not $ hIsSpace t) then "" : t else t
fixE t = if T.all isSpace $ last txt then t else T.init t
unStrip ws new =
fixE $ T.unlines $ map (ws `T.append`) $ fixS $ T.lines new
mStrip = case txt of
(l : _) ->
let ws = fst $ T.span isSpace l
in (,) ws . T.unlines <$> traverse (T.stripPrefix ws) txt
_ -> Nothing
err = return $ IdeResultFail
(IdeError
PluginError
(T.pack
"You must format a whole block of code. Ormolu does not support arbitrary ranges."
)
Null
)
fmt' (ws, striped) =
ret (lineRange r) <$> (fmap (unStrip ws) <$> fmt striped fileOpts)
in
maybe err fmt' mStrip
where
ret _ (Left err) = IdeResultFail
(IdeError PluginError (T.pack $ "ormoluCmd: " ++ show err) Null)
ret r (Right new) = IdeResultOk [TextEdit r new]
exop s =
"-X" `isPrefixOf` s || "-fplugin=" `isPrefixOf` s || "-pgmF=" `isPrefixOf` s
#else
provider _ _ _ _ = return $ IdeResultOk [] -- NOP formatter
#endif