Skip to content

Commit 81a11e8

Browse files
Jana ChadtVeryMilkyJoe
authored andcommitted
Add plugin for formatting cabal files using cabal-fmt
1 parent cdc8f78 commit 81a11e8

26 files changed

+608
-17
lines changed

.github/workflows/test.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,9 +244,14 @@ jobs:
244244
run: cabal test hls-change-type-signature-plugin --test-options="$TEST_OPTS" || cabal test hls-change-type-signature-plugin --test-options="$TEST_OPTS" || LSP_TEST_LOG_COLOR=0 LSP_TEST_LOG_MESSAGES=true LSP_TEST_LOG_STDERR=true cabal test hls-change-type-signature-plugin --test-options="$TEST_OPTS"
245245

246246
- if: matrix.test
247-
name: Test hls-gadt-plugin test suit
247+
name: Test hls-gadt-plugin test suite
248248
run: cabal test hls-gadt-plugin --test-options="$TEST_OPTS" || cabal test hls-gadt-plugin --test-options="$TEST_OPTS" || LSP_TEST_LOG_COLOR=0 LSP_TEST_LOG_MESSAGES=true LSP_TEST_LOG_STDERR=true cabal test hls-gadt-plugin --test-options="$TEST_OPTS"
249249

250+
## version needs to be limited since the tests depend on cabal-fmt which only builds using specific ghc versions
251+
- if: matrix.test && matrix.ghc == '8.10.7'
252+
name: Test hls-cabal-fmt-plugin test suite
253+
run: cabal test hls-cabal-fmt-plugin --test-options="$TEST_OPTS" || cabal test hls-cabal-fmt-plugin --test-options="$TEST_OPTS" || LSP_TEST_LOG_COLOR=0 LSP_TEST_LOG_MESSAGES=true LSP_TEST_LOG_STDERR=true cabal test hls-cabal-fmt-plugin --test-options="$TEST_OPTS"
254+
250255
test_post_job:
251256
if: always()
252257
runs-on: ubuntu-latest

CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
# Plugins
1010
/plugins/hls-alternate-number-format-plugin @drsooch
1111
/plugins/hls-brittany-plugin @fendor
12+
/plugins/hls-cabal-fmt-plugin @VeryMilkyJoe @fendor
1213
/plugins/hls-call-hierarchy-plugin @July541
1314
/plugins/hls-class-plugin @Ailrun
1415
/plugins/hls-eval-plugin

cabal.project

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ packages:
66
./ghcide
77
./hls-plugin-api
88
./hls-test-utils
9+
./plugins/hls-cabal-fmt-plugin
910
./plugins/hls-tactics-plugin
1011
./plugins/hls-brittany-plugin
1112
./plugins/hls-stylish-haskell-plugin
@@ -67,5 +68,8 @@ allow-newer:
6768
-- ghc-9.2
6869
----------
6970
hiedb:base,
71+
-- needed for tests of hls-cabal-fmt-plugin
72+
cabal-fmt:base,
73+
cabal-fmt:bytestring,
7074

7175
ekg-wai:time

docs/features.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,13 @@ Format your code with various Haskell code formatters.
9595
| Ormolu | `hls-ormolu-plugin` |
9696
| Stylish Haskell | `hls-stylish-haskell-plugin` |
9797

98+
Format your cabal files with a cabal code formatter.
99+
100+
| Formatter | Provided by |
101+
|-----------------|------------------------------|
102+
| cabal-fmt | `hls-cabal-fmt-plugin` |
103+
104+
98105
## Document symbols
99106

100107
Provided by: `ghcide`

docs/supported-versions.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ Sometimes a plugin will be supported in the prebuilt binaries but not in a HLS b
3737
| Plugin | Unsupported GHC versions |
3838
|-------------------------------------|--------------------------|
3939
| `hls-alternate-number-plugin` | |
40-
| `hls-brittany-plugin` | 9.2 |
40+
| `hls-brittany-plugin` | 9.2 |
41+
| `hls-cabal-fmt-plugin` | |
4142
| `hls-call-hierarchy-plugin` | |
4243
| `hls-class-plugin` | |
4344
| `hls-eval-plugin` | |

exe/Plugins.hs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ import qualified Ide.Plugin.StylishHaskell as StylishHaskell
109109
import qualified Ide.Plugin.Brittany as Brittany
110110
#endif
111111

112+
#if cabalfmt
113+
import qualified Ide.Plugin.CabalFmt as CabalFmt
114+
#endif
115+
112116
data Log = forall a. (Pretty a) => Log a
113117

114118
instance Pretty Log where
@@ -157,6 +161,9 @@ idePlugins recorder includeExamples = pluginDescToIdePlugins allPlugins
157161
#if brittany
158162
Brittany.descriptor "brittany" :
159163
#endif
164+
#if cabalfmt
165+
CabalFmt.descriptor pluginRecorder "cabal-fmt" :
166+
#endif
160167
#if callHierarchy
161168
CallHierarchy.descriptor :
162169
#endif

haskell-language-server.cabal

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,11 @@ common example-plugins
229229
Ide.Plugin.Example2,
230230
Ide.Plugin.ExampleCabal
231231

232+
flag cabalfmt
233+
description: Enable cabal-fmt plugin
234+
default: True
235+
manual: True
236+
232237
common class
233238
if flag(class)
234239
build-depends: hls-class-plugin ^>= 1.0
@@ -346,6 +351,11 @@ common brittany
346351
build-depends: hls-brittany-plugin ^>= 1.0
347352
cpp-options: -Dbrittany
348353

354+
common cabalfmt
355+
if flag(cabalfmt)
356+
build-depends: hls-cabal-fmt-plugin ^>= 0.1.0.0
357+
cpp-options: -Dcabalfmt
358+
349359
executable haskell-language-server
350360
import: common-deps
351361
-- configuration
@@ -376,6 +386,7 @@ executable haskell-language-server
376386
, ormolu
377387
, stylishHaskell
378388
, brittany
389+
, cabalfmt
379390

380391
main-is: Main.hs
381392
hs-source-dirs: exe

hls-plugin-api/src/Ide/Plugin/Config.hs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ data Config =
5050
{ checkParents :: CheckParents
5151
, checkProject :: !Bool
5252
, formattingProvider :: !T.Text
53+
, cabalFormattingProvider :: !T.Text
5354
, maxCompletions :: !Int
5455
, plugins :: !(Map.Map T.Text PluginConfig)
5556
} deriving (Show,Eq)
@@ -62,6 +63,7 @@ instance Default Config where
6263
, formattingProvider = "ormolu"
6364
-- , formattingProvider = "floskell"
6465
-- , formattingProvider = "stylish-haskell"
66+
, cabalFormattingProvider = "cabal-fmt"
6567
, maxCompletions = 40
6668
, plugins = Map.empty
6769
}
@@ -78,6 +80,7 @@ parseConfig defValue = A.withObject "Config" $ \v -> do
7880
<$> (o .:? "checkParents" <|> v .:? "checkParents") .!= checkParents defValue
7981
<*> (o .:? "checkProject" <|> v .:? "checkProject") .!= checkProject defValue
8082
<*> o .:? "formattingProvider" .!= formattingProvider defValue
83+
<*> o .:? "cabalFormattingProvider" .!= cabalFormattingProvider defValue
8184
<*> o .:? "maxCompletions" .!= maxCompletions defValue
8285
<*> o .:? "plugin" .!= plugins defValue
8386

hls-plugin-api/src/Ide/Types.hs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -344,14 +344,15 @@ instance PluginMethod Request TextDocumentCompletion where
344344

345345
instance PluginMethod Request TextDocumentFormatting where
346346
pluginEnabled STextDocumentFormatting msgParams pluginDesc conf =
347-
pluginResponsible uri pluginDesc && PluginId (formattingProvider conf) == pid
347+
pluginResponsible uri pluginDesc
348+
&& (PluginId (formattingProvider conf) == pid || PluginId (cabalFormattingProvider conf) == pid)
348349
where
349350
uri = msgParams ^. J.textDocument . J.uri
350351
pid = pluginId pluginDesc
351352

352353
instance PluginMethod Request TextDocumentRangeFormatting where
353354
pluginEnabled _ msgParams pluginDesc conf = pluginResponsible uri pluginDesc
354-
&& PluginId (formattingProvider conf) == pid
355+
&& (PluginId (formattingProvider conf) == pid || PluginId (cabalFormattingProvider conf) == pid)
355356
where
356357
uri = msgParams ^. J.textDocument . J.uri
357358
pid = pluginId pluginDesc

hls-test-utils/src/Test/Hls.hs

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@ module Test.Hls
1717
goldenGitDiff,
1818
goldenWithHaskellDoc,
1919
goldenWithHaskellDocFormatter,
20+
goldenWithCabalDocFormatter,
2021
def,
2122
runSessionWithServer,
2223
runSessionWithServerFormatter,
24+
runSessionWithCabalServerFormatter,
2325
runSessionWithServer',
2426
waitForProgressDone,
2527
waitForAllProgressDone,
@@ -70,7 +72,7 @@ import Development.IDE.Types.Options
7072
import GHC.IO.Handle
7173
import GHC.Stack (emptyCallStack)
7274
import Ide.Plugin.Config (Config, PluginConfig,
73-
formattingProvider, plugins)
75+
cabalFormattingProvider ,formattingProvider, plugins)
7476
import Ide.PluginUtils (idePluginsToPluginDesc,
7577
pluginDescToIdePlugins)
7678
import Ide.Types
@@ -130,15 +132,30 @@ goldenWithHaskellDoc plugin title testDataDir path desc ext act =
130132
act doc
131133
documentContents doc
132134

135+
136+
runSessionWithServer :: PluginDescriptor IdeState -> FilePath -> Session a -> IO a
137+
runSessionWithServer plugin = runSessionWithServer' [plugin] def def fullCaps
138+
139+
runSessionWithServerFormatter :: PluginDescriptor IdeState -> String -> PluginConfig -> FilePath -> Session a -> IO a
140+
runSessionWithServerFormatter plugin formatter conf =
141+
runSessionWithServer'
142+
[plugin]
143+
def
144+
{ formattingProvider = T.pack formatter
145+
, plugins = M.singleton (T.pack formatter) conf
146+
}
147+
def
148+
fullCaps
149+
133150
goldenWithHaskellDocFormatter
134-
:: PluginDescriptor IdeState
135-
-> String
151+
:: PluginDescriptor IdeState -- ^ Formatter plugin to be used
152+
-> String -- ^ Name of the formatter to be used
136153
-> PluginConfig
137-
-> TestName
138-
-> FilePath
139-
-> FilePath
140-
-> FilePath
141-
-> FilePath
154+
-> TestName -- ^ Title of the test
155+
-> FilePath -- ^ Directory of the test data to be used
156+
-> FilePath -- ^ Path to the testdata to be used within the directory
157+
-> FilePath -- ^ Additional suffix to be appended to the output file
158+
-> FilePath -- ^ Extension of the output file
142159
-> (TextDocumentIdentifier -> Session ())
143160
-> TestTree
144161
goldenWithHaskellDocFormatter plugin formatter conf title testDataDir path desc ext act =
@@ -151,15 +168,33 @@ goldenWithHaskellDocFormatter plugin formatter conf title testDataDir path desc
151168
act doc
152169
documentContents doc
153170

154-
runSessionWithServer :: PluginDescriptor IdeState -> FilePath -> Session a -> IO a
155-
runSessionWithServer plugin = runSessionWithServer' [plugin] def def fullCaps
171+
goldenWithCabalDocFormatter
172+
:: PluginDescriptor IdeState -- ^ Formatter plugin to be used
173+
-> String -- ^ Name of the formatter to be used
174+
-> PluginConfig
175+
-> TestName -- ^ Title of the test
176+
-> FilePath -- ^ Directory of the test data to be used
177+
-> FilePath -- ^ Path to the testdata to be used within the directory
178+
-> FilePath -- ^ Additional suffix to be appended to the output file
179+
-> FilePath -- ^ Extension of the output file
180+
-> (TextDocumentIdentifier -> Session ())
181+
-> TestTree
182+
goldenWithCabalDocFormatter plugin formatter conf title testDataDir path desc ext act =
183+
goldenGitDiff title (testDataDir </> path <.> desc <.> ext)
184+
$ runSessionWithCabalServerFormatter plugin formatter conf testDataDir
185+
$ TL.encodeUtf8 . TL.fromStrict
186+
<$> do
187+
doc <- openDoc (path <.> ext) "cabal"
188+
void waitForBuildQueue
189+
act doc
190+
documentContents doc
156191

157-
runSessionWithServerFormatter :: PluginDescriptor IdeState -> String -> PluginConfig -> FilePath -> Session a -> IO a
158-
runSessionWithServerFormatter plugin formatter conf =
192+
runSessionWithCabalServerFormatter :: PluginDescriptor IdeState -> String -> PluginConfig -> FilePath -> Session a -> IO a
193+
runSessionWithCabalServerFormatter plugin formatter conf =
159194
runSessionWithServer'
160195
[plugin]
161196
def
162-
{ formattingProvider = T.pack formatter
197+
{ cabalFormattingProvider = T.pack formatter
163198
, plugins = M.singleton (T.pack formatter) conf
164199
}
165200
def

0 commit comments

Comments
 (0)