Skip to content

Commit 460b455

Browse files
committed
Update to ormolu 0.5.0 and simplify plugin
Move makeDiffTextEdit from Haskell-IDE-Engine to PluginUtils.
1 parent 69b3516 commit 460b455

13 files changed

+137
-70
lines changed

cabal.project

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,4 @@ package ghcide
2424

2525
write-ghc-environment-files: never
2626

27-
index-state: 2020-03-24T21:15:10Z
27+
index-state: 2020-04-24T21:15:10Z

haskell-language-server.cabal

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ library
4949
Ide.Plugin.Pragmas
5050
Ide.Plugin.Floskell
5151
Ide.Plugin.Formatter
52+
Ide.PluginUtils
5253
Ide.Types
5354
Ide.Version
5455
other-modules:
@@ -65,6 +66,7 @@ library
6566
, containers
6667
, data-default
6768
, deepseq
69+
, Diff
6870
, directory
6971
, extra
7072
, filepath
@@ -95,7 +97,7 @@ library
9597
Ide.Plugin.Brittany
9698

9799
if impl(ghc >= 8.6)
98-
build-depends: ormolu >= 0.0.3.1
100+
build-depends: ormolu ^>= 0.0.5
99101

100102
ghc-options:
101103
-Wall
@@ -151,7 +153,7 @@ executable haskell-language-server
151153
-- which works for now.
152154
, ghc
153155
--------------------------------------------------------------
154-
, ghc-check
156+
, ghc-check ^>= 0.1
155157
, ghc-paths
156158
, ghcide
157159
, gitrev

src/Ide/Plugin/Brittany.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ descriptor plId = PluginDescriptor
3636
-- If the provider fails an error is returned that can be displayed to the user.
3737
provider
3838
:: FormattingProvider IO
39-
provider _ideState typ contents fp opts = do
39+
provider _lf _ideState typ contents fp opts = do
4040
-- text uri formatType opts = pluginGetFile "brittanyCmd: " uri $ \fp -> do
4141
confFile <- liftIO $ getConfFile fp
4242
let (range, selectedContents) = case typ of

src/Ide/Plugin/Floskell.hs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
{-# LANGUAGE RecordWildCards #-}
2-
{-# LANGUAGE CPP #-}
32
{-# LANGUAGE OverloadedStrings #-}
43
{-# LANGUAGE ScopedTypeVariables #-}
54
{-# LANGUAGE TypeApplications #-}
@@ -45,7 +44,7 @@ descriptor plId = PluginDescriptor
4544
-- Formats the given source in either a given Range or the whole Document.
4645
-- If the provider fails an error is returned that can be displayed to the user.
4746
provider :: FormattingProvider IO
48-
provider _ideState typ contents fp _ = do
47+
provider _lf _ideState typ contents fp _ = do
4948
let file = fromNormalizedFilePath fp
5049
config <- findConfigOrDefault file
5150
let (range, selectedContents) = case typ of

src/Ide/Plugin/Formatter.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,15 +70,15 @@ doFormatting lf providers ideState ft uri params = do
7070
Just contents -> do
7171
logDebug (ideLogger ideState) $ T.pack $
7272
"Formatter.doFormatting: contents=" ++ show contents -- AZ
73-
provider ideState ft contents fp params
73+
provider lf ideState ft contents fp params
7474
Nothing -> return $ Left $ responseError $ T.pack $ "Formatter plugin: could not get file contents for " ++ show uri
7575
Nothing -> return $ Left $ responseError $ T.pack $ "Formatter plugin: uriToFilePath failed for: " ++ show uri
7676
Nothing -> return $ Left $ responseError $ T.pack $ "Formatter plugin: no formatter found for:[" ++ T.unpack mf ++ "]"
7777

7878
-- ---------------------------------------------------------------------
7979

8080
noneProvider :: FormattingProvider IO
81-
noneProvider _ _ _ _ _ = return $ Right (List [])
81+
noneProvider _ _ _ _ _ _ = return $ Right (List [])
8282

8383
-- ---------------------------------------------------------------------
8484

src/Ide/Plugin/Ormolu.hs

Lines changed: 18 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,6 @@ module Ide.Plugin.Ormolu
1313
where
1414

1515
import Control.Exception
16-
import Control.Monad
17-
import Data.Char
18-
import Data.List
19-
import Data.Maybe
2016
import qualified Data.Text as T
2117
import Development.IDE.Core.Rules
2218
import Development.IDE.Types.Diagnostics as D
@@ -25,7 +21,7 @@ import qualified DynFlags as D
2521
import qualified EnumSet as S
2622
import GHC
2723
import Ide.Types
28-
import qualified HIE.Bios as BIOS
24+
import Ide.PluginUtils
2925
import Ide.Plugin.Formatter
3026
import Language.Haskell.LSP.Types
3127
import Ormolu
@@ -51,18 +47,7 @@ descriptor plId = PluginDescriptor
5147

5248
provider :: FormattingProvider IO
5349
#if __GLASGOW_HASKELL__ >= 806
54-
provider ideState typ contents fp _ = do
55-
let
56-
exop s =
57-
"-X" `isPrefixOf` s || "-fplugin=" `isPrefixOf` s || "-pgmF=" `isPrefixOf` s
58-
opts <- lookupBiosComponentOptions fp
59-
let cradleOpts =
60-
map DynOption
61-
$ filter exop
62-
$ join
63-
$ maybeToList
64-
$ BIOS.componentOptions
65-
<$> opts
50+
provider _lf ideState typ contents fp _ = do
6651
let
6752
fromDyn :: ParsedModule -> IO [DynOption]
6853
fromDyn pmod =
@@ -82,56 +67,31 @@ provider ideState typ contents fp _ = do
8267
Just pm -> fromDyn pm
8368

8469
let
85-
conf o = Config o False False True False
86-
fmt :: T.Text -> [DynOption] -> IO (Either OrmoluException T.Text)
87-
fmt cont o =
88-
try @OrmoluException (ormolu (conf o) (fromNormalizedFilePath fp) $ T.unpack cont)
70+
fullRegion = RegionIndices Nothing Nothing
71+
rangeRegion s e = RegionIndices (Just s) (Just e)
72+
mkConf o region = defaultConfig { cfgDynOptions = o, cfgRegion = region }
73+
fmt :: T.Text -> Config RegionIndices -> IO (Either OrmoluException T.Text)
74+
fmt cont conf =
75+
try @OrmoluException (ormolu conf (fromNormalizedFilePath fp) $ T.unpack cont)
8976

9077
case typ of
91-
FormatText -> ret (fullRange contents) <$> fmt contents cradleOpts
78+
FormatText -> ret <$> fmt contents (mkConf fileOpts fullRegion)
9279
FormatRange r ->
9380
let
94-
txt = T.lines $ extractRange r contents
95-
lineRange (Range (Position sl _) (Position el _)) =
96-
Range (Position sl 0) $ Position el $ T.length $ last txt
97-
hIsSpace (h : _) = T.all isSpace h
98-
hIsSpace _ = True
99-
fixS t = if hIsSpace txt && (not $ hIsSpace t) then "" : t else t
100-
fixE t = if T.all isSpace $ last txt then t else T.init t
101-
unStrip :: T.Text -> T.Text -> T.Text
102-
unStrip ws new =
103-
fixE $ T.unlines $ map (ws `T.append`) $ fixS $ T.lines new
104-
mStrip :: Maybe (T.Text, T.Text)
105-
mStrip = case txt of
106-
(l : _) ->
107-
let ws = fst $ T.span isSpace l
108-
in (,) ws . T.unlines <$> traverse (T.stripPrefix ws) txt
109-
_ -> Nothing
110-
err :: IO (Either ResponseError (List TextEdit))
111-
err = return $ Left $ responseError
112-
$ T.pack "You must format a whole block of code. Ormolu does not support arbitrary ranges."
113-
fmt' :: (T.Text, T.Text) -> IO (Either ResponseError (List TextEdit))
114-
fmt' (ws, striped) =
115-
ret (lineRange r) <$> (fmap (unStrip ws) <$> fmt striped fileOpts)
81+
Range (Position sl _) (Position el _) = normalize r
11682
in
117-
maybe err fmt' mStrip
83+
ret <$> fmt contents (mkConf fileOpts (rangeRegion sl el))
11884
where
119-
ret :: Range -> Either OrmoluException T.Text -> Either ResponseError (List TextEdit)
120-
ret _ (Left err) = Left
85+
ret :: Either OrmoluException T.Text -> Either ResponseError (List TextEdit)
86+
ret (Left err) = Left
12187
(responseError (T.pack $ "ormoluCmd: " ++ show err) )
122-
ret r (Right new) = Right (List [TextEdit r new])
88+
ret (Right new) = Right (makeDiffTextEdit contents new)
12389

12490
#else
12591
provider _ _ _ _ = return $ Right [] -- NOP formatter
12692
#endif
12793

128-
-- ---------------------------------------------------------------------
129-
130-
-- | Find the cradle wide 'ComponentOptions' that apply to a 'FilePath'
131-
lookupBiosComponentOptions :: (Monad m) => NormalizedFilePath -> m (Maybe BIOS.ComponentOptions)
132-
lookupBiosComponentOptions _fp = do
133-
-- gmc <- getModuleCache
134-
-- return $ lookupInCache fp gmc (const Just) (Just . compOpts) Nothing
135-
return Nothing
136-
137-
-- ---------------------------------------------------------------------
94+
-- | Extend to the line below and above to replace newline character.
95+
normalize :: Range -> Range
96+
normalize (Range (Position sl _) (Position el _)) =
97+
Range (Position sl 0) (Position (el + 1) 0)

src/Ide/PluginUtils.hs

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
{-# LANGUAGE OverloadedStrings #-}
2+
module Ide.PluginUtils where
3+
4+
import qualified Data.Text as T
5+
import Data.Maybe
6+
import Data.Algorithm.DiffOutput
7+
import Data.Algorithm.Diff
8+
import qualified Data.HashMap.Strict as H
9+
import Language.Haskell.LSP.Types.Capabilities
10+
import qualified Language.Haskell.LSP.Types as J
11+
import Language.Haskell.LSP.Types
12+
13+
data WithDeletions = IncludeDeletions | SkipDeletions
14+
deriving Eq
15+
16+
-- | Generate a 'WorkspaceEdit' value from a pair of source Text
17+
diffText :: ClientCapabilities -> (Uri,T.Text) -> T.Text -> WithDeletions -> WorkspaceEdit
18+
diffText clientCaps old new withDeletions =
19+
let
20+
supports = clientSupportsDocumentChanges clientCaps
21+
in diffText' supports old new withDeletions
22+
23+
makeDiffTextEdit :: T.Text -> T.Text -> List TextEdit
24+
makeDiffTextEdit f1 f2 = diffTextEdit f1 f2 IncludeDeletions
25+
26+
makeDiffTextEditAdditive :: T.Text -> T.Text -> List TextEdit
27+
makeDiffTextEditAdditive f1 f2 = diffTextEdit f1 f2 SkipDeletions
28+
29+
diffTextEdit :: T.Text -> T.Text -> WithDeletions -> List TextEdit
30+
diffTextEdit fText f2Text withDeletions = J.List r
31+
where
32+
r = map diffOperationToTextEdit diffOps
33+
d = getGroupedDiff (lines $ T.unpack fText) (lines $ T.unpack f2Text)
34+
35+
diffOps = filter (\x -> (withDeletions == IncludeDeletions) || not (isDeletion x))
36+
(diffToLineRanges d)
37+
38+
isDeletion (Deletion _ _) = True
39+
isDeletion _ = False
40+
41+
42+
diffOperationToTextEdit :: DiffOperation LineRange -> J.TextEdit
43+
diffOperationToTextEdit (Change fm to) = J.TextEdit range nt
44+
where
45+
range = calcRange fm
46+
nt = T.pack $ init $ unlines $ lrContents to
47+
48+
{-
49+
In order to replace everything including newline characters,
50+
the end range should extend below the last line. From the specification:
51+
"If you want to specify a range that contains a line including
52+
the line ending character(s) then use an end position denoting
53+
the start of the next line"
54+
-}
55+
diffOperationToTextEdit (Deletion (LineRange (sl, el) _) _) = J.TextEdit range ""
56+
where
57+
range = J.Range (J.Position (sl - 1) 0)
58+
(J.Position el 0)
59+
60+
diffOperationToTextEdit (Addition fm l) = J.TextEdit range nt
61+
-- fm has a range wrt to the changed file, which starts in the current file at l
62+
-- So the range has to be shifted to start at l
63+
where
64+
range = J.Range (J.Position (l' - 1) 0)
65+
(J.Position (l' - 1) 0)
66+
l' = max l sl -- Needed to add at the end of the file
67+
sl = fst $ lrNumbers fm
68+
nt = T.pack $ unlines $ lrContents fm
69+
70+
71+
calcRange fm = J.Range s e
72+
where
73+
sl = fst $ lrNumbers fm
74+
sc = 0
75+
s = J.Position (sl - 1) sc -- Note: zero-based lines
76+
el = snd $ lrNumbers fm
77+
ec = length $ last $ lrContents fm
78+
e = J.Position (el - 1) ec -- Note: zero-based lines
79+
80+
81+
-- | A pure version of 'diffText' for testing
82+
diffText' :: Bool -> (Uri,T.Text) -> T.Text -> WithDeletions -> WorkspaceEdit
83+
diffText' supports (f,fText) f2Text withDeletions =
84+
if supports
85+
then WorkspaceEdit Nothing (Just docChanges)
86+
else WorkspaceEdit (Just h) Nothing
87+
where
88+
diff = diffTextEdit fText f2Text withDeletions
89+
h = H.singleton f diff
90+
docChanges = J.List [docEdit]
91+
docEdit = J.TextDocumentEdit (J.VersionedTextDocumentIdentifier f (Just 0)) diff
92+
93+
-- ---------------------------------------------------------------------
94+
95+
clientSupportsDocumentChanges :: ClientCapabilities -> Bool
96+
clientSupportsDocumentChanges caps =
97+
let ClientCapabilities mwCaps _ _ _ = caps
98+
supports = do
99+
wCaps <- mwCaps
100+
WorkspaceEditClientCapabilities mDc <- _workspaceEdit wCaps
101+
mDc
102+
in
103+
fromMaybe False supports

src/Ide/Types.hs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,8 @@ data FormattingType = FormatText
169169
-- It is required to pass in the whole Document Text for that to happen, an empty text
170170
-- and file uri, does not suffice.
171171
type FormattingProvider m
172-
= IdeState
172+
= LSP.LspFuncs Config
173+
-> IdeState
173174
-> FormattingType -- ^ How much to format
174175
-> T.Text -- ^ Text to format
175176
-> NormalizedFilePath -- ^ location of the file being formatted

stack-8.6.4.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ extra-deps:
3636
- monad-dijkstra-0.1.1.2
3737
- monad-memo-0.4.1
3838
- multistate-0.8.0.1
39-
- ormolu-0.0.3.1
39+
- ormolu-0.0.5.0
4040
- parser-combinators-1.2.1
4141
- regex-base-0.94.0.0
4242
- regex-tdfa-1.3.1.0

stack-8.6.5.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ extra-deps:
2828
- monad-dijkstra-0.1.1.2
2929
- optics-core-0.2
3030
- optparse-applicative-0.15.1.0
31-
- ormolu-0.0.3.1
31+
- ormolu-0.0.5.0
3232
- parser-combinators-1.2.1
3333
- regex-base-0.94.0.0
3434
- regex-pcre-builtin-0.95.1.1.8.43

stack-8.8.2.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ extra-deps:
2929
- ilist-0.3.1.0
3030
- lsp-test-0.10.2.0
3131
- monad-dijkstra-0.1.1.2
32+
- ormolu-0.0.5.0
3233
- semigroups-0.18.5
3334
- temporary-1.2.1.1
3435

stack-8.8.3.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ extra-deps:
2929
- ilist-0.3.1.0
3030
- lsp-test-0.10.2.0
3131
- monad-dijkstra-0.1.1.2
32+
- ormolu-0.0.5.0
3233
- semigroups-0.18.5
3334
- temporary-1.2.1.1
3435

stack.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ extra-deps:
2828
- monad-dijkstra-0.1.1.2
2929
- optics-core-0.2
3030
- optparse-applicative-0.15.1.0
31-
- ormolu-0.0.3.1
31+
- ormolu-0.0.5.0
3232
- parser-combinators-1.2.1
3333
- regex-base-0.94.0.0
3434
- regex-pcre-builtin-0.95.1.1.8.43

0 commit comments

Comments
 (0)