Skip to content

Commit 9fc84c1

Browse files
committed
Add cabal-gild as a cabal file formatter plugin
1 parent 41de40e commit 9fc84c1

16 files changed

+385
-42
lines changed

.github/workflows/test.yml

+42-37
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ jobs:
7474
- ubuntu-latest
7575
- macOS-latest
7676
- windows-latest
77-
test:
77+
test:
7878
- true
7979
- false
8080
exclude:
@@ -112,139 +112,144 @@ jobs:
112112
113113
- if: matrix.test
114114
name: Test hls-graph
115-
run: cabal test hls-graph
115+
run: cabal test hls-graph
116116

117117
- if: needs.pre_job.outputs.should_skip_ghcide != 'true' && matrix.test
118118
name: Test ghcide
119119
# run the tests without parallelism to avoid running out of memory
120-
run: cabal test ghcide || cabal test ghcide
120+
run: cabal test ghcide || cabal test ghcide
121121

122122
- if: matrix.test
123123
name: Test hls-plugin-api
124-
run: cabal test hls-plugin-api || cabal test hls-plugin-api
124+
run: cabal test hls-plugin-api || cabal test hls-plugin-api
125125

126126
- if: matrix.test
127127
name: Test func-test suite
128128
env:
129129
HLS_TEST_EXE: hls
130130
HLS_WRAPPER_TEST_EXE: hls-wrapper
131-
run: cabal test func-test || cabal test func-test
131+
run: cabal test func-test || cabal test func-test
132132

133133
- if: matrix.test
134134
name: Test wrapper-test suite
135135
env:
136136
HLS_TEST_EXE: hls
137137
HLS_WRAPPER_TEST_EXE: hls-wrapper
138-
run: cabal test wrapper-test
138+
run: cabal test wrapper-test
139139

140140
- if: matrix.test
141141
name: Test hls-refactor-plugin
142-
run: cabal test hls-refactor-plugin-tests || cabal test hls-refactor-plugin-tests
142+
run: cabal test hls-refactor-plugin-tests || cabal test hls-refactor-plugin-tests
143143

144-
- if: matrix.test
144+
- if: matrix.test
145145
name: Test hls-floskell-plugin
146-
run: cabal test hls-floskell-plugin-tests || cabal test hls-floskell-plugin-tests
146+
run: cabal test hls-floskell-plugin-tests || cabal test hls-floskell-plugin-tests
147147

148148
- if: matrix.test
149149
name: Test hls-class-plugin
150-
run: cabal test hls-class-plugin-tests || cabal test hls-class-plugin-tests
150+
run: cabal test hls-class-plugin-tests || cabal test hls-class-plugin-tests
151151

152152
- if: matrix.test
153153
name: Test hls-pragmas-plugin
154-
run: cabal test hls-pragmas-plugin-tests || cabal test hls-pragmas-plugin-tests
154+
run: cabal test hls-pragmas-plugin-tests || cabal test hls-pragmas-plugin-tests
155155

156156
- if: matrix.test
157157
name: Test hls-eval-plugin
158-
run: cabal test hls-eval-plugin-tests || cabal test hls-eval-plugin-tests
158+
run: cabal test hls-eval-plugin-tests || cabal test hls-eval-plugin-tests
159159

160160
- if: matrix.test
161161
name: Test hls-splice-plugin
162-
run: cabal test hls-splice-plugin-tests || cabal test hls-splice-plugin-tests
162+
run: cabal test hls-splice-plugin-tests || cabal test hls-splice-plugin-tests
163163

164164
- if: matrix.test && matrix.ghc != '9.2'
165165
name: Test hls-stan-plugin
166-
run: cabal test hls-stan-plugin-tests || cabal test hls-stan-plugin-tests
166+
run: cabal test hls-stan-plugin-tests || cabal test hls-stan-plugin-tests
167167

168168
- if: matrix.test
169169
name: Test hls-stylish-haskell-plugin
170-
run: cabal test hls-stylish-haskell-plugin-tests || cabal test hls-stylish-haskell-plugin-tests
170+
run: cabal test hls-stylish-haskell-plugin-tests || cabal test hls-stylish-haskell-plugin-tests
171171

172-
- if: matrix.test
172+
- if: matrix.test
173173
name: Test hls-ormolu-plugin
174-
run: cabal test hls-ormolu-plugin-tests || cabal test hls-ormolu-plugin-tests
174+
run: cabal test hls-ormolu-plugin-tests || cabal test hls-ormolu-plugin-tests
175175

176-
- if: matrix.test
176+
- if: matrix.test
177177
name: Test hls-fourmolu-plugin
178-
run: cabal test hls-fourmolu-plugin-tests || cabal test hls-fourmolu-plugin-tests
178+
run: cabal test hls-fourmolu-plugin-tests || cabal test hls-fourmolu-plugin-tests
179179

180180
- if: matrix.test
181181
name: Test hls-explicit-imports-plugin test suite
182-
run: cabal test hls-explicit-imports-plugin-tests || cabal test hls-explicit-imports-plugin-tests
182+
run: cabal test hls-explicit-imports-plugin-tests || cabal test hls-explicit-imports-plugin-tests
183183

184184
- if: matrix.test
185185
name: Test hls-call-hierarchy-plugin test suite
186-
run: cabal test hls-call-hierarchy-plugin-tests || cabal test hls-call-hierarchy-plugin-tests
186+
run: cabal test hls-call-hierarchy-plugin-tests || cabal test hls-call-hierarchy-plugin-tests
187187

188188
- if: matrix.test && matrix.os != 'windows-latest'
189189
name: Test hls-rename-plugin test suite
190-
run: cabal test hls-rename-plugin-tests || cabal test hls-rename-plugin-tests
190+
run: cabal test hls-rename-plugin-tests || cabal test hls-rename-plugin-tests
191191

192-
- if: matrix.test
192+
- if: matrix.test
193193
name: Test hls-hlint-plugin test suite
194-
run: cabal test hls-hlint-plugin-tests || cabal test hls-hlint-plugin-tests
194+
run: cabal test hls-hlint-plugin-tests || cabal test hls-hlint-plugin-tests
195195

196196
- if: matrix.test
197197
name: Test hls-module-name-plugin test suite
198-
run: cabal test hls-module-name-plugin-tests || cabal test hls-module-name-plugin-tests
198+
run: cabal test hls-module-name-plugin-tests || cabal test hls-module-name-plugin-tests
199199

200200
- if: matrix.test
201201
name: Test hls-alternate-number-format-plugin test suite
202-
run: cabal test hls-alternate-number-format-plugin-tests || cabal test hls-alternate-number-format-plugin-tests
202+
run: cabal test hls-alternate-number-format-plugin-tests || cabal test hls-alternate-number-format-plugin-tests
203203

204204
- if: matrix.test
205205
name: Test hls-qualify-imported-names-plugin test suite
206-
run: cabal test hls-qualify-imported-names-plugin-tests || cabal test hls-qualify-imported-names-plugin-tests
206+
run: cabal test hls-qualify-imported-names-plugin-tests || cabal test hls-qualify-imported-names-plugin-tests
207207

208208
- if: matrix.test
209209
name: Test hls-code-range-plugin test suite
210-
run: cabal test hls-code-range-plugin-tests || cabal test hls-code-range-plugin-tests
210+
run: cabal test hls-code-range-plugin-tests || cabal test hls-code-range-plugin-tests
211211

212212
- if: matrix.test
213213
name: Test hls-change-type-signature test suite
214-
run: cabal test hls-change-type-signature-plugin-tests || cabal test hls-change-type-signature-plugin-tests
214+
run: cabal test hls-change-type-signature-plugin-tests || cabal test hls-change-type-signature-plugin-tests
215215

216216
- if: matrix.test
217217
name: Test hls-gadt-plugin test suit
218-
run: cabal test hls-gadt-plugin-tests || cabal test hls-gadt-plugin-tests
218+
run: cabal test hls-gadt-plugin-tests || cabal test hls-gadt-plugin-tests
219219

220220
- if: matrix.test
221221
name: Test hls-explicit-fixity-plugin test suite
222-
run: cabal test hls-explicit-fixity-plugin-tests || cabal test hls-explicit-fixity-plugin-tests
222+
run: cabal test hls-explicit-fixity-plugin-tests || cabal test hls-explicit-fixity-plugin-tests
223223

224224
- if: matrix.test
225225
name: Test hls-explicit-record-fields-plugin test suite
226-
run: cabal test hls-explicit-record-fields-plugin-tests || cabal test hls-explicit-record-fields-plugin-tests
226+
run: cabal test hls-explicit-record-fields-plugin-tests || cabal test hls-explicit-record-fields-plugin-tests
227227

228228
## version needs to be limited since the tests depend on cabal-fmt which only builds using specific ghc versions
229229
- if: matrix.test && matrix.ghc == '9.2'
230230
name: Test hls-cabal-fmt-plugin test suite
231-
run: cabal test hls-cabal-fmt-plugin-tests --flag=isolateCabalfmtTests || cabal test hls-cabal-fmt-plugin-tests --flag=isolateCabalfmtTests
231+
run: cabal test hls-cabal-fmt-plugin-tests --flag=isolateCabalfmtTests || cabal test hls-cabal-fmt-plugin-tests --flag=isolateCabalfmtTests
232+
233+
## version needs to be limited since the tests depend on cabal-gild which only builds using specific ghc versions
234+
- if: matrix.test && matrix.ghc == '9.2'
235+
name: Test hls-cabal-gild-plugin test suite
236+
run: cabal test hls-cabal-gild-plugin-tests --flag=isolateCabalGildTests || cabal test hls-cabal-gild-plugin-tests --flag=isolateCabalGildTests
232237

233238
- if: matrix.test
234239
name: Test hls-cabal-plugin test suite
235-
run: cabal test hls-cabal-plugin-tests || cabal test hls-cabal-plugin-tests
240+
run: cabal test hls-cabal-plugin-tests || cabal test hls-cabal-plugin-tests
236241

237242
- if: matrix.test
238243
name: Test hls-retrie-plugin test suite
239-
run: cabal test hls-retrie-plugin-tests || cabal test hls-retrie-plugin-tests
244+
run: cabal test hls-retrie-plugin-tests || cabal test hls-retrie-plugin-tests
240245

241246
- if: matrix.test
242247
name: Test hls-overloaded-record-dot-plugin test suite
243-
run: cabal test hls-overloaded-record-dot-plugin-tests || cabal test hls-overloaded-record-dot-plugin-tests
248+
run: cabal test hls-overloaded-record-dot-plugin-tests || cabal test hls-overloaded-record-dot-plugin-tests
244249

245250
- if: matrix.test
246251
name: Test hls-semantic-tokens-plugin test suite
247-
run: cabal test hls-semantic-tokens-plugin-tests || cabal test hls-semantic-tokens-plugin-tests
252+
run: cabal test hls-semantic-tokens-plugin-tests || cabal test hls-semantic-tokens-plugin-tests
248253

249254

250255
test_post_job:

CODEOWNERS

+4-3
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@
1414
# Plugins
1515
/plugins/hls-alternate-number-format-plugin @drsooch
1616
/plugins/hls-cabal-fmt-plugin @VeryMilkyJoe @fendor
17+
/plugins/hls-cabal-gild-plugin @fendor
1718
/plugins/hls-cabal-plugin @fendor
1819
/plugins/hls-call-hierarchy-plugin @July541
1920
/plugins/hls-change-type-signature-plugin
20-
/plugins/hls-class-plugin
21+
/plugins/hls-class-plugin
2122
/plugins/hls-code-range-plugin @kokobd
2223
/plugins/hls-eval-plugin
2324
/plugins/hls-explicit-fixity-plugin
@@ -33,7 +34,7 @@
3334
/plugins/hls-pragmas-plugin @eddiemundo
3435
/plugins/hls-qualify-imported-names-plugin @eddiemundo
3536
/plugins/hls-refactor-plugin @santiweight
36-
/plugins/hls-rename-plugin
37+
/plugins/hls-rename-plugin
3738
/plugins/hls-retrie-plugin @pepeiborra
3839
/plugins/hls-semantic-tokens-plugin @soulomoon
3940
/plugins/hls-splice-plugin @konn
@@ -48,7 +49,7 @@
4849
/docs @michaelpj
4950

5051
# CI
51-
/.circleci
52+
/.circleci
5253
/.github @michaelpj @fendor
5354

5455
# Build

haskell-language-server.cabal

+51
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,56 @@ test-suite hls-cabal-fmt-plugin-tests
141141
if flag(isolateCabalfmtTests)
142142
build-tool-depends: cabal-fmt:cabal-fmt ^>=0.1.6
143143

144+
-----------------------------
145+
-- cabal-gild plugin
146+
-----------------------------
147+
148+
flag cabalgild
149+
description: Enable cabal-gild plugin
150+
default: True
151+
manual: True
152+
153+
common cabalgild
154+
if flag(cabalgild)
155+
build-depends: haskell-language-server:hls-cabal-gild-plugin
156+
cpp-options: -Dhls_cabalgild
157+
158+
flag isolateCabalGildTests
159+
description: Should tests search for 'cabal-gild' on the $PATH or shall we install it via build-tool-depends?
160+
-- By default, search on the PATH
161+
default: False
162+
manual: True
163+
164+
library hls-cabal-gild-plugin
165+
import: defaults, pedantic, warnings
166+
exposed-modules: Ide.Plugin.CabalGild
167+
hs-source-dirs: plugins/hls-cabal-gild-plugin/src
168+
build-depends:
169+
, base >=4.12 && <5
170+
, directory
171+
, filepath
172+
, ghcide == 2.7.0.0
173+
, hls-plugin-api == 2.7.0.0
174+
, lsp-types
175+
, text
176+
, mtl
177+
, process-extras
178+
179+
test-suite hls-cabal-gild-plugin-tests
180+
import: defaults, pedantic, test-defaults, warnings
181+
type: exitcode-stdio-1.0
182+
hs-source-dirs: plugins/hls-cabal-gild-plugin/test
183+
main-is: Main.hs
184+
build-depends:
185+
, base
186+
, directory
187+
, filepath
188+
, haskell-language-server:hls-cabal-gild-plugin
189+
, hls-test-utils == 2.7.0.0
190+
191+
if flag(isolateCabalGildTests)
192+
build-tool-depends: cabal-gild:cabal-gild ^>=1.1
193+
144194
-----------------------------
145195
-- cabal plugin
146196
-----------------------------
@@ -1621,6 +1671,7 @@ library
16211671
, cabal
16221672
, callHierarchy
16231673
, cabalfmt
1674+
, cabalgild
16241675
, changeTypeSignature
16251676
, class
16261677
, eval

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,8 @@ instance Default Config where
189189
, formattingProvider = "ormolu"
190190
-- , formattingProvider = "floskell"
191191
-- , formattingProvider = "stylish-haskell"
192-
, cabalFormattingProvider = "cabal-fmt"
192+
, cabalFormattingProvider = "gild"
193+
-- , cabalFormattingProvider = "cabal-fmt"
193194
-- this string value needs to kept in sync with the value provided in HlsPlugins
194195
, maxCompletions = 40
195196
, plugins = mempty
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
{-# LANGUAGE LambdaCase #-}
2+
{-# LANGUAGE OverloadedStrings #-}
3+
4+
module Ide.Plugin.CabalGild where
5+
6+
import Control.Monad.Except (throwError)
7+
import Control.Monad.IO.Class
8+
import qualified Data.Text as T
9+
import Development.IDE hiding (pluginHandlers)
10+
import Ide.Plugin.Error (PluginError (PluginInternalError, PluginInvalidParams))
11+
import Ide.PluginUtils
12+
import Ide.Types
13+
import Language.LSP.Protocol.Types
14+
import Prelude hiding (log)
15+
import System.Directory
16+
import System.Exit
17+
import System.FilePath
18+
import System.Process.ListLike
19+
import qualified System.Process.Text as Process
20+
21+
data Log
22+
= LogProcessInvocationFailure Int T.Text
23+
| LogReadCreateProcessInfo [String]
24+
| LogInvalidInvocationInfo
25+
| LogFormatterBinNotFound
26+
deriving (Show)
27+
28+
instance Pretty Log where
29+
pretty = \case
30+
LogProcessInvocationFailure exitCode err ->
31+
vcat
32+
[ "Invocation of cabal-gild failed with code" <+> pretty exitCode
33+
, "Stderr:" <+> pretty err
34+
]
35+
LogReadCreateProcessInfo args ->
36+
"Formatter invocation: cabal-gild " <+> pretty args
37+
LogInvalidInvocationInfo -> "Invocation of cabal-gild with range was called but is not supported."
38+
LogFormatterBinNotFound -> "Couldn't find executable 'cabal-gild'"
39+
40+
descriptor :: Recorder (WithPriority Log) -> PluginId -> PluginDescriptor IdeState
41+
descriptor recorder plId =
42+
(defaultCabalPluginDescriptor plId "Provides formatting of cabal files with cabal-gild")
43+
{ pluginHandlers = mkFormattingHandlers (provider recorder)
44+
}
45+
46+
-- | Formatter provider of cabal gild.
47+
-- Formats the given source in either a given Range or the whole Document.
48+
-- If the provider fails an error is returned that can be displayed to the user.
49+
provider :: Recorder (WithPriority Log) -> FormattingHandler IdeState
50+
provider recorder _ _ (FormatRange _) _ _ _ = do
51+
logWith recorder Info LogInvalidInvocationInfo
52+
throwError $ PluginInvalidParams "You cannot format a text-range using cabal-gild."
53+
provider recorder _ide _ FormatText contents nfp _ = do
54+
let cabalGildArgs = ["--stdin=" <> fp, "--input=-"] -- < Read from stdin
55+
x <- liftIO $ findExecutable "cabal-gild"
56+
case x of
57+
Just _ -> do
58+
log Debug $ LogReadCreateProcessInfo cabalGildArgs
59+
(exitCode, out, err) <-
60+
liftIO $ Process.readCreateProcessWithExitCode
61+
( proc "cabal-gild" cabalGildArgs
62+
)
63+
{ cwd = Just $ takeDirectory fp
64+
}
65+
contents
66+
case exitCode of
67+
ExitFailure code -> do
68+
log Error $ LogProcessInvocationFailure code err
69+
throwError (PluginInternalError "Failed to invoke cabal-gild")
70+
ExitSuccess -> do
71+
let fmtDiff = makeDiffTextEdit contents out
72+
pure $ InL fmtDiff
73+
Nothing -> do
74+
log Error LogFormatterBinNotFound
75+
throwError (PluginInternalError "No installation of cabal-gild could be found. Please install it into your global environment.")
76+
where
77+
fp = fromNormalizedFilePath nfp
78+
log = logWith recorder

0 commit comments

Comments
 (0)