Skip to content

Commit 1f24526

Browse files
Jana Chadtfendor
authored andcommitted
Add plugin for formatting cabal files using cabal-fmt
1 parent 12095b2 commit 1f24526

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
@@ -66,5 +67,8 @@ allow-newer:
6667
-- ghc-9.2
6768
----------
6869
hiedb:base,
70+
-- needed for tests of hls-cabal-fmt-plugin
71+
cabal-fmt:base,
72+
cabal-fmt:bytestring,
6973

7074
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
@@ -10,7 +10,7 @@ Last supporting HLS version:
1010
- specific version number: this GHC version is no longer one of the actively supported versions, and the last version of HLS which supports it is listed.
1111

1212
Support status (see the support policy below for more details):
13-
- "supported": this version of GHC is currently actively supported
13+
- "supported": this version of GHC is currently actively supported
1414
- "deprecated": this version of GHC was supported in the past, but is now deprecated
1515
- "will be deprecated ...": this version of GHC has special deprecation conditions that deviate from the support policy
1616
- "partial": not all features and plugins work, see the plugin support table and any linked issues for more details
@@ -50,6 +50,7 @@ Sometimes a plugin will be supported in the pre-built binaries but not in a HLS
5050
|-------------------------------------|--------------------------|
5151
| `hls-alternate-number-plugin` | |
5252
| `hls-brittany-plugin` | 9.2 |
53+
| `hls-cabal-fmt-plugin` | |
5354
| `hls-call-hierarchy-plugin` | |
5455
| `hls-class-plugin` | |
5556
| `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)