From fff9b6d3ef0b5a9124267d94a29798fe4fb0029e Mon Sep 17 00:00:00 2001 From: Timothy Clem Date: Tue, 28 Feb 2017 15:45:38 -0800 Subject: [PATCH] Refactor IO back out into Source and SemanticDiff --- semantic-diff.cabal | 1 - src/DiffCommand.hs | 1 - src/ParseCommand.hs | 1 - src/SemanticDiff.hs | 19 +++++++++++++- src/SemanticDiff/IO.hs | 56 ----------------------------------------- src/Source.hs | 32 ++++++++++++++++++++++- test/IntegrationSpec.hs | 1 - test/TOCSpec.hs | 1 - 8 files changed, 49 insertions(+), 63 deletions(-) delete mode 100644 src/SemanticDiff/IO.hs diff --git a/semantic-diff.cabal b/semantic-diff.cabal index 1a51f1f51..65e73d565 100644 --- a/semantic-diff.cabal +++ b/semantic-diff.cabal @@ -49,7 +49,6 @@ library , Renderer.SExpression , Renderer.TOC , SemanticDiff - , SemanticDiff.IO , SES , Source , SourceSpan diff --git a/src/DiffCommand.hs b/src/DiffCommand.hs index e489b40f2..5f583d892 100644 --- a/src/DiffCommand.hs +++ b/src/DiffCommand.hs @@ -32,7 +32,6 @@ import Renderer.SExpression import Renderer.Split import Renderer.Summary import Renderer.TOC -import SemanticDiff.IO import Source import Syntax import Term diff --git a/src/ParseCommand.hs b/src/ParseCommand.hs index 4c6a730e7..b09a4a862 100644 --- a/src/ParseCommand.hs +++ b/src/ParseCommand.hs @@ -24,7 +24,6 @@ import Text.Parser.TreeSitter.C import Text.Parser.TreeSitter.Go import Text.Parser.TreeSitter.JavaScript import Text.Parser.TreeSitter.Ruby -import SemanticDiff.IO data ParseJSON = ParseJSON { category :: Text diff --git a/src/SemanticDiff.hs b/src/SemanticDiff.hs index d300cf340..daaeae812 100644 --- a/src/SemanticDiff.hs +++ b/src/SemanticDiff.hs @@ -13,7 +13,9 @@ import qualified Renderer as R import Development.GitRev import DiffCommand import ParseCommand -import SemanticDiff.IO +import qualified Data.Text.IO as TextIO +import System.IO +import System.Environment (lookupEnv) main :: IO () main = do @@ -56,3 +58,18 @@ versionString = "semantic-diff version " <> showVersion Library.version <> " (" version :: Parser (a -> a) version = infoOption versionString (long "version" <> short 'V' <> help "output the version of the program") + +writeToOutput :: Maybe FilePath -> Text -> IO () +writeToOutput output text = case output of + Nothing -> do + setEncoding + TextIO.hPutStrLn stdout text + Just path -> withFile path WriteMode (`TextIO.hPutStr` text) + where + setEncoding = do + lang <- lookupEnv "LANG" + case lang of + -- If LANG is set and isn't the empty string, leave the encoding. + Just x | x /= "" -> pure () + -- Otherwise default to utf8. + _ -> hSetEncoding stdout utf8 diff --git a/src/SemanticDiff/IO.hs b/src/SemanticDiff/IO.hs deleted file mode 100644 index 7a882e59f..000000000 --- a/src/SemanticDiff/IO.hs +++ /dev/null @@ -1,56 +0,0 @@ -module SemanticDiff.IO where - -import Prelude -import Data.Text -import qualified Data.Text.IO as TextIO -import System.IO -import System.Environment (lookupEnv) - -import Control.Exception (catch, IOException) -import qualified Data.ByteString as B1 -import qualified Data.Text.ICU.Convert as Convert -import qualified Data.Text.ICU.Detect as Detect - -import Source - -writeToOutput :: Maybe FilePath -> Text -> IO () -writeToOutput output text = case output of - Nothing -> do - setEncoding - TextIO.hPutStrLn stdout text - Just path -> withFile path WriteMode (`TextIO.hPutStr` text) - - where - setEncoding = do - lang <- lookupEnv "LANG" - case lang of - -- If LANG is set and isn't the empty string, leave the encoding. - Just x | x /= "" -> pure () - -- Otherwise default to utf8. - _ -> hSetEncoding stdout utf8 - --- | Read the file and convert it to Unicode. -readAndTranscodeFile :: FilePath -> IO Source -readAndTranscodeFile path = do - size <- fileSize path - text <- case size of - 0 -> pure B1.empty - _ -> B1.readFile path - transcode text - --- From https://github.com/haskell/bytestring/pull/79/files -fileSize :: FilePath -> IO Integer -fileSize f = withBinaryFile f ReadMode $ \h -> do - -- hFileSize fails if file is not regular file (like /dev/null). Catch - -- exception and try reading anyway. - filesz <- catch (hFileSize h) useZeroIfNotRegularFile - pure $ fromIntegral filesz `max` 0 - where useZeroIfNotRegularFile :: IOException -> IO Integer - useZeroIfNotRegularFile _ = pure 0 - --- | Transcode a file to a unicode source. -transcode :: B1.ByteString -> IO Source -transcode text = fromText <$> do - match <- Detect.detectCharset text - converter <- Convert.open match Nothing - pure $ Convert.toUnicode converter text diff --git a/src/Source.hs b/src/Source.hs index 4e72f3442..0ae597806 100644 --- a/src/Source.hs +++ b/src/Source.hs @@ -2,6 +2,7 @@ {-# OPTIONS_GHC -funbox-strict-fields #-} module Source where +import Prelude (FilePath, fromIntegral) import Prologue import qualified Data.ByteString as B import qualified Data.Text as T @@ -9,6 +10,10 @@ import Numeric import Range import SourceSpan import Test.LeanCheck +import System.IO +import Control.Exception (catch, IOException) +import qualified Data.Text.ICU.Convert as Convert +import qualified Data.Text.ICU.Detect as Detect -- | The source, oid, path, and Maybe SourceKind of a blob in a Git repo. data SourceBlob = SourceBlob { source :: Source, oid :: T.Text, path :: FilePath, blobKind :: Maybe SourceKind } @@ -22,12 +27,37 @@ newtype Source = Source { sourceText :: B.ByteString } data SourceKind = PlainBlob Word32 | ExecutableBlob Word32 | SymlinkBlob Word32 deriving (Show, Eq) +-- | Read the file and convert it to Unicode. +readAndTranscodeFile :: FilePath -> IO Source +readAndTranscodeFile path = do + size <- fileSize path + text <- case size of + 0 -> pure B.empty + _ -> B.readFile path + transcode text + +-- From https://github.com/haskell/bytestring/pull/79/files +fileSize :: FilePath -> IO Integer +fileSize f = withBinaryFile f ReadMode $ \h -> do + -- hFileSize fails if file is not regular file (like /dev/null). Catch + -- exception and try reading anyway. + filesz <- catch (hFileSize h) useZeroIfNotRegularFile + pure $ fromIntegral filesz `max` 0 + where useZeroIfNotRegularFile :: IOException -> IO Integer + useZeroIfNotRegularFile _ = pure 0 + +-- | Transcode a file to a unicode source. +transcode :: B.ByteString -> IO Source +transcode text = fromText <$> do + match <- Detect.detectCharset text + converter <- Convert.open match Nothing + pure $ Convert.toUnicode converter text + modeToDigits :: SourceKind -> Text modeToDigits (PlainBlob mode) = toS $ showOct mode "" modeToDigits (ExecutableBlob mode) = toS $ showOct mode "" modeToDigits (SymlinkBlob mode) = toS $ showOct mode "" - -- | The default plain blob mode defaultPlainBlob :: SourceKind defaultPlainBlob = PlainBlob 0o100644 diff --git a/test/IntegrationSpec.hs b/test/IntegrationSpec.hs index 63e94c030..c9fb427aa 100644 --- a/test/IntegrationSpec.hs +++ b/test/IntegrationSpec.hs @@ -14,7 +14,6 @@ import Renderer import Renderer.SExpression as Renderer import Source import DiffCommand -import SemanticDiff.IO (readAndTranscodeFile) import System.FilePath import System.FilePath.Glob import Test.Hspec (Spec, describe, it, SpecWith, runIO, parallel) diff --git a/test/TOCSpec.hs b/test/TOCSpec.hs index 6c294017a..5db9365de 100644 --- a/test/TOCSpec.hs +++ b/test/TOCSpec.hs @@ -10,7 +10,6 @@ import Data.Record import Data.String import Diff import DiffCommand -import SemanticDiff.IO (readAndTranscodeFile) import Info import Interpreter import ParseCommand