module Darcs.Patch.Object where

import Darcs.Prelude

import qualified Data.ByteString.Char8 as BC ( unpack )

import Darcs.Patch.Format ( FileNameFormat(..) )
import Darcs.Util.ByteString ( packStringToUTF8, encodeLocale )
import Darcs.Util.Path ( AnchoredPath, encodeWhite, anchorPath )
import Darcs.Util.Printer ( Doc, text, packedString )
import Darcs.Util.Tree ( Tree )

-- | Given a state type (parameterized over a monad m :: * -> *), this gives us
-- the type of the key with which we can lookup an item (or object) in the
-- state.
type family ObjectIdOf (state :: (* -> *) -> *)

-- | We require from such a key (an 'ObjectId') that it has a canonical way
-- to format itself to a 'Doc'. For historical reasons, this takes a parameter
-- of type 'FileNameFormat'.
class Eq oid => ObjectId oid where
  formatObjectId :: FileNameFormat -> oid -> Doc

type instance ObjectIdOf Tree = AnchoredPath

-- formatFileName is defined here only to avoid an import cycle

-- | Format a 'AnchoredPath' to a 'Doc' according to the given 'FileNameFormat'.
--
-- NOTE: This is not only used for display but also to format patch files. This is
--       why we have to do the white space encoding here.
--       See 'Darcs.Repository.Hashed.writePatchIfNecessary'.
--
-- Besides white space encoding, for 'FileNameFormatV2' we just pack it into a 'Doc'. For
-- 'FileNameFormatV1' we must emulate the non-standard darcs-1 encoding of file paths: it
-- is an UTF8 encoding of the raw byte stream, interpreted as code points.
--
-- See also 'Darcs.Patch.Show.readFileName'.
formatFileName :: FileNameFormat -> AnchoredPath -> Doc
formatFileName :: FileNameFormat -> AnchoredPath -> Doc
formatFileName FileNameFormat
FileNameFormatV1 =
  ByteString -> Doc
packedString (ByteString -> Doc)
-> (AnchoredPath -> ByteString) -> AnchoredPath -> Doc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ByteString
packStringToUTF8 (String -> ByteString)
-> (AnchoredPath -> String) -> AnchoredPath -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> String
BC.unpack (ByteString -> String)
-> (AnchoredPath -> ByteString) -> AnchoredPath -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ByteString
encodeLocale (String -> ByteString)
-> (AnchoredPath -> String) -> AnchoredPath -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
encodeWhite (String -> String)
-> (AnchoredPath -> String) -> AnchoredPath -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AnchoredPath -> String
ap2fp
formatFileName FileNameFormat
FileNameFormatV2 = String -> Doc
text (String -> Doc) -> (AnchoredPath -> String) -> AnchoredPath -> Doc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
encodeWhite (String -> String)
-> (AnchoredPath -> String) -> AnchoredPath -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AnchoredPath -> String
ap2fp
formatFileName FileNameFormat
FileNameFormatDisplay = String -> Doc
text (String -> Doc) -> (AnchoredPath -> String) -> AnchoredPath -> Doc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AnchoredPath -> String
ap2fp

instance ObjectId AnchoredPath where
  formatObjectId :: FileNameFormat -> AnchoredPath -> Doc
formatObjectId = FileNameFormat -> AnchoredPath -> Doc
formatFileName

ap2fp :: AnchoredPath -> FilePath
ap2fp :: AnchoredPath -> String
ap2fp AnchoredPath
ap = String
"./" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> AnchoredPath -> String
anchorPath String
"" AnchoredPath
ap