1- {-# LANGUAGE NoImplicitPrelude #-}
2- {-# LANGUAGE OverloadedRecordDot #-}
3- {-# LANGUAGE OverloadedStrings #-}
1+ {-# LANGUAGE NoImplicitPrelude #-}
2+ {-# LANGUAGE DuplicateRecordFields #-}
3+ {-# LANGUAGE NoFieldSelectors #-}
4+ {-# LANGUAGE OverloadedRecordDot #-}
5+ {-# LANGUAGE OverloadedStrings #-}
46
57{-|
68Module : Stack.IDE
@@ -11,33 +13,68 @@ Types and functions related to Stack's @ide@ command.
1113-}
1214
1315module Stack.IDE
14- ( OutputStream (.. )
15- , ListPackagesCmd (.. )
16- , idePackagesCmd
16+ ( idePackagesCmd
1717 , ideTargetsCmd
18- , listPackages
19- , listTargets
18+ , ideGhcOptionsCmd
2019 ) where
2120
21+ import qualified Data.ByteString as BS
2222import qualified Data.Map as Map
23+ import qualified Data.Map.Strict as M
2324import qualified Data.Set as Set
2425import qualified Data.Text as T
2526import Data.Tuple ( swap )
27+ import Stack.Build.FileTargets
28+ ( findFileTargets , getAllLocalTargets , getAllNonLocalTargets
29+ , getGhciPkgInfos , loadGhciPkgDescs , optsAndMacros
30+ )
31+ import Stack.Build.Installed ( toInstallMap )
32+ import Stack.Build.Source ( localDependencies , projectLocalPackages )
33+ import Stack.Build.Target ( NeedTargets (.. ) )
34+ import Stack.Package ( topSortPackageComponent )
35+ import Path.Extra ( forgivingResolveFile' )
2636import Stack.Prelude
2737import Stack.Runners
28- ( ShouldReexec (.. ), withBuildConfig , withConfig )
38+ ( ShouldReexec (.. ), withBuildConfig , withConfig
39+ , withEnvConfig
40+ )
2941import Stack.Types.BuildConfig
3042 ( BuildConfig (.. ), HasBuildConfig (.. ) )
43+ import Stack.Types.BuildOpts ( BuildOpts (.. ) )
44+ import qualified Stack.Types.BuildOpts as BenchmarkOpts ( BenchmarkOpts (.. ) )
45+ import qualified Stack.Types.BuildOpts as TestOpts ( TestOpts (.. ) )
46+ import Stack.Types.BuildOptsCLI
47+ ( BuildOptsCLI (.. ), defaultBuildOptsCLI )
48+ import Stack.Types.Config ( buildOptsL )
49+ import Stack.Types.EnvConfig ( EnvConfig (.. ), HasEnvConfig (.. ) )
3150import Stack.Types.IdeOpts ( ListPackagesCmd (.. ), OutputStream (.. ) )
3251import Stack.Types.NamedComponent
33- ( NamedComponent , isCBench , isCExe , isCTest
52+ ( NamedComponent , isCBench , isCExe , isCSubLib , isCTest
3453 , renderPkgComponent
3554 )
55+ import Stack.Types.Package ( LocalPackage (.. ), Package (.. ) )
3656import Stack.Types.Runner ( Runner )
3757import Stack.Types.SourceMap
3858 ( ProjectPackage (.. ), SMWanted (.. ), ppComponentsMaybe )
3959import System.IO ( putStrLn )
4060
61+ -- | Type representing \'pretty\' exceptions thrown by functions exported by the
62+ -- "Stack.IDE" module.
63+ newtype IdePrettyException
64+ = FileTargetIsInvalidAbsFile String
65+ deriving (Show , Typeable )
66+
67+ instance Pretty IdePrettyException where
68+ pretty (FileTargetIsInvalidAbsFile name) =
69+ " [S-9208]"
70+ <> line
71+ <> fillSep
72+ [ flow " Cannot work out a valid path for file target"
73+ , style File (fromString name) <> " ."
74+ ]
75+
76+ instance Exception IdePrettyException
77+
4178-- | Function underlying the @stack ide packages@ command. List packages in the
4279-- project.
4380idePackagesCmd :: (OutputStream , ListPackagesCmd ) -> RIO Runner ()
@@ -93,3 +130,70 @@ listTargets stream isCompType = do
93130 toNameAndComponent pkgName' =
94131 fmap (map (pkgName',) . Set. toList) . ppComponentsMaybe (\ x ->
95132 if isCompType x then Just x else Nothing )
133+
134+ -- | Function underlying the @stack ide ghc-options@ command.
135+ ideGhcOptionsCmd :: Text -> RIO Runner ()
136+ ideGhcOptionsCmd rawTarget =
137+ let boptsCLI = defaultBuildOptsCLI { initialBuildSteps = True }
138+ in withConfig YesReexec $ withEnvConfig AllowNoTargets boptsCLI $ do
139+ bopts <- view buildOptsL
140+ -- override env so running of tests and benchmarks is disabled
141+ let boptsLocal = bopts
142+ { testOpts = bopts. testOpts { TestOpts. runTests = False }
143+ , benchmarkOpts =
144+ bopts. benchmarkOpts { BenchmarkOpts. runBenchmarks = False }
145+ }
146+ local (set buildOptsL boptsLocal) (ideGhcOptions rawTarget)
147+
148+ ideGhcOptions :: HasEnvConfig env => Text -> RIO env ()
149+ ideGhcOptions rawTarget = do
150+ sourceMap <- view $ envConfigL . to (. sourceMap)
151+ installMap <- toInstallMap sourceMap
152+ locals <- projectLocalPackages
153+ depLocals <- localDependencies
154+ let localMap = M. fromList [(lp. package. name, lp) | lp <- locals ++ depLocals]
155+ -- Parse to either file targets or build targets
156+ (inputTargets, mfileTargets) <- processRawTarget rawTarget >>= maybe
157+ (pure (mempty , Nothing ))
158+ -- Figure out targets based on file target
159+ (findFileTargets locals . pure )
160+ -- Get a list of all the local target packages.
161+ (directlyWanted, extraLoadDeps) <-
162+ getAllLocalTargets True inputTargets Nothing localMap
163+ -- Get a list of all the non-local target packages.
164+ nonLocalTargets <- getAllNonLocalTargets inputTargets
165+ let localTargets = directlyWanted <> extraLoadDeps
166+ getInternalDependencies target localPackage =
167+ topSortPackageComponent localPackage. package target False
168+ internalDependencies =
169+ M. intersectionWith getInternalDependencies inputTargets localMap
170+ relevantDependencies = M. filter (any isCSubLib) internalDependencies
171+ -- Load package descriptions.
172+ pkgDescs <- loadGhciPkgDescs mempty localTargets
173+ pkgs <- getGhciPkgInfos installMap [] (fmap fst mfileTargets) pkgDescs
174+ (omittedOpts, pkgopts, macros) <-
175+ optsAndMacros
176+ Nothing
177+ localTargets
178+ pkgs
179+ nonLocalTargets
180+ relevantDependencies
181+ let outputDivider = liftIO $ putStrLn " ---"
182+ outputDivider
183+ mapM_ (liftIO . putStrLn ) pkgopts
184+ outputDivider
185+ liftIO $ BS. putStr macros
186+ outputDivider
187+ mapM_ (liftIO . putStrLn ) omittedOpts
188+ outputDivider
189+
190+ processRawTarget :: HasEnvConfig env => Text -> RIO env (Maybe (Path Abs File ))
191+ processRawTarget rawTarget =
192+ if " .hs" `T.isSuffixOf` rawTarget || " .lhs" `T.isSuffixOf` rawTarget
193+ then
194+ forgivingResolveFile' rawTarget' >>= maybe
195+ (prettyThrowM $ FileTargetIsInvalidAbsFile rawTarget')
196+ (pure . Just )
197+ else pure Nothing
198+ where
199+ rawTarget' = T. unpack rawTarget
0 commit comments