on master help sign in
command: Add CLI option to export GHCi configuration
e0a4f05Elliot Cameron
lib/command/src/Obelisk/Command.hs+9−1
@@ -100,6 +100,7 @@ data ObInternal
100 -- the preprocessor argument syntax is also handled outside
100 -- the preprocessor argument syntax is also handled outside
101 -- optparse-applicative, but it shouldn't ever conflict with another syntax
101 -- optparse-applicative, but it shouldn't ever conflict with another syntax
102 = ObInternal_ApplyPackages String String String [String]
102 = ObInternal_ApplyPackages String String String [String]
103+ | ObInternal_ExportGhciConfig
103 deriving Show
104 deriving Show
104
105
105obCommand :: ArgsConfig -> Parser ObCommand
106obCommand :: ArgsConfig -> Parser ObCommand
@@ -118,8 +119,14 @@ obCommand cfg = hsubparser
118 text "Hint: To open the documentation you can pipe the output of this command like"
119 text "Hint: To open the documentation you can pipe the output of this command like"
119 <$$> text "ob doc reflex reflex-dom-core | xargs -n1 xdg-open")
120 <$$> text "ob doc reflex reflex-dom-core | xargs -n1 xdg-open")
120 , command "hoogle" $ info (ObCommand_Hoogle <$> shellFlags <*> portOpt 8080) $ progDesc "Run a hoogle server locally for your project's dependency tree"
121 , command "hoogle" $ info (ObCommand_Hoogle <$> shellFlags <*> portOpt 8080) $ progDesc "Run a hoogle server locally for your project's dependency tree"
122+ , command "internal" $ info (ObCommand_Internal <$> internalCommand) $ progDesc "Internal Obelisk commands with unstable APIs"
121 ])
123 ])
122
124
125+internalCommand :: Parser ObInternal
126+internalCommand = hsubparser $ mconcat
127+ [ command "export-ghci-configuration" $ info (pure ObInternal_ExportGhciConfig) $ progDesc "Export the GHCi configuration used by ob run, etc.; useful for IDE integration"
128+ ]
129+
123packageNames :: Parser [String]
130packageNames :: Parser [String]
124packageNames = some (strArgument (metavar "PACKAGE-NAME..."))
131packageNames = some (strArgument (metavar "PACKAGE-NAME..."))
125
132
@@ -133,7 +140,7 @@ deployCommand cfg = hsubparser $ mconcat
133 where
140 where
134 platformP = hsubparser $ mconcat
141 platformP = hsubparser $ mconcat
135 [ command "android" $ info (pure (Android, [])) mempty
142 [ command "android" $ info (pure (Android, [])) mempty
136− , command "ios" $ info ((,) <$> pure IOS <*> (fmap pure $ strArgument (metavar "TEAMID" <> help "Your Team ID - found in the Apple developer portal"))) mempty
143+ , command "ios" $ info ((,) <$> pure IOS <*> fmap pure (strArgument (metavar "TEAMID" <> help "Your Team ID - found in the Apple developer portal"))) mempty
137 ]
144 ]
138
145
139 remoteBuilderParser :: Parser (Maybe RemoteBuilder)
146 remoteBuilderParser :: Parser (Maybe RemoteBuilder)
@@ -381,6 +388,7 @@ ob = \case
381 ObCommand_Internal icmd -> case icmd of
388 ObCommand_Internal icmd -> case icmd of
382 ObInternal_ApplyPackages origPath inPath outPath packagePaths -> do
389 ObInternal_ApplyPackages origPath inPath outPath packagePaths -> do
383 liftIO $ Preprocessor.applyPackages origPath inPath outPath packagePaths
390 liftIO $ Preprocessor.applyPackages origPath inPath outPath packagePaths
391+ ObInternal_ExportGhciConfig -> liftIO . putStrLn . unlines =<< exportGhciConfig
384
392
385haddockCommand :: [String] -> String
393haddockCommand :: [String] -> String
386haddockCommand pkgs = unwords
394haddockCommand pkgs = unwords
lib/command/src/Obelisk/Command/Run.hs+21−4
@@ -115,6 +115,11 @@ runWatch = withProjectRoot "." $ \root -> do
115 withGhciScript pkgs root $ \dotGhciPath ->
115 withGhciScript pkgs root $ \dotGhciPath ->
116 runGhcid root True dotGhciPath pkgs Nothing
116 runGhcid root True dotGhciPath pkgs Nothing
117
117
118+exportGhciConfig :: MonadObelisk m => m [String]
119+exportGhciConfig = withProjectRoot "." $ \root -> do
120+ pkgs <- fmap toList . parsePackagesOrFail =<< getLocalPkgs root
121+ getGhciSessionSettings pkgs "."
122+
118-- | Relative paths to local packages of an obelisk project.
123-- | Relative paths to local packages of an obelisk project.
119--
124--
120-- These are a combination of the obelisk predefined local packages,
125-- These are a combination of the obelisk predefined local packages,
@@ -274,7 +279,7 @@ withGhciScript
274 -> (FilePath -> m ()) -- ^ Action to run with the path to generated temporary .ghci
279 -> (FilePath -> m ()) -- ^ Action to run with the path to generated temporary .ghci
275 -> m ()
280 -> m ()
276withGhciScript packageInfos pathBase f = do
281withGhciScript packageInfos pathBase f = do
277− selfExe <- liftIO getExecutablePath
282+ ghciSettings <- getGhciSessionSettings packageInfos pathBase
278 let
283 let
279 packageNames = Set.fromList $ map _cabalPackageInfo_packageName packageInfos
284 packageNames = Set.fromList $ map _cabalPackageInfo_packageName packageInfos
280 modulesToLoad = mconcat
285 modulesToLoad = mconcat
@@ -283,9 +288,7 @@ withGhciScript packageInfos pathBase f = do
283 , [ "Frontend" | "frontend" `Set.member` packageNames ]
288 , [ "Frontend" | "frontend" `Set.member` packageNames ]
284 ]
289 ]
285 dotGhci = unlines
290 dotGhci = unlines
286− -- TODO: Shell escape
291+ [ ":set " <> unwords ghciSettings -- TODO: Shell escape
287− [ ":set -F -pgmF " <> selfExe <> " -optF " <> preprocessorIdentifier <> " " <> unwords (map (("-optF " <>) . makeRelative pathBase . _cabalPackageInfo_packageFile) packageInfos)
288− , ":set -i" <> intercalate ":" (packageInfos >>= rootedSourceDirs)
289 , if null modulesToLoad then "" else ":load " <> unwords modulesToLoad
292 , if null modulesToLoad then "" else ":load " <> unwords modulesToLoad
290 , "import qualified Obelisk.Run"
293 , "import qualified Obelisk.Run"
291 , "import qualified Frontend"
294 , "import qualified Frontend"
@@ -296,6 +299,20 @@ withGhciScript packageInfos pathBase f = do
296 liftIO $ writeFile dotGhciPath dotGhci
299 liftIO $ writeFile dotGhciPath dotGhci
297 f dotGhciPath
300 f dotGhciPath
298
301
302+-- | Builds a list of options to pass to ghci or set in .ghci file that configures
303+-- the preprocessor and source includes.
304+getGhciSessionSettings
305+ :: MonadObelisk m
306+ => [CabalPackageInfo] -- ^ List of packages to load into ghci
307+ -> FilePath -- ^ All paths written to the .ghci file will be relative to this path
308+ -> m [String]
309+getGhciSessionSettings packageInfos pathBase = do
310+ selfExe <- liftIO getExecutablePath
311+ -- TODO: Shell escape
312+ pure
313+ $ ["-F", "-pgmF", selfExe, "-optF", preprocessorIdentifier]
314+ <> concatMap (\p -> ["-optF", makeRelative pathBase $ _cabalPackageInfo_packageFile p]) packageInfos
315+ <> [ "-i" <> intercalate ":" (packageInfos >>= rootedSourceDirs) ]
299 where
316 where
300 rootedSourceDirs pkg = NE.toList $
317 rootedSourceDirs pkg = NE.toList $
301 makeRelative pathBase . (_cabalPackageInfo_packageRoot pkg </>) <$> _cabalPackageInfo_sourceDirs pkg
318 makeRelative pathBase . (_cabalPackageInfo_packageRoot pkg </>) <$> _cabalPackageInfo_sourceDirs pkg