1
1
{-# LANGUAGE CPP #-}
2
+ {-# LANGUAGE PatternSynonyms #-}
2
3
module Ide.Plugin.Stan (descriptor , Log ) where
3
4
4
- import Compat.HieTypes (HieASTs , HieFile )
5
- import Control.DeepSeq (NFData )
6
- import Control.Monad (void )
7
- import Control.Monad.IO.Class (liftIO )
8
- import Control.Monad.Trans.Class (lift )
9
- import Control.Monad.Trans.Maybe (MaybeT (MaybeT ), runMaybeT )
5
+ import Compat.HieTypes (HieASTs , HieFile (.. ))
6
+ import Control.DeepSeq (NFData )
7
+ import Control.Monad (void , when )
8
+ import Control.Monad.IO.Class (liftIO )
9
+ import Control.Monad.Trans.Maybe (MaybeT (MaybeT ), runMaybeT )
10
10
import Data.Default
11
- import Data.Foldable (toList )
12
- import Data.Hashable (Hashable )
13
- import qualified Data.HashMap.Strict as HM
14
- import qualified Data.Map as Map
15
- import Data.Maybe (fromJust , mapMaybe )
16
- import qualified Data.Text as T
11
+ import Data.Foldable (toList )
12
+ import Data.Hashable (Hashable )
13
+ import qualified Data.HashMap.Strict as HM
14
+ import qualified Data.Map as Map
15
+ import Data.Maybe (fromJust , mapMaybe ,
16
+ maybeToList )
17
+ import qualified Data.Text as T
17
18
import Development.IDE
18
19
import Development.IDE (Diagnostic (_codeDescription ))
19
20
import Development.IDE.Core.Rules (getHieFile ,
@@ -26,7 +27,7 @@ import Development.IDE.GHC.Compat (HieASTs (HieASTs),
26
27
runHsc , srcSpanEndCol ,
27
28
srcSpanEndLine ,
28
29
srcSpanStartCol ,
29
- srcSpanStartLine , tcg_exports )
30
+ srcSpanStartLine , tcg_exports , HieFile ( hie_hs_file ) )
30
31
import Development.IDE.GHC.Error (realSrcSpanToRange )
31
32
import GHC.Generics (Generic )
32
33
import Ide.Plugin.Config
@@ -36,12 +37,20 @@ import Ide.Types (PluginDescriptor (..),
36
37
defaultPluginDescriptor ,
37
38
pluginEnabledConfig )
38
39
import qualified Language.LSP.Protocol.Types as LSP
40
+ import Stan (getStanConfig , createCabalExtensionsMap )
39
41
import Stan.Analysis (Analysis (.. ), runAnalysis )
40
42
import Stan.Category (Category (.. ))
41
43
import Stan.Core.Id (Id (.. ))
42
44
import Stan.Inspection (Inspection (.. ))
43
45
import Stan.Inspection.All (inspectionsIds , inspectionsMap )
44
46
import Stan.Observation (Observation (.. ))
47
+ import System.Directory (makeRelativeToCurrentDirectory )
48
+ import Stan.Cli (StanArgs (.. ))
49
+ import Trial (whenResult , fiasco , pattern FiascoL , pattern ResultL , Fatality , Trial , TaggedTrial )
50
+ import Stan.Report.Settings (ToggleSolution (.. ), Verbosity (.. ), OutputSettings (.. ))
51
+ import Stan.Config (defaultConfig , ConfigP (.. ), applyConfig , Config )
52
+ import Stan.EnvVars (EnvVars (.. ))
53
+ import Data.HashSet (HashSet )
45
54
46
55
descriptor :: Recorder (WithPriority Log ) -> PluginId -> PluginDescriptor IdeState
47
56
descriptor recorder plId = (defaultPluginDescriptor plId desc)
@@ -53,11 +62,21 @@ descriptor recorder plId = (defaultPluginDescriptor plId desc)
53
62
where
54
63
desc = " Provides stan diagnostics. Built with stan-" <> VERSION_stan
55
64
56
- newtype Log = LogShake Shake. Log deriving (Show )
65
+ data Log = LogShake ! Shake. Log
66
+ | LogWarnConf ! [(Fatality , T. Text )]
67
+ | LogDebugStanConfigResult ! (Trial T. Text Stan.Config. Config )
68
+ | LogDebugStanEnvVars ! (TaggedTrial T. Text Bool )
69
+ | LogDebugStanCheckMap ! (HM. HashMap FilePath (HashSet (Id Inspection )))
70
+ deriving (Show )
57
71
58
72
instance Pretty Log where
59
73
pretty = \ case
60
74
LogShake log -> pretty log
75
+ LogWarnConf errs -> " Fiasco encountered when trying to load stan configuration. Using default inspections:"
76
+ <> line <> (pretty $ show errs)
77
+ LogDebugStanConfigResult t -> " Config result: " <> (pretty $ show t)
78
+ LogDebugStanEnvVars t -> " Env vars: " <> (pretty $ show t)
79
+ LogDebugStanCheckMap hm -> " Map of checks per file: " <> (pretty $ show hm)
61
80
62
81
data GetStanDiagnostics = GetStanDiagnostics
63
82
deriving (Eq , Show , Generic )
@@ -72,15 +91,52 @@ rules :: Recorder (WithPriority Log) -> PluginId -> Rules ()
72
91
rules recorder plId = do
73
92
define (cmapWithPrio LogShake recorder) $
74
93
\ GetStanDiagnostics file -> do
75
- config <- getPluginConfigAction plId
76
- if pluginEnabledConfig plcDiagnosticsOn config then do
94
+ plugConfig <- getPluginConfigAction plId
95
+ if pluginEnabledConfig plcDiagnosticsOn plugConfig then do
77
96
maybeHie <- getHieFile file
78
97
case maybeHie of
79
98
Nothing -> return ([] , Nothing )
80
99
Just hie -> do
81
- let enabledInspections = HM. fromList [(LSP. fromNormalizedFilePath file, inspectionsIds)]
82
- -- This should use Cabal config for extensions and Stan config for inspection preferences is the future
83
- let analysis = runAnalysis Map. empty enabledInspections [] [hie]
100
+ let isLoud = False -- in Stan: notJson = not isLoud
101
+ let stanArgs =
102
+ StanArgs
103
+ { stanArgsHiedir = " " -- :: !FilePath -- ^ Directory with HIE files
104
+ , stanArgsCabalFilePath = [] -- :: ![FilePath] -- ^ Path to @.cabal@ files.
105
+ , stanArgsOutputSettings = OutputSettings NonVerbose ShowSolution -- :: !OutputSettings -- ^ Settings for output terminal report
106
+ -- doesnt matter, because it is silenced by isLoud
107
+ , stanArgsReport = Nothing -- :: !(Maybe ReportArgs) -- ^ @HTML@ report settings
108
+ , stanArgsUseDefaultConfigFile = fiasco " " -- :: !(TaggedTrial Text Bool) -- ^ Use default @.stan.toml@ file
109
+ , stanArgsConfigFile = Nothing -- :: !(Maybe FilePath) -- ^ Path to a custom configurations file.
110
+ , stanArgsConfig = ConfigP {configChecks = fiasco " " ,
111
+ configRemoved = fiasco " " ,
112
+ configIgnored = fiasco " " } -- :: !PartialConfig
113
+ -- if they are not fiascos, .stan.toml's aren't taken into account
114
+ ,stanArgsJsonOut = not isLoud -- :: !Bool -- ^ Output the machine-readable output in JSON format instead.
115
+ }
116
+
117
+ (configTrial, useDefConfig, env) <- liftIO $ getStanConfig stanArgs isLoud
118
+ logWith recorder Debug (LogDebugStanConfigResult configTrial)
119
+ logWith recorder Debug (LogDebugStanEnvVars $ envVarsUseDefaultConfigFile env)
120
+
121
+ (cabalExtensionsMap, checksMap, confIgnored) <- case configTrial of
122
+ FiascoL es -> do
123
+ logWith recorder Warning (LogWarnConf es)
124
+ pure (Map. empty,
125
+ HM. fromList [(LSP. fromNormalizedFilePath file, inspectionsIds)],
126
+ [] )
127
+ ResultL warnings stanConfig -> do
128
+ let currentHSAbs = fromNormalizedFilePath file -- hie_hs_file hie
129
+ currentHSRel <- liftIO $ makeRelativeToCurrentDirectory currentHSAbs
130
+ cabalExtensionsMap <- liftIO $ createCabalExtensionsMap isLoud (stanArgsCabalFilePath stanArgs) [hie]
131
+
132
+ -- Files (keys) in checksMap need to have an absolute path for the analysis, but applyConfig needs to receive relative
133
+ -- filepaths to apply the config, because the toml config has relative paths. Stan itself seems to work only in terms of relative paths.
134
+ let checksMap = HM. mapKeys (const currentHSAbs) $ applyConfig [currentHSRel] stanConfig
135
+ logWith recorder Debug (LogDebugStanCheckMap checksMap)
136
+
137
+ let analysis = runAnalysis cabalExtensionsMap checksMap (configIgnored stanConfig) [hie]
138
+ pure (cabalExtensionsMap, checksMap, configIgnored stanConfig)
139
+ let analysis = runAnalysis cabalExtensionsMap checksMap confIgnored [hie]
84
140
return (analysisToDiagnostics file analysis, Just () )
85
141
else return ([] , Nothing )
86
142
0 commit comments