diff --git a/System/Console/Haskeline/History.hs b/System/Console/Haskeline/History.hs index 9fe2d126a14874e834a3b9549f161038d7ac7bda..f09e702fb0e09dbf09c3124189a5a45fd98eca0c 100644 --- a/System/Console/Haskeline/History.hs +++ b/System/Console/Haskeline/History.hs @@ -28,12 +28,17 @@ import qualified Data.Sequence as Seq import Data.Sequence ( Seq, (<|), ViewL(..), ViewR(..), viewl, viewr ) import Data.Foldable (toList) -import qualified Data.ByteString as B -import qualified Data.ByteString.UTF8 as UTF8 import Control.Exception import System.Directory(doesFileExist) +#ifdef USE_GHC_ENCODINGS +import qualified System.IO as IO +#else +import qualified Data.ByteString as B +import qualified Data.ByteString.UTF8 as UTF8 +#endif + data History = History {histLines :: Seq String, stifleAmt :: Maybe Int} -- stored in reverse @@ -58,9 +63,7 @@ readHistory :: FilePath -> IO History readHistory file = handle (\(_::IOException) -> return emptyHistory) $ do exists <- doesFileExist file contents <- if exists - -- use binary file I/O to avoid Windows CRLF line endings - -- which cause confusion when switching between systems. - then fmap UTF8.toString (B.readFile file) + then readUTF8File file else return "" _ <- evaluate (length contents) -- force file closed return History {histLines = Seq.fromList $ lines contents, @@ -70,7 +73,7 @@ readHistory file = handle (\(_::IOException) -> return emptyHistory) $ do -- error when writing the file, it will be ignored. writeHistory :: FilePath -> History -> IO () writeHistory file = handle (\(_::IOException) -> return ()) - . B.writeFile file . UTF8.fromString + . writeUTF8File file . unlines . historyLines -- | Limit the number of lines stored in the history. @@ -108,3 +111,38 @@ addHistoryRemovingAllDupes :: String -> History -> History addHistoryRemovingAllDupes h hs = addHistory h hs {histLines = filteredHS} where filteredHS = Seq.fromList $ filter (/= h) $ toList $ histLines hs + +--------- +-- UTF-8 file I/O, for old versions of GHC + +readUTF8File :: FilePath -> IO String +#ifdef USE_GHC_ENCODINGS +readUTF8File file = do + h <- IO.openFile file IO.ReadMode + IO.hSetEncoding h IO.utf8 + IO.hSetNewlineMode h IO.noNewlineTranslation + contents <- IO.hGetContents h + _ <- evaluate (length contents) + IO.hClose h + return contents +#else +readUTF8File file = do + contents <- fmap UTF8.toString $ B.readFile file + _ <- evaluate (length contents) + return contents +#endif + +writeUTF8File :: FilePath -> String -> IO () +#ifdef USE_GHC_ENCODINGS +writeUTF8File file contents = do + h <- IO.openFile file IO.WriteMode + IO.hSetEncoding h IO.utf8 + -- Write a file which is portable between systems. + IO.hSetNewlineMode h IO.noNewlineTranslation + IO.hPutStr h contents + IO.hClose h +#else +-- use binary file I/O to avoid Windows CRLF line endings +-- which cause confusion when switching between systems. +writeUTF8File file = B.writeFile file . UTF8.fromString +#endif diff --git a/haskeline.cabal b/haskeline.cabal index 54a05e5eceea09bfcfc5d4e7e97f1c94bb563920..dd10632ed54c82786e4f5d02b1f9b0e66b803885 100644 --- a/haskeline.cabal +++ b/haskeline.cabal @@ -53,8 +53,7 @@ Library Build-depends: base>=3 && <4.1 , containers>=0.1 && < 0.3, directory==1.0.*, bytestring==0.9.* } - Build-depends: filepath >= 1.1 && < 1.4, mtl >= 1.1 && < 2.1, - utf8-string==0.3.* && >=0.3.6 + Build-depends: filepath >= 1.1 && < 1.4, mtl >= 1.1 && < 2.1 Extensions: ForeignFunctionInterface, Rank2Types, FlexibleInstances, TypeSynonymInstances FlexibleContexts, ExistentialQuantification @@ -90,6 +89,10 @@ Library System.Console.Haskeline.Vi include-dirs: includes c-sources: cbits/h_wcwidth.c + + if impl(ghc>=7.4) { + cpp-options: -DUSE_GHC_ENCODINGS + } if os(windows) { Build-depends: Win32>=2.0 Other-modules: System.Console.Haskeline.Backend.Win32 @@ -98,8 +101,9 @@ Library install-includes: win_console.h cpp-options: -DMINGW } else { - Build-depends: unix>=2.0 && < 2.6 + Build-depends: unix>=2.0 && < 2.6, -- unix-2.3 doesn't build on ghc-6.8.1 or earlier + utf8-string==0.3.* && >=0.3.6 c-sources: cbits/h_iconv.c includes: h_iconv.h install-includes: h_iconv.h