1
1
mirror of https://github.com/github/semantic.git synced 2024-11-28 01:47:01 +03:00
semantic/app/Main.hs

83 lines
3.1 KiB
Haskell
Raw Normal View History

2015-11-18 01:44:16 +03:00
module Main where
2015-11-27 20:22:05 +03:00
import Categorizable
import Diff
2015-11-27 20:22:05 +03:00
import Interpreter
2015-12-09 17:50:55 +03:00
import qualified Parser as P
import Syntax
2015-12-03 05:40:34 +03:00
import Range
2015-12-01 19:33:16 +03:00
import Split
2015-11-27 20:41:38 +03:00
import Term
import TreeSitter
2015-11-27 20:42:00 +03:00
import Unified
import Control.Comonad.Cofree
import qualified Data.Char as Char
2015-11-27 17:19:09 +03:00
import qualified Data.Map as Map
2015-12-07 22:34:58 +03:00
import qualified Data.ByteString.Char8 as B1
import qualified Data.ByteString.Lazy as B2
2015-12-01 19:33:10 +03:00
import Data.Set hiding (split)
2015-12-01 19:15:13 +03:00
import Options.Applicative
2015-12-03 23:10:49 +03:00
import System.FilePath
import Foreign.Ptr
2015-12-01 19:08:04 +03:00
data Output = Unified | Split
2015-12-01 19:15:05 +03:00
data Argument = Argument { output :: Output, sourceA :: FilePath, sourceB :: FilePath }
2015-12-01 19:08:04 +03:00
2015-12-01 19:15:13 +03:00
arguments :: Parser Argument
arguments = Argument
2015-12-01 19:32:52 +03:00
<$> (flag Split Unified (long "unified" <> help "output a unified diff")
<|> flag' Split (long "split" <> help "output a split diff"))
2015-12-01 19:15:13 +03:00
<*> argument str (metavar "FILE a")
<*> argument str (metavar "FILE b")
2015-11-18 01:44:16 +03:00
main :: IO ()
2015-11-20 19:36:54 +03:00
main = do
2015-12-01 19:19:40 +03:00
arguments <- execParser opts
2015-12-07 22:23:32 +03:00
let (sourceAPath, sourceBPath) = (sourceA arguments, sourceB arguments)
aContents <- readFile sourceAPath
bContents <- readFile sourceBPath
2015-12-09 18:36:37 +03:00
(aTerm, bTerm) <- let parse = (parserForType . takeExtension) sourceAPath in do
aTerm <- parse aContents
bTerm <- parse bContents
2015-12-14 20:13:18 +03:00
return (replaceLeavesWithWordBranches aTerm aContents, replaceLeavesWithWordBranches bTerm bContents)
2015-12-07 22:34:58 +03:00
let diff = interpret comparable aTerm bTerm in
case output arguments of
Unified -> do
output <- unified diff aContents bContents
B1.putStr output
Split -> do
output <- split diff aContents bContents
B2.putStr output
where
2015-12-01 19:19:40 +03:00
opts = info (helper <*> arguments)
(fullDesc <> progDesc "Diff some things" <> header "semantic-diff - diff semantically")
2015-11-25 00:51:53 +03:00
2015-12-09 18:36:37 +03:00
parserForType :: String -> P.Parser
parserForType mediaType = maybe P.lineByLineParser parseTreeSitterFile $ case mediaType of
".h" -> Just ts_language_c
".c" -> Just ts_language_c
".js" -> Just ts_language_javascript
2015-12-03 23:10:49 +03:00
_ -> Nothing
replaceLeavesWithWordBranches :: Term String Info -> String -> Term String Info
replaceLeavesWithWordBranches term source = replaceIn term
where
replaceIn (info@(Info range lineRange categories) :< syntax) = info :< case syntax of
Leaf _ | ranges <- rangesOfWordsFrom (start range) (substring range source), length (ranges) > 1 -> Indexed $ makeLeaf lineRange categories <$> ranges
Indexed i -> Indexed $ replaceIn <$> i
Fixed f -> Fixed $ replaceIn <$> f
Keyed k -> Keyed $ replaceIn <$> k
_ -> syntax
makeLeaf lineRange categories range = Info range lineRange categories :< Leaf (substring range source)
rangesOfWordsFrom :: Int -> String -> [Range]
rangesOfWordsFrom startIndex string = case break Char.isSpace string of
([], []) -> []
([], rest) -> rangesOfWordsAfterWhitespace startIndex rest
(word, []) -> [ Range startIndex $ length word ]
(word, rest) -> (Range startIndex $ length word) : rangesOfWordsAfterWhitespace (startIndex + length word) rest
where
rangesOfWordsAfterWhitespace startIndex string | (whitespace, rest) <- break (not . Char.isSpace) string = rangesOfWordsFrom (startIndex + length whitespace) rest