Skip to content

Commit 369fdfe

Browse files
rmehri01jneira
andauthored
HLint: Pass options through user config (#1724)
* Get flags for hlint through user config * Add test case for hlint flags * Add documentation for hlint configuration * Fix build after merging master * Remove unnecessary functions from hlint plugin * Add test case that adds hints based on flags * Fix build after merging master * Add configHasDiagnostics back in Co-authored-by: Javier Neira <atreyu.bbb@gmail.com>
1 parent aa9b3c6 commit 369fdfe

File tree

5 files changed

+87
-20
lines changed

5 files changed

+87
-20
lines changed

plugins/hls-hlint-plugin/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# HLint Plugin for the [Haskell Language Server](https://github.com/haskell/haskell-language-server#readme)
2+
3+
## Configuration
4+
5+
This is typically done through an [HLint configuration file](https://github.com/ndmitchell/hlint#customizing-the-hints).
6+
You can also change the behavior of HLint by adding a list of flags to `haskell.plugin.hlint.config.flags`
7+
if your configuration is in a non-standard location or you want to change settings globally.

plugins/hls-hlint-plugin/src/Ide/Plugin/Hlint.hs

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
{-# LANGUAGE DuplicateRecordFields #-}
55
{-# LANGUAGE FlexibleContexts #-}
66
{-# LANGUAGE FlexibleInstances #-}
7+
{-# LANGUAGE OverloadedLabels #-}
78
{-# LANGUAGE OverloadedStrings #-}
89
{-# LANGUAGE PackageImports #-}
910
{-# LANGUAGE ScopedTypeVariables #-}
@@ -33,9 +34,11 @@ import Data.Maybe
3334
import qualified Data.Text as T
3435
import qualified Data.Text.IO as T
3536
import Data.Typeable
36-
import Development.IDE
37+
import Development.IDE hiding
38+
(Error)
3739
import Development.IDE.Core.Rules (defineNoFile,
38-
getParsedModuleWithComments)
40+
getParsedModuleWithComments,
41+
usePropertyAction)
3942
import Development.IDE.Core.Shake (getDiagnostics)
4043
import Refact.Apply
4144

@@ -70,10 +73,13 @@ import Language.Haskell.GHC.ExactPrint.Types (Rigidity (.
7073
#endif
7174

7275
import Ide.Logger
73-
import Ide.Plugin.Config
76+
import Ide.Plugin.Config hiding
77+
(Config)
78+
import Ide.Plugin.Properties
7479
import Ide.PluginUtils
7580
import Ide.Types
76-
import Language.Haskell.HLint as Hlint
81+
import Language.Haskell.HLint as Hlint hiding
82+
(Error)
7783
import Language.LSP.Server (ProgressCancellable (Cancellable),
7884
sendRequest,
7985
withIndefiniteProgress)
@@ -95,8 +101,11 @@ descriptor plId = (defaultPluginDescriptor plId)
95101
[ PluginCommand "applyOne" "Apply a single hint" applyOneCmd
96102
, PluginCommand "applyAll" "Apply all hints to the file" applyAllCmd
97103
]
98-
, pluginHandlers = mkPluginHandler STextDocumentCodeAction codeActionProvider
99-
, pluginConfigDescriptor = defaultConfigDescriptor {configHasDiagnostics = True}
104+
, pluginHandlers = mkPluginHandler STextDocumentCodeAction codeActionProvider
105+
, pluginConfigDescriptor = defaultConfigDescriptor
106+
{ configHasDiagnostics = True
107+
, configCustomConfig = mkCustomConfig properties
108+
}
100109
}
101110

102111
-- This rule only exists for generating file diagnostics
@@ -126,7 +135,9 @@ rules plugin = do
126135
ideas <- if hlintOn' then getIdeas file else return (Right [])
127136
return (diagnostics file ideas, Just ())
128137

129-
getHlintSettingsRule (HlintEnabled [])
138+
defineNoFile $ \GetHlintSettings -> do
139+
(Config flags) <- getHlintConfig plugin
140+
liftIO $ argsSettings flags
130141

131142
action $ do
132143
files <- getFilesOfInterest
@@ -241,11 +252,6 @@ getExtensions pflags nfp = do
241252

242253
-- ---------------------------------------------------------------------
243254

244-
data HlintUsage
245-
= HlintEnabled { cmdArgs :: [String] }
246-
| HlintDisabled
247-
deriving Show
248-
249255
data GetHlintSettings = GetHlintSettings
250256
deriving (Eq, Show, Typeable, Generic)
251257
instance Hashable GetHlintSettings
@@ -259,15 +265,22 @@ instance Binary GetHlintSettings
259265

260266
type instance RuleResult GetHlintSettings = (ParseFlags, [Classify], Hint)
261267

262-
getHlintSettingsRule :: HlintUsage -> Rules ()
263-
getHlintSettingsRule usage =
264-
defineNoFile $ \GetHlintSettings ->
265-
liftIO $ case usage of
266-
HlintEnabled cmdArgs -> argsSettings cmdArgs
267-
HlintDisabled -> fail "hlint configuration unspecified"
268-
269268
-- ---------------------------------------------------------------------
270269

270+
newtype Config = Config [String]
271+
272+
properties :: Properties '[ 'PropertyKey "flags" ('TArray String)]
273+
properties = emptyProperties
274+
& defineArrayProperty #flags
275+
"Flags used by hlint" []
276+
277+
-- | Get the plugin config
278+
getHlintConfig :: PluginId -> Action Config
279+
getHlintConfig pId =
280+
Config
281+
<$> usePropertyAction #flags pId properties
282+
283+
-- ---------------------------------------------------------------------
271284
codeActionProvider :: PluginMethodHandler IdeState TextDocumentCodeAction
272285
codeActionProvider ideState plId (CodeActionParams _ _ docId _ context) = Right . LSP.List . map InR <$> liftIO getCodeActions
273286
where

test/functional/Config.hs

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22

33
module Config (tests) where
44

5-
import Control.Lens hiding (List)
5+
import Control.Lens hiding (List, (.=))
66
import Control.Monad
77
import Data.Aeson
88
import qualified Data.Map as Map
99
import qualified Data.Text as T
1010
import Ide.Plugin.Config
11+
import qualified Ide.Plugin.Config as Plugin
1112
import Language.LSP.Test as Test
1213
import qualified Language.LSP.Types.Lens as L
1314
import System.FilePath ((</>))
@@ -55,6 +56,38 @@ hlintTests = testGroup "hlint plugin enables" [
5556

5657
liftIO $ noHlintDiagnostics diags'
5758

59+
, testCase "adding hlint flags to plugin configuration removes hlint diagnostics" $ runHlintSession "" $ do
60+
let config = def { hlintOn = True }
61+
sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (toJSON config))
62+
63+
doc <- openDoc "ApplyRefact2.hs" "haskell"
64+
testHlintDiagnostics doc
65+
66+
let config' = hlintConfigWithFlags ["--ignore=Redundant id", "--hint=test-hlint-config.yaml"]
67+
sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (toJSON config'))
68+
69+
diags' <- waitForDiagnosticsFrom doc
70+
71+
liftIO $ noHlintDiagnostics diags'
72+
73+
, testCase "adding hlint flags to plugin configuration adds hlint diagnostics" $ runHlintSession "" $ do
74+
let config = def { hlintOn = True }
75+
sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (toJSON config))
76+
77+
doc <- openDoc "ApplyRefact7.hs" "haskell"
78+
79+
expectNoMoreDiagnostics 3 doc "hlint"
80+
81+
let config' = hlintConfigWithFlags ["--with-group=generalise"]
82+
sendNotification SWorkspaceDidChangeConfiguration (DidChangeConfigurationParams (toJSON config'))
83+
84+
diags' <- waitForDiagnosticsFromSource doc "hlint"
85+
d <- liftIO $ inspectDiagnostic diags' ["Use <>"]
86+
87+
liftIO $ do
88+
length diags' @?= 1
89+
d ^. L.range @?= Range (Position 1 10) (Position 1 21)
90+
d ^. L.severity @?= Just DsInfo
5891
]
5992
where
6093
runHlintSession :: FilePath -> Session a -> IO a
@@ -94,3 +127,14 @@ pluginGlobalOn config pid state = config'
94127
where
95128
pluginConfig = def { plcGlobalOn = state }
96129
config' = def { plugins = Map.insert pid pluginConfig (plugins config) }
130+
131+
hlintConfigWithFlags :: [T.Text] -> Config
132+
hlintConfigWithFlags flags =
133+
def
134+
{ hlintOn = True
135+
, Plugin.plugins = Map.fromList [("hlint",
136+
def { Plugin.plcConfig = unObject $ object ["flags" .= flags] }
137+
)] }
138+
where
139+
unObject (Object obj) = obj
140+
unObject _ = undefined

test/testdata/hlint/ApplyRefact7.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
main = undefined
2+
foo x y = [x, x] ++ y
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- ignore: { name: Eta reduce }

0 commit comments

Comments
 (0)