{-# LANGUAGE CPP #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedLabels #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
module Ide.Plugin.Ormolu
( descriptor
, provider
, LogEvent
)
where
import Control.Exception (Handler (..), IOException,
SomeException (..), catches,
handle)
import Control.Monad.Except (ExceptT (ExceptT), runExceptT,
throwError)
import Control.Monad.Extra
import Control.Monad.IO.Class (liftIO)
import Control.Monad.Trans
import Control.Monad.Trans.Except (ExceptT (..), mapExceptT,
runExceptT)
import Data.Functor ((<&>))
import Data.List (intercalate)
import Data.Maybe (catMaybes)
import Data.Text (Text)
import qualified Data.Text as T
import Development.IDE hiding (pluginHandlers)
import Development.IDE.GHC.Compat (hsc_dflags, moduleNameString)
import qualified Development.IDE.GHC.Compat as D
import qualified Development.IDE.GHC.Compat.Util as S
import GHC.LanguageExtensions.Type
import Ide.Plugin.Error (PluginError (PluginInternalError))
import Ide.Plugin.Properties
import Ide.PluginUtils
import Ide.Types hiding (Config)
import qualified Ide.Types as Types
import Language.LSP.Protocol.Message
import Language.LSP.Protocol.Types
import Language.LSP.Server hiding (defaultConfig)
import Ormolu
import System.Exit
import System.FilePath
import System.Process.Run (cwd, proc)
import System.Process.Text (readCreateProcessWithExitCode)
import Text.Read (readMaybe)
descriptor :: Recorder (WithPriority LogEvent) -> PluginId -> PluginDescriptor IdeState
descriptor :: Recorder (WithPriority LogEvent)
-> PluginId -> PluginDescriptor IdeState
descriptor Recorder (WithPriority LogEvent)
recorder PluginId
plId =
(forall ideState. PluginId -> PluginDescriptor ideState
defaultPluginDescriptor PluginId
plId)
{ $sel:pluginHandlers:PluginDescriptor :: PluginHandlers IdeState
pluginHandlers = forall a. FormattingHandler a -> PluginHandlers a
mkFormattingHandlers forall a b. (a -> b) -> a -> b
$ Recorder (WithPriority LogEvent)
-> PluginId -> FormattingHandler IdeState
provider Recorder (WithPriority LogEvent)
recorder PluginId
plId,
$sel:pluginConfigDescriptor:PluginDescriptor :: ConfigDescriptor
pluginConfigDescriptor = ConfigDescriptor
defaultConfigDescriptor {$sel:configCustomConfig:ConfigDescriptor :: CustomConfig
configCustomConfig = forall (r :: [PropertyKey]). Properties r -> CustomConfig
mkCustomConfig Properties '[ 'PropertyKey "external" 'TBoolean]
properties}
}
properties :: Properties '[ 'PropertyKey "external" 'TBoolean]
properties :: Properties '[ 'PropertyKey "external" 'TBoolean]
properties =
Properties '[]
emptyProperties
forall a b. a -> (a -> b) -> b
& forall (s :: Symbol) (r :: [PropertyKey]).
(KnownSymbol s, NotElem s r) =>
KeyNameProxy s
-> Text
-> Bool
-> Properties r
-> Properties ('PropertyKey s 'TBoolean : r)
defineBooleanProperty
#external
Text
"Call out to an external \"ormolu\" executable, rather than using the bundled library"
Bool
False
provider :: Recorder (WithPriority LogEvent) -> PluginId -> FormattingHandler IdeState
provider :: Recorder (WithPriority LogEvent)
-> PluginId -> FormattingHandler IdeState
provider Recorder (WithPriority LogEvent)
recorder PluginId
plId IdeState
ideState FormattingType
typ Text
contents NormalizedFilePath
fp FormattingOptions
_ = forall e (m :: * -> *) a. m (Either e a) -> ExceptT e m a
ExceptT forall a b. (a -> b) -> a -> b
$ forall c (m :: * -> *) a.
MonadLsp c m =>
Text -> ProgressCancellable -> m a -> m a
withIndefiniteProgress Text
title ProgressCancellable
Cancellable forall a b. (a -> b) -> a -> b
$ forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT forall a b. (a -> b) -> a -> b
$ do
[[Char]]
fileOpts <-
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [] (DynFlags -> [[Char]]
fromDyn forall b c a. (b -> c) -> (a -> b) -> a -> c
. HscEnv -> DynFlags
hsc_dflags forall b c a. (b -> c) -> (a -> b) -> a -> c
. HscEnvEq -> HscEnv
hscEnv)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (forall a. [Char] -> IdeState -> Action a -> IO a
runAction [Char]
"Ormolu" IdeState
ideState forall a b. (a -> b) -> a -> b
$ forall k v.
IdeRule k v =>
k -> NormalizedFilePath -> Action (Maybe v)
use GhcSession
GhcSession NormalizedFilePath
fp)
Bool
useCLI <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ forall a. [Char] -> IdeState -> Action a -> IO a
runAction [Char]
"Ormolu" IdeState
ideState forall a b. (a -> b) -> a -> b
$ forall (s :: Symbol) (k :: PropertyKey) (t :: PropertyType)
(r :: [PropertyKey]).
HasProperty s k t r =>
KeyNameProxy s -> PluginId -> Properties r -> Action (ToHsType t)
usePropertyAction forall a. IsLabel "external" a => a
#external PluginId
plId Properties '[ 'PropertyKey "external" 'TBoolean]
properties
if Bool
useCLI
then forall (m :: * -> *) e a (n :: * -> *) e' b.
(m (Either e a) -> n (Either e' b))
-> ExceptT e m a -> ExceptT e' n b
mapExceptT forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ forall e (m :: * -> *) a. m (Either e a) -> ExceptT e m a
ExceptT
forall a b. (a -> b) -> a -> b
$ forall e a. Exception e => (e -> IO a) -> IO a -> IO a
handle @IOException
(forall (f :: * -> *) a. Applicative f => a -> f a
pure forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. a -> Either a b
Left forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> PluginError
PluginInternalError forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> Text
T.pack forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> [Char]
show)
forall a b. (a -> b) -> a -> b
$ forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT forall a b. (a -> b) -> a -> b
$ [[Char]] -> ExceptT PluginError IO ([TextEdit] |? Null)
cliHandler [[Char]]
fileOpts
else do
forall (m :: * -> *) msg.
(HasCallStack, MonadIO m) =>
Recorder (WithPriority msg) -> Priority -> msg -> m ()
logWith Recorder (WithPriority LogEvent)
recorder Priority
Debug forall a b. (a -> b) -> a -> b
$ [Char] -> LogEvent
LogCompiledInVersion VERSION_ormolu
let
fmt :: T.Text -> Config RegionIndices -> IO (Either SomeException T.Text)
fmt :: Text -> Config RegionIndices -> IO (Either SomeException Text)
fmt Text
cont Config RegionIndices
conf = forall a b c. (a -> b -> c) -> b -> a -> c
flip forall a. IO a -> [Handler a] -> IO a
catches forall {b}. [Handler (Either SomeException b)]
handlers forall a b. (a -> b) -> a -> b
$ do
#if MIN_VERSION_ormolu(0,5,3)
cabalInfo <- getCabalInfoForSourceFile fp' <&> \case
CabalNotFound -> Nothing
CabalDidNotMention cabalInfo -> Just cabalInfo
CabalFound cabalInfo -> Just cabalInfo
#if MIN_VERSION_ormolu(0,7,0)
(fixityOverrides, moduleReexports) <- getDotOrmoluForSourceFile fp'
let conf' = refineConfig ModuleSource cabalInfo (Just fixityOverrides) (Just moduleReexports) conf
#else
fixityOverrides <- traverse getFixityOverridesForSourceFile cabalInfo
let conf' = refineConfig ModuleSource cabalInfo fixityOverrides conf
#endif
let cont' = cont
#else
let conf' :: Config RegionIndices
conf' = Config RegionIndices
conf
cont' :: [Char]
cont' = Text -> [Char]
T.unpack Text
cont
#endif
forall a b. b -> Either a b
Right forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *).
MonadIO m =>
Config RegionIndices -> [Char] -> [Char] -> m Text
ormolu Config RegionIndices
conf' [Char]
fp' [Char]
cont'
handlers :: [Handler (Either SomeException b)]
handlers =
[ forall a e. Exception e => (e -> IO a) -> Handler a
Handler forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a. Applicative f => a -> f a
pure forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. a -> Either a b
Left forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall e. Exception e => e -> SomeException
SomeException @OrmoluException
, forall a e. Exception e => (e -> IO a) -> Handler a
Handler forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a. Applicative f => a -> f a
pure forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. a -> Either a b
Left forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall e. Exception e => e -> SomeException
SomeException @IOException
]
Either SomeException Text
res <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ Text -> Config RegionIndices -> IO (Either SomeException Text)
fmt Text
contents Config RegionIndices
defaultConfig { cfgDynOptions :: [DynOption]
cfgDynOptions = forall a b. (a -> b) -> [a] -> [b]
map [Char] -> DynOption
DynOption [[Char]]
fileOpts, cfgRegion :: RegionIndices
cfgRegion = RegionIndices
region }
Either SomeException Text
-> ExceptT PluginError (LspM Config) ([TextEdit] |? Null)
ret Either SomeException Text
res
where
fp' :: [Char]
fp' = NormalizedFilePath -> [Char]
fromNormalizedFilePath NormalizedFilePath
fp
region :: RegionIndices
region :: RegionIndices
region = case FormattingType
typ of
FormattingType
FormatText ->
Maybe Int -> Maybe Int -> RegionIndices
RegionIndices forall a. Maybe a
Nothing forall a. Maybe a
Nothing
FormatRange (Range (Position UInt
sl UInt
_) (Position UInt
el UInt
_)) ->
Maybe Int -> Maybe Int -> RegionIndices
RegionIndices (forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ UInt
sl forall a. Num a => a -> a -> a
+ UInt
1) (forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ UInt
el forall a. Num a => a -> a -> a
+ UInt
1)
title :: Text
title = [Char] -> Text
T.pack forall a b. (a -> b) -> a -> b
$ [Char]
"Formatting " forall a. Semigroup a => a -> a -> a
<> [Char] -> [Char]
takeFileName (NormalizedFilePath -> [Char]
fromNormalizedFilePath NormalizedFilePath
fp)
ret :: Either SomeException T.Text -> ExceptT PluginError (LspM Types.Config) ([TextEdit] |? Null)
ret :: Either SomeException Text
-> ExceptT PluginError (LspM Config) ([TextEdit] |? Null)
ret (Left SomeException
err) = forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError forall a b. (a -> b) -> a -> b
$ Text -> PluginError
PluginInternalError forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> Text
T.pack forall a b. (a -> b) -> a -> b
$ [Char]
"ormoluCmd: " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> [Char]
show SomeException
err
ret (Right Text
new) = forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a b. a -> a |? b
InL forall a b. (a -> b) -> a -> b
$ Text -> Text -> [TextEdit]
makeDiffTextEdit Text
contents Text
new
fromDyn :: D.DynFlags -> [String]
fromDyn :: DynFlags -> [[Char]]
fromDyn DynFlags
df =
let
pp :: [[Char]]
pp =
let p :: [Char]
p = Settings -> [Char]
D.sPgm_F forall a b. (a -> b) -> a -> b
$ DynFlags -> Settings
D.settings DynFlags
df
in [[Char]
"-pgmF=" forall a. Semigroup a => a -> a -> a
<> [Char]
p | Bool -> Bool
not (forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Char]
p)]
pm :: [[Char]]
pm = ([Char]
"-fplugin=" forall a. Semigroup a => a -> a -> a
<>) forall b c a. (b -> c) -> (a -> b) -> a -> c
. ModuleName -> [Char]
moduleNameString forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> DynFlags -> [ModuleName]
D.pluginModNames DynFlags
df
ex :: [[Char]]
ex = Extension -> [Char]
showExtension forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. Enum a => EnumSet a -> [a]
S.toList (DynFlags -> EnumSet Extension
D.extensionFlags DynFlags
df)
in [[Char]]
pp forall a. Semigroup a => a -> a -> a
<> [[Char]]
pm forall a. Semigroup a => a -> a -> a
<> [[Char]]
ex
cliHandler :: [String] -> ExceptT PluginError IO ([TextEdit] |? Null)
cliHandler :: [[Char]] -> ExceptT PluginError IO ([TextEdit] |? Null)
cliHandler [[Char]]
fileOpts = do
CLIVersionInfo{Bool
noCabal :: CLIVersionInfo -> Bool
noCabal :: Bool
noCabal} <- do
(ExitCode
exitCode, Text
out, Text
_err) <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ CreateProcess -> Text -> IO (ExitCode, Text, Text)
readCreateProcessWithExitCode ( [Char] -> [[Char]] -> CreateProcess
proc [Char]
"ormolu" [[Char]
"--version"] ) Text
""
let version :: Maybe [Int]
version = do
forall (f :: * -> *). Alternative f => Bool -> f ()
guard forall a b. (a -> b) -> a -> b
$ ExitCode
exitCode forall a. Eq a => a -> a -> Bool
== ExitCode
ExitSuccess
Text
"ormolu" : Text
v : [Text]
_ <- forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ Text -> [Text]
T.words Text
out
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse (forall a. Read a => [Char] -> Maybe a
readMaybe @Int forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> [Char]
T.unpack) forall a b. (a -> b) -> a -> b
$ Text -> Text -> [Text]
T.splitOn Text
"." Text
v
case Maybe [Int]
version of
Just [Int]
v -> do
forall (m :: * -> *) msg.
(HasCallStack, MonadIO m) =>
Recorder (WithPriority msg) -> Priority -> msg -> m ()
logWith Recorder (WithPriority LogEvent)
recorder Priority
Debug forall a b. (a -> b) -> a -> b
$ [Int] -> LogEvent
LogExternalVersion [Int]
v
forall (f :: * -> *) a. Applicative f => a -> f a
pure CLIVersionInfo
{ noCabal :: Bool
noCabal = [Int]
v forall a. Ord a => a -> a -> Bool
>= [Int
0, Int
7]
}
Maybe [Int]
Nothing -> do
forall (m :: * -> *) msg.
(HasCallStack, MonadIO m) =>
Recorder (WithPriority msg) -> Priority -> msg -> m ()
logWith Recorder (WithPriority LogEvent)
recorder Priority
Debug forall a b. (a -> b) -> a -> b
$ [Int] -> LogEvent
LogExternalVersion []
forall (m :: * -> *) msg.
(HasCallStack, MonadIO m) =>
Recorder (WithPriority msg) -> Priority -> msg -> m ()
logWith Recorder (WithPriority LogEvent)
recorder Priority
Warning forall a b. (a -> b) -> a -> b
$ Text -> LogEvent
NoVersion Text
out
forall (f :: * -> *) a. Applicative f => a -> f a
pure CLIVersionInfo
{ noCabal :: Bool
noCabal = Bool
True
}
(ExitCode
exitCode, Text
out, Text
err) <- do
let commandArgs :: [[Char]]
commandArgs = forall a b. (a -> b) -> [a] -> [b]
map ([Char]
"-o" forall a. Semigroup a => a -> a -> a
<>) [[Char]]
fileOpts
forall a. Semigroup a => a -> a -> a
<> (if Bool
noCabal then [[Char]
"--no-cabal"] else [[Char]
"--stdin-input-file", [Char]
fp'])
forall a. Semigroup a => a -> a -> a
<> forall a. [Maybe a] -> [a]
catMaybes
[ ([Char]
"--start-line=" forall a. Semigroup a => a -> a -> a
<>) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> [Char]
show forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> RegionIndices -> Maybe Int
regionStartLine RegionIndices
region
, ([Char]
"--end-line=" forall a. Semigroup a => a -> a -> a
<>) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> [Char]
show forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> RegionIndices -> Maybe Int
regionEndLine RegionIndices
region
]
cwd :: [Char]
cwd = [Char] -> [Char]
takeDirectory [Char]
fp'
forall (m :: * -> *) msg.
(HasCallStack, MonadIO m) =>
Recorder (WithPriority msg) -> Priority -> msg -> m ()
logWith Recorder (WithPriority LogEvent)
recorder Priority
Debug forall a b. (a -> b) -> a -> b
$ [[Char]] -> [Char] -> LogEvent
LogOrmoluCommand [[Char]]
commandArgs [Char]
cwd
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ CreateProcess -> Text -> IO (ExitCode, Text, Text)
readCreateProcessWithExitCode ([Char] -> [[Char]] -> CreateProcess
proc [Char]
"ormolu" [[Char]]
commandArgs) {cwd :: Maybe [Char]
cwd = forall a. a -> Maybe a
Just [Char]
cwd} Text
contents
case ExitCode
exitCode of
ExitCode
ExitSuccess -> do
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not forall a b. (a -> b) -> a -> b
$ Text -> Bool
T.null Text
err) forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) msg.
(HasCallStack, MonadIO m) =>
Recorder (WithPriority msg) -> Priority -> msg -> m ()
logWith Recorder (WithPriority LogEvent)
recorder Priority
Debug forall a b. (a -> b) -> a -> b
$ Text -> LogEvent
StdErr Text
err
forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a b. a -> a |? b
InL forall a b. (a -> b) -> a -> b
$ Text -> Text -> [TextEdit]
makeDiffTextEdit Text
contents Text
out
ExitFailure Int
n -> do
forall (m :: * -> *) msg.
(HasCallStack, MonadIO m) =>
Recorder (WithPriority msg) -> Priority -> msg -> m ()
logWith Recorder (WithPriority LogEvent)
recorder Priority
Info forall a b. (a -> b) -> a -> b
$ Text -> LogEvent
StdErr Text
err
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError forall a b. (a -> b) -> a -> b
$ Text -> PluginError
PluginInternalError forall a b. (a -> b) -> a -> b
$ Text
"Ormolu failed with exit code " forall a. Semigroup a => a -> a -> a
<> [Char] -> Text
T.pack (forall a. Show a => a -> [Char]
show Int
n)
newtype CLIVersionInfo = CLIVersionInfo
{ CLIVersionInfo -> Bool
noCabal :: Bool
}
data LogEvent
= NoVersion Text
| StdErr Text
| LogCompiledInVersion String
| LogExternalVersion [Int]
| LogOrmoluCommand [String] FilePath
deriving (Int -> LogEvent -> [Char] -> [Char]
[LogEvent] -> [Char] -> [Char]
LogEvent -> [Char]
forall a.
(Int -> a -> [Char] -> [Char])
-> (a -> [Char]) -> ([a] -> [Char] -> [Char]) -> Show a
showList :: [LogEvent] -> [Char] -> [Char]
$cshowList :: [LogEvent] -> [Char] -> [Char]
show :: LogEvent -> [Char]
$cshow :: LogEvent -> [Char]
showsPrec :: Int -> LogEvent -> [Char] -> [Char]
$cshowsPrec :: Int -> LogEvent -> [Char] -> [Char]
Show)
instance Pretty LogEvent where
pretty :: forall ann. LogEvent -> Doc ann
pretty = \case
NoVersion Text
t -> Doc ann
"Couldn't get Ormolu version:" forall a. Semigroup a => a -> a -> a
<> forall ann. Doc ann
line forall a. Semigroup a => a -> a -> a
<> forall ann. Int -> Doc ann -> Doc ann
indent Int
2 (forall a ann. Pretty a => a -> Doc ann
pretty Text
t)
StdErr Text
t -> Doc ann
"Ormolu stderr:" forall a. Semigroup a => a -> a -> a
<> forall ann. Doc ann
line forall a. Semigroup a => a -> a -> a
<> forall ann. Int -> Doc ann -> Doc ann
indent Int
2 (forall a ann. Pretty a => a -> Doc ann
pretty Text
t)
LogCompiledInVersion [Char]
v -> Doc ann
"Using compiled in ormolu-" forall a. Semigroup a => a -> a -> a
<> forall a ann. Pretty a => a -> Doc ann
pretty [Char]
v
LogExternalVersion [Int]
v ->
Doc ann
"Using external ormolu"
forall a. Semigroup a => a -> a -> a
<> if forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Int]
v then Doc ann
"" else Doc ann
"-"
forall a. Semigroup a => a -> a -> a
<> forall a ann. Pretty a => a -> Doc ann
pretty (forall a. [a] -> [[a]] -> [a]
intercalate [Char]
"." forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map forall a. Show a => a -> [Char]
show [Int]
v)
LogOrmoluCommand [[Char]]
commandArgs [Char]
cwd -> Doc ann
"Running: `ormolu " forall a. Semigroup a => a -> a -> a
<> forall a ann. Pretty a => a -> Doc ann
pretty ([[Char]] -> [Char]
unwords [[Char]]
commandArgs) forall a. Semigroup a => a -> a -> a
<> Doc ann
"` in directory " forall a. Semigroup a => a -> a -> a
<> forall a ann. Pretty a => a -> Doc ann
pretty [Char]
cwd
showExtension :: Extension -> String
showExtension :: Extension -> [Char]
showExtension Extension
Cpp = [Char]
"-XCPP"
showExtension Extension
other = [Char]
"-X" forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> [Char]
show Extension
other