1
1
mirror of https://github.com/anoma/juvix.git synced 2024-12-14 08:27:03 +03:00
juvix/app/Commands/Format.hs
janmasrovira 3d012cc8fb
Support more paths (#2000)
- Closes #1993 

This pr makes it possible to use `~`, `..` and environment variables in
the `juvix.yaml` and all flags / input of the cli.

In the CLI, the shell will be responsible for replacing environment
variables with their value, so the usual syntax can be used. For the
`dependencies` field, I have implemented a parser that has some
restrictions:
1. Environment variables are given with the makefile-like syntax
`$(VAR)`
2. The three characters `$` `(` `)` are reserved for the environment
variables syntax.
    They cannot be part of the path.
3. `~` is reserved for `$(HOME)`. I.e. the prepath `~~` will expand to
`$HOME$HOME`.
4. Nested environment variables are not allowed.

Thanks @paulcadman for the feedback. I think we are ready to merge this
nightmarish pr 👻

---------

Co-authored-by: Paul Cadman <git@paulcadman.dev>
2023-04-19 15:56:48 +01:00

66 lines
2.3 KiB
Haskell

module Commands.Format where
import Commands.Base
import Commands.Format.Options
import Juvix.Formatter
import Juvix.Prelude.Pretty
data FormatNoEditRenderMode
= ReformattedFile (NonEmpty AnsiText)
| InputPath (Path Abs File)
| Silent
data FormatRenderMode
= EditInPlace FormattedFileInfo
| NoEdit FormatNoEditRenderMode
data FormatTarget
= TargetFile
| TargetDir
runCommand :: forall r. Members '[Embed IO, App, Resource, Files] r => FormatOptions -> Sem r ()
runCommand opts = do
f <- filePathToAbs (opts ^. formatInput)
let target = case f of
Left {} -> TargetFile
Right {} -> TargetDir
runOutputSem (renderFormattedOutput target opts) $ runScopeFileApp $ do
res <- case f of
Left p -> format p
Right p -> formatProject p
when (res == FormatResultFail) (embed (exitWith (ExitFailure 1)))
renderModeFromOptions :: FormatTarget -> FormatOptions -> FormattedFileInfo -> FormatRenderMode
renderModeFromOptions target opts formattedInfo
| opts ^. formatInPlace = EditInPlace formattedInfo
| opts ^. formatCheck = NoEdit Silent
| otherwise = case target of
TargetFile -> NoEdit (ReformattedFile (formattedInfo ^. formattedFileInfoContentsAnsi))
TargetDir -> NoEdit (InputPath (formattedInfo ^. formattedFileInfoPath))
renderFormattedOutput :: forall r. Members '[Embed IO, App, Resource, Files] r => FormatTarget -> FormatOptions -> FormattedFileInfo -> Sem r ()
renderFormattedOutput target opts fInfo = do
let renderMode = renderModeFromOptions target opts fInfo
outputResult renderMode
where
outputResult :: FormatRenderMode -> Sem r ()
outputResult = \case
EditInPlace i@(FormattedFileInfo {..}) ->
runTempFileIO $
restoreFileOnError _formattedFileInfoPath $
writeFile' _formattedFileInfoPath (i ^. formattedFileInfoContentsText)
NoEdit m -> case m of
ReformattedFile ts -> forM_ ts renderStdOut
InputPath p -> say (pack (toFilePath p))
Silent -> return ()
runScopeFileApp :: Member App r => Sem (ScopeEff ': r) a -> Sem r a
runScopeFileApp = interpret $ \case
ScopeFile p -> do
let appFile =
AppPath
{ _pathPath = mkPrepath (toFilePath p),
_pathIsInput = False
}
runPipeline appFile upToScoping