-
Notifications
You must be signed in to change notification settings - Fork 211
/
Format.hs
122 lines (99 loc) · 4.07 KB
/
Format.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
-- | This module contains the implementation of the @dhall format@ subcommand
module Dhall.Format
( -- * Format
Format(..)
, format
) where
import Data.Foldable (for_)
import Data.List.NonEmpty (NonEmpty)
import Data.Maybe (fromMaybe)
import Dhall.Pretty (CharacterSet, annToAnsiStyle, detectCharacterSet)
import Dhall.Util
( Censor
, CheckFailed (..)
, Header (..)
, Input (..)
, OutputMode (..)
, Transitivity (..)
, handleMultipleChecksFailed
)
import qualified Data.Text.IO
import qualified Dhall.Import
import qualified Dhall.Pretty
import qualified Dhall.Util
import qualified Prettyprinter as Pretty
import qualified Prettyprinter.Render.Terminal as Pretty.Terminal
import qualified Prettyprinter.Render.Text as Pretty.Text
import qualified System.AtomicWrite.Writer.LazyText as AtomicWrite.LazyText
import qualified System.Console.ANSI
import qualified System.FilePath
import qualified System.IO
-- | Arguments to the `format` subcommand
data Format = Format
{ chosenCharacterSet :: Maybe CharacterSet
, censor :: Censor
, transitivity :: Transitivity
, inputs :: NonEmpty Input
, outputMode :: OutputMode
}
-- | Implementation of the @dhall format@ subcommand
format :: Format -> IO ()
format (Format { inputs = inputs0, transitivity = transitivity0, ..}) =
handleMultipleChecksFailed "format" "formatted" go inputs0
where
go input = do
let directory = case input of
StandardInput ->
"."
InputFile file ->
System.FilePath.takeDirectory file
let status = Dhall.Import.emptyStatus directory
let layoutHeaderAndExpr (Header header, expr) =
let characterSet = fromMaybe (detectCharacterSet expr) chosenCharacterSet
in
Dhall.Pretty.layout
( Pretty.pretty header
<> Dhall.Pretty.prettyCharacterSet characterSet expr
<> "\n")
(inputName, originalText, transitivity) <- case input of
InputFile file -> do
text <- Data.Text.IO.readFile file
return (file, text, transitivity0)
StandardInput -> do
text <- Data.Text.IO.getContents
return ("(input)", text, NonTransitive)
headerAndExpr@(_, parsedExpression) <- Dhall.Util.getExpressionAndHeaderFromStdinText censor inputName originalText
case transitivity of
Transitive ->
for_ parsedExpression $ \import_ -> do
maybeFilepath <- Dhall.Import.dependencyToFile status import_
for_ maybeFilepath $ \filepath ->
go (InputFile filepath)
NonTransitive ->
return ()
let docStream = layoutHeaderAndExpr headerAndExpr
let formattedText = Pretty.Text.renderStrict docStream
case outputMode of
Write -> do
case input of
InputFile file ->
if originalText == formattedText
then return ()
else AtomicWrite.LazyText.atomicWriteFile
file
(Pretty.Text.renderLazy docStream)
StandardInput -> do
supportsANSI <- System.Console.ANSI.hSupportsANSI System.IO.stdout
Pretty.Terminal.renderIO
System.IO.stdout
(if supportsANSI
then (fmap annToAnsiStyle docStream)
else (Pretty.unAnnotateS docStream))
return (Right ())
Check ->
return $
if originalText == formattedText
then Right ()
else Left CheckFailed{..}