2 ( writeBinary, readBinary
18import Control.Exception (catch)
19import qualified Data.Binary as Binary
20import qualified Data.ByteString as BS
21import qualified Data.ByteString.Internal as BS
22import qualified Data.ByteString.Builder as B
23import qualified Data.ByteString.Builder.Extra as B (defaultChunkSize)
24import qualified Foreign.ForeignPtr as FPtr
25import GHC.IO.Exception (IOException, IOErrorType(InvalidArgument))
26import qualified System.Directory as Dir
27import System.FilePath ((</>))
28import qualified System.FilePath as FP
29import qualified System.IO as IO
30import System.IO.Error (ioeGetErrorType, annotateIOError, modifyIOError)
37writeBinary :: (Binary.Binary a) => FilePath -> a -> IO ()
38writeBinary path value =
39 do let dir = FP.dropFileName path
40 Dir.createDirectoryIfMissing True dir
41 Binary.encodeFile path value
44readBinary :: (Binary.Binary a) => FilePath -> IO (Maybe a)
46 do exists_ <- Dir.doesFileExist path
50 do result <- Binary.decodeFileOrFail path
63writeUtf8 :: FilePath -> BS.ByteString -> IO ()
64writeUtf8 filePath content =
65 withUtf8 filePath IO.WriteMode $ \handle ->
66 BS.hPut handle content
69withUtf8 :: FilePath -> IO.IOMode -> (IO.Handle -> IO a) -> IO a
70withUtf8 filePath mode callback =
71 IO.withFile filePath mode $ \handle ->
72 do IO.hSetEncoding handle IO.utf8
80readUtf8 :: FilePath -> IO BS.ByteString
82 withUtf8 filePath IO.ReadMode $ \handle ->
83 modifyIOError (encodingError filePath) $
84 do fileSize <- catch (IO.hFileSize handle) useZeroIfNotRegularFile
85 let readSize = max 0 (fromIntegral fileSize) + 1
86 hGetContentsSizeHint handle readSize (max 255 readSize)
89useZeroIfNotRegularFile :: IOException -> IO Integer
90useZeroIfNotRegularFile _ =
94hGetContentsSizeHint :: IO.Handle -> Int -> Int -> IO BS.ByteString
95hGetContentsSizeHint handle =
98 readChunks chunks readSize incrementSize =
99 do fp <- BS.mallocByteString readSize
100 readCount <- FPtr.withForeignPtr fp $ \buf -> IO.hGetBuf handle buf readSize
101 let chunk = BS.PS fp 0 readCount
102 if readCount < readSize && readSize > 0
103 then return $! BS.concat (reverse (chunk:chunks))
104 else readChunks (chunk:chunks) incrementSize (min 32752 (readSize + incrementSize))
107encodingError :: FilePath -> IOError -> IOError
108encodingError filePath ioErr =
109 case ioeGetErrorType ioErr of
112 (userError "Bad encoding; the file must be valid UTF-8")
125writeBuilder :: FilePath -> B.Builder -> IO ()
126writeBuilder path builder =
127 IO.withBinaryFile path IO.WriteMode $ \handle ->
128 do IO.hSetBuffering handle (IO.BlockBuffering Nothing)
129 B.hPutBuilder handle builder
137 Writer (IO.Handle -> IO ())
140put :: FilePath -> Writer -> IO ()
141put path (Writer callback) =
142 IO.withBinaryFile path IO.WriteMode callback
145putByteString :: BS.ByteString -> Writer
151putBuilder :: B.Builder -> Writer
154 B.hPutBuilder handle builder
157putFile :: FilePath -> Writer
160 IO.withBinaryFile path IO.ReadMode $ \source ->
164putHelp :: IO.Handle -> IO.Handle -> IO ()
166 do chunk <- BS.hGet source B.defaultChunkSize
170 do BS.hPut sink chunk
178exists :: FilePath -> IO Bool
187remove :: FilePath -> IO ()
189 do exists_ <- Dir.doesFileExist filePath
191 then Dir.removeFile filePath
195removeDir :: FilePath -> IO ()
197 do exists_ <- Dir.doesDirectoryExist path
199 then Dir.removeDirectoryRecursive path
207find :: FilePath -> IO (Maybe FilePath)
209 do subDir <- Dir.getCurrentDirectory
210 findHelp name (FP.splitDirectories subDir)
213findHelp :: FilePath -> [String] -> IO (Maybe FilePath)
219 do exists_ <- Dir.doesFileExist (FP.joinPath dirs </> name)
221 then return (Just (FP.joinPath dirs))
222 else findHelp name (init dirs)
229andM :: (Monad m) => [m Bool] -> m Bool
235 check : otherChecks ->
237 if bool then andM otherChecks else return False
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list