Skip to content

Commit 84b0073

Browse files
authored
Merge pull request #146 from Ailrun/stylish-haskell-plugin
[Plugin] stylish-haskell formatter
2 parents 5896026 + c61f27a commit 84b0073

11 files changed

+118
-0
lines changed

Diff for: exe/Main.hs

+2
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ import Ide.Plugin.Example2 as Example2
9494
import Ide.Plugin.GhcIde as GhcIde
9595
import Ide.Plugin.Floskell as Floskell
9696
import Ide.Plugin.Ormolu as Ormolu
97+
import Ide.Plugin.StylishHaskell as StylishHaskell
9798
#if AGPL
9899
import Ide.Plugin.Brittany as Brittany
99100
#endif
@@ -129,6 +130,7 @@ idePlugins includeExamples = pluginDescToIdePlugins allPlugins
129130
-- , genericDescriptor "generic"
130131
-- , ghcmodDescriptor "ghcmod"
131132
, Ormolu.descriptor "ormolu"
133+
, StylishHaskell.descriptor "stylish-haskell"
132134
#if AGPL
133135
, Brittany.descriptor "brittany"
134136
#endif

Diff for: haskell-language-server.cabal

+2
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.Plugin.StylishHaskell
5253
Ide.PluginUtils
5354
Ide.Types
5455
Ide.Version
@@ -84,6 +85,7 @@ library
8485
, process
8586
, regex-tdfa >= 1.3.1.0
8687
, shake >= 0.17.5
88+
, stylish-haskell == 0.11.*
8789
, text
8890
, transformers
8991
, unordered-containers

Diff for: src/Ide/Plugin/Config.hs

+1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ instance Default Config where
6464
-- , formattingProvider = "brittany"
6565
, formattingProvider = "ormolu"
6666
-- , formattingProvider = "floskell"
67+
-- , formattingProvider = "stylish-haskell"
6768
}
6869

6970
-- TODO: Add API for plugins to expose their own LSP config options

Diff for: src/Ide/Plugin/StylishHaskell.hs

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
module Ide.Plugin.StylishHaskell
2+
(
3+
descriptor
4+
, provider
5+
)
6+
where
7+
8+
import Control.Monad.IO.Class
9+
import Data.Text (Text)
10+
import qualified Data.Text as T
11+
import Ide.Plugin.Formatter
12+
import Ide.PluginUtils
13+
import Ide.Types
14+
import Language.Haskell.Stylish
15+
import Language.Haskell.LSP.Types as J
16+
17+
import System.Directory
18+
import System.FilePath
19+
20+
descriptor :: PluginId -> PluginDescriptor
21+
descriptor plId = (defaultPluginDescriptor plId)
22+
{ pluginFormattingProvider = Just provider
23+
}
24+
25+
-- | Formatter provider of stylish-haskell.
26+
-- Formats the given source in either a given Range or the whole Document.
27+
-- If the provider fails an error is returned that can be displayed to the user.
28+
provider :: FormattingProvider IO
29+
provider _lf _ideState typ contents fp _opts = do
30+
let file = fromNormalizedFilePath fp
31+
config <- liftIO $ loadConfigFrom file
32+
let (range, selectedContents) = case typ of
33+
FormatText -> (fullRange contents, contents)
34+
FormatRange r -> (normalize r, extractRange r contents)
35+
result = runStylishHaskell file config selectedContents
36+
case result of
37+
Left err -> return $ Left $ responseError $ T.pack $ "stylishHaskellCmd: " ++ err
38+
Right new -> return $ Right $ J.List [TextEdit range new]
39+
40+
-- | Recursively search in every directory of the given filepath for .stylish-haskell.yaml.
41+
-- If no such file has been found, return default config.
42+
loadConfigFrom :: FilePath -> IO Config
43+
loadConfigFrom file = do
44+
currDir <- getCurrentDirectory
45+
setCurrentDirectory (takeDirectory file)
46+
config <- loadConfig (makeVerbose False) Nothing
47+
setCurrentDirectory currDir
48+
return config
49+
50+
-- | Run stylish-haskell on the given text with the given configuration.
51+
runStylishHaskell :: FilePath -- ^ Location of the file being formatted. Used for error message
52+
-> Config -- ^ Configuration for stylish-haskell
53+
-> Text -- ^ Text to format
54+
-> Either String Text -- ^ Either formatted Text or an error message
55+
runStylishHaskell file config = fmap fromLines . fmt . toLines
56+
where
57+
fromLines = T.pack . unlines
58+
fmt = runSteps (configLanguageExtensions config) (Just file) (configSteps config)
59+
toLines = lines . T.unpack

Diff for: stack-8.6.4.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ extra-deps:
3333
- hlint-2.2.8
3434
- hoogle-5.0.17.11
3535
- hsimport-0.11.0@rev:2
36+
- HsYAML-0.2.1.0@rev:1
37+
- HsYAML-aeson-0.2.0.0@rev:1
3638
- lens-4.18
3739
- lsp-test-0.10.3.0
3840
- microlens-th-0.4.2.3@rev:1
@@ -48,6 +50,7 @@ extra-deps:
4850
# - shake-0.18.5
4951
- github: wz1000/shake
5052
commit: fb3859dca2e54d1bbb2c873e68ed225fa179fbef
53+
- stylish-haskell-0.11.0.0
5154
- syz-0.2.0.0
5255
- tasty-rerun-1.1.17
5356
- temporary-1.2.1.1

Diff for: stack-8.6.5.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ extra-deps:
2525
- haskell-lsp-0.22.0.0
2626
- haskell-lsp-types-0.22.0.0
2727
- hie-bios-0.5.0
28+
- HsYAML-0.2.1.0@rev:1
29+
- HsYAML-aeson-0.2.0.0@rev:1
2830
- indexed-profunctors-0.1
2931
- lens-4.18
3032
- lsp-test-0.10.3.0
@@ -40,6 +42,7 @@ extra-deps:
4042
- semialign-1.1
4143
- github: wz1000/shake
4244
commit: fb3859dca2e54d1bbb2c873e68ed225fa179fbef
45+
- stylish-haskell-0.11.0.0
4346
- tasty-rerun-1.1.17
4447
- temporary-1.2.1.1
4548
- type-equality-1

Diff for: stack-8.8.2.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ extra-deps:
2323
- hlint-2.2.8
2424
- hoogle-5.0.17.11
2525
- hsimport-0.11.0
26+
- HsYAML-0.2.1.0@rev:1
27+
- HsYAML-aeson-0.2.0.0@rev:1
2628
- ilist-0.3.1.0
2729
- lsp-test-0.10.3.0
2830
- monad-dijkstra-0.1.1.2
@@ -31,6 +33,7 @@ extra-deps:
3133
- semigroups-0.18.5
3234
- github: wz1000/shake
3335
commit: fb3859dca2e54d1bbb2c873e68ed225fa179fbef
36+
- stylish-haskell-0.11.0.0
3437
- temporary-1.2.1.1
3538

3639
flags:

Diff for: stack-8.8.3.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ extra-deps:
3030
- semigroups-0.18.5
3131
- github: wz1000/shake
3232
commit: fb3859dca2e54d1bbb2c873e68ed225fa179fbef
33+
- stylish-haskell-0.11.0.0
3334
- temporary-1.2.1.1
3435

3536
flags:

Diff for: stack.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ extra-deps:
2525
- haskell-lsp-0.22.0.0
2626
- haskell-lsp-types-0.22.0.0
2727
- hie-bios-0.5.0
28+
- HsYAML-0.2.1.0@rev:1
29+
- HsYAML-aeson-0.2.0.0@rev:1
2830
- indexed-profunctors-0.1
2931
- lens-4.18
3032
- lsp-test-0.10.3.0
@@ -40,6 +42,7 @@ extra-deps:
4042
- semialign-1.1
4143
- github: wz1000/shake
4244
commit: fb3859dca2e54d1bbb2c873e68ed225fa179fbef
45+
- stylish-haskell-0.11.0.0
4346
- tasty-rerun-1.1.17
4447
- temporary-1.2.1.1
4548
- type-equality-1

Diff for: test/functional/Format.hs

+33
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ tests = testGroup "format document" [
2424
documentContents doc >>= liftIO . (`shouldBe` formattedDocTabSize5)
2525
, rangeTests
2626
, providerTests
27+
, stylishHaskellTests
2728
, brittanyTests
2829
, ormoluTests
2930
]
@@ -68,6 +69,38 @@ providerTests = testGroup "formatting provider" [
6869
documentContents doc >>= liftIO . (`shouldBe` formattedBrittanyPostFloskell)
6970
]
7071

72+
stylishHaskellTests :: TestTree
73+
stylishHaskellTests = testGroup "stylish-haskell" [
74+
testCase "formats a file" $ runSession hieCommand fullCaps "test/testdata" $ do
75+
sendNotification WorkspaceDidChangeConfiguration (DidChangeConfigurationParams (formatLspConfig "stylish-haskell"))
76+
doc <- openDoc "StylishHaskell.hs" "haskell"
77+
formatDoc doc (FormattingOptions 2 True)
78+
contents <- documentContents doc
79+
liftIO $ contents `shouldBe`
80+
"import Data.Char\n\
81+
\import qualified Data.List\n\
82+
\import Data.String\n\
83+
\\n\
84+
\bar :: Maybe (Either String Integer) -> Integer\n\
85+
\bar Nothing = 0\n\
86+
\bar (Just (Left _)) = 0\n\
87+
\bar (Just (Right x)) = x\n"
88+
, testCase "formats a range" $ runSession hieCommand fullCaps "test/testdata" $ do
89+
sendNotification WorkspaceDidChangeConfiguration (DidChangeConfigurationParams (formatLspConfig "stylish-haskell"))
90+
doc <- openDoc "StylishHaskell.hs" "haskell"
91+
formatRange doc (FormattingOptions 2 True) (Range (Position 0 0) (Position 2 21))
92+
contents <- documentContents doc
93+
liftIO $ contents `shouldBe`
94+
"import Data.Char\n\
95+
\import qualified Data.List\n\
96+
\import Data.String\n\
97+
\\n\
98+
\bar :: Maybe (Either String Integer) -> Integer\n\
99+
\bar Nothing = 0\n\
100+
\bar (Just (Left _)) = 0\n\
101+
\bar (Just (Right x)) = x\n"
102+
]
103+
71104
brittanyTests :: TestTree
72105
brittanyTests = testGroup "brittany" [
73106
ignoreTestBecause "Broken" $ testCase "formats a document with LF endings" $ runSession hieCommand fullCaps "test/testdata" $ do

Diff for: test/testdata/StylishHaskell.hs

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import Data.Char
2+
import qualified Data.List
3+
import Data.String
4+
5+
bar :: Maybe (Either String Integer) -> Integer
6+
bar Nothing = 0
7+
bar (Just (Left _)) = 0
8+
bar (Just (Right x)) = x

0 commit comments

Comments
 (0)