hnix/src/Nix/Render.hs

112 lines
4.5 KiB
Haskell
Raw Normal View History

2018-04-07 21:02:50 +02:00
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DefaultSignatures #-}
2018-04-07 21:02:50 +02:00
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
2018-04-07 21:02:50 +02:00
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE ViewPatterns #-}
2018-04-07 21:02:50 +02:00
module Nix.Render where
2018-04-07 21:02:50 +02:00
import Prelude hiding (readFile)
import Control.Monad.Trans
2018-04-10 18:03:24 +02:00
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
2018-04-10 18:03:24 +02:00
import qualified Data.Set as Set
import qualified Data.Text as T
import qualified Data.Text.Encoding as T
2018-11-17 05:51:18 +01:00
import Data.Text.Prettyprint.Doc
2018-04-10 18:03:24 +02:00
import Data.Void
import Debug.Trace
2018-04-10 18:03:24 +02:00
import Nix.Expr.Types.Annotated
import qualified System.Directory as S
import qualified System.Posix.Files as S
import Text.Megaparsec.Error
import Text.Megaparsec.Pos
2018-04-07 21:02:50 +02:00
class Monad m => MonadFile m where
readFile :: FilePath -> m ByteString
default readFile :: (MonadTrans t, MonadFile m', m ~ t m') => FilePath -> m ByteString
readFile = lift . readFile
listDirectory :: FilePath -> m [FilePath]
default listDirectory :: (MonadTrans t, MonadFile m', m ~ t m') => FilePath -> m [FilePath]
listDirectory = lift . listDirectory
getCurrentDirectory :: m FilePath
default getCurrentDirectory :: (MonadTrans t, MonadFile m', m ~ t m') => m FilePath
getCurrentDirectory = lift getCurrentDirectory
canonicalizePath :: FilePath -> m FilePath
default canonicalizePath :: (MonadTrans t, MonadFile m', m ~ t m') => FilePath -> m FilePath
canonicalizePath = lift . canonicalizePath
getHomeDirectory :: m FilePath
default getHomeDirectory :: (MonadTrans t, MonadFile m', m ~ t m') => m FilePath
getHomeDirectory = lift getHomeDirectory
doesPathExist :: FilePath -> m Bool
default doesPathExist :: (MonadTrans t, MonadFile m', m ~ t m') => FilePath -> m Bool
doesPathExist = lift . doesPathExist
doesFileExist :: FilePath -> m Bool
default doesFileExist :: (MonadTrans t, MonadFile m', m ~ t m') => FilePath -> m Bool
doesFileExist = lift . doesFileExist
doesDirectoryExist :: FilePath -> m Bool
default doesDirectoryExist :: (MonadTrans t, MonadFile m', m ~ t m') => FilePath -> m Bool
doesDirectoryExist = lift . doesDirectoryExist
getSymbolicLinkStatus :: FilePath -> m S.FileStatus
default getSymbolicLinkStatus :: (MonadTrans t, MonadFile m', m ~ t m') => FilePath -> m S.FileStatus
getSymbolicLinkStatus = lift . getSymbolicLinkStatus
instance MonadFile IO where
readFile = BS.readFile
listDirectory = S.listDirectory
getCurrentDirectory = S.getCurrentDirectory
canonicalizePath = S.canonicalizePath
getHomeDirectory = S.getHomeDirectory
doesPathExist = S.doesPathExist
doesFileExist = S.doesFileExist
doesDirectoryExist = S.doesDirectoryExist
getSymbolicLinkStatus = S.getSymbolicLinkStatus
2018-04-07 21:02:50 +02:00
2018-11-17 05:14:23 +01:00
posAndMsg :: SourcePos -> Doc a -> ParseError s Void
posAndMsg (SourcePos _ lineNo _) msg =
FancyError (unPos lineNo)
(Set.fromList [ErrorFail (show msg) :: ErrorFancy Void])
renderLocation :: MonadFile m => SrcSpan -> Doc a -> m (Doc a)
renderLocation (SrcSpan (SourcePos file begLine begCol)
(SourcePos file' endLine endCol)) msg
| file /= "<string>" && file == file' = do
exist <- doesFileExist file
if exist
then do
txt <- sourceContext file begLine begCol endLine endCol msg
return $ vsep
[ "In file " <> errorContext file begLine begCol endLine endCol <> ":"
, txt
]
else return msg
renderLocation (SrcSpan beg end) msg =
fail $ "Don't know how to render range from " ++ show beg ++ " to " ++ show end
++ " for error: " ++ show msg
errorContext :: FilePath -> Pos -> Pos -> Pos -> Pos -> Doc a
errorContext path bl bc _el _ec =
pretty path <> ":" <> pretty (unPos bl) <> ":" <> pretty (unPos bc)
sourceContext :: MonadFile m => FilePath -> Pos -> Pos -> Pos -> Pos -> Doc a -> m (Doc a)
sourceContext path (unPos -> begLine) (unPos -> begCol)
(unPos -> endLine) (unPos -> endCol) msg = do
traceM $ "Taking lines from " ++ path
traceM $ "begLine = " ++ show begLine
traceM $ "begCol = " ++ show begCol
traceM $ "endLine = " ++ show endLine
traceM $ "endCol = " ++ show endCol
traceM $ "msg = " ++ show msg
ls <- take (endLine - begLine)
. drop (pred begLine)
. T.lines
. T.decodeUtf8
<$> readFile path
pure $ vsep $ map pretty ls