dhall-1.40.2: src/Dhall/Src.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}
-- | This module provides the `Src` type used for source spans in error messages
module Dhall.Src
( -- * Type
Src(..)
) where
import Control.DeepSeq (NFData)
import Data.Data (Data)
import Data.Text (Text)
import GHC.Generics (Generic)
import Instances.TH.Lift ()
import Language.Haskell.TH.Syntax (Lift (..))
import Prettyprinter (Pretty (..))
import Text.Megaparsec (SourcePos (SourcePos), mkPos, unPos)
import {-# SOURCE #-} qualified Dhall.Util
import qualified Data.Text as Text
import qualified Text.Megaparsec as Megaparsec
import qualified Text.Printf as Printf
-- | Source code extract
data Src = Src
{ srcStart :: !SourcePos
, srcEnd :: !SourcePos
, srcText :: Text -- Text field is intentionally lazy
} deriving (Data, Eq, Generic, Ord, Show, NFData)
instance Lift Src where
#if MIN_VERSION_template_haskell(2,16,0)
liftTyped (Src (SourcePos a b c) (SourcePos d e f) g) =
[|| Src (SourcePos a (mkPos b') (mkPos c')) (SourcePos d (mkPos e') (mkPos f')) g ||]
#else
lift (Src (SourcePos a b c) (SourcePos d e f) g) =
[| Src (SourcePos a (mkPos b') (mkPos c')) (SourcePos d (mkPos e') (mkPos f')) g |]
#endif
where
b' = unPos b
c' = unPos c
e' = unPos e
f' = unPos f
instance Pretty Src where
pretty (Src begin _ text) =
pretty (Dhall.Util.snip numberedLines)
<> "\n"
<> pretty (Megaparsec.sourcePosPretty begin)
where
prefix = Text.replicate (n - 1) " "
where
n = Megaparsec.unPos (Megaparsec.sourceColumn begin)
ls = Text.lines (prefix <> text)
numberOfLines = length ls
minimumNumber =
Megaparsec.unPos (Megaparsec.sourceLine begin)
maximumNumber = minimumNumber + numberOfLines - 1
numberWidth :: Int
numberWidth =
truncate (logBase (10 :: Double) (fromIntegral maximumNumber)) + 1
adapt n line = Text.pack outputString
where
inputString = Text.unpack line
outputString =
Printf.printf ("%" <> show numberWidth <> "d│ %s") n inputString
numberedLines = Text.unlines (zipWith adapt [minimumNumber..] ls)